File Index
Files and directories
Sign in
FILE

meson-canvas.c

File preview with syntax highlighting.

linux-6.19.14/drivers/soc/amlogic/meson-canvas.c C
  1// SPDX-License-Identifier: GPL-2.0+
  2/*
  3 * Copyright (C) 2018 BayLibre, SAS
  4 * Copyright (C) 2015 Amlogic, Inc. All rights reserved.
  5 * Copyright (C) 2014 Endless Mobile
  6 */
  7
  8#include <linux/kernel.h>
  9#include <linux/mfd/syscon.h>
 10#include <linux/module.h>
 11#include <linux/platform_device.h>
 12#include <linux/regmap.h>
 13#include <linux/soc/amlogic/meson-canvas.h>
 14#include <linux/of_address.h>
 15#include <linux/of_platform.h>
 16#include <linux/io.h>
 17
 18#define NUM_CANVAS 256
 19
 20/* DMC Registers */
 21#define DMC_CAV_LUT_DATAL	0x00
 22	#define CANVAS_WIDTH_LBIT	29
 23	#define CANVAS_WIDTH_LWID	3
 24#define DMC_CAV_LUT_DATAH	0x04
 25	#define CANVAS_WIDTH_HBIT	0
 26	#define CANVAS_HEIGHT_BIT	9
 27	#define CANVAS_WRAP_BIT		22
 28	#define CANVAS_BLKMODE_BIT	24
 29	#define CANVAS_ENDIAN_BIT	26
 30#define DMC_CAV_LUT_ADDR	0x08
 31	#define CANVAS_LUT_WR_EN	BIT(9)
 32	#define CANVAS_LUT_RD_EN	BIT(8)
 33
 34struct meson_canvas {
 35	struct device *dev;
 36	void __iomem *reg_base;
 37	spinlock_t lock; /* canvas device lock */
 38	u8 used[NUM_CANVAS];
 39	bool supports_endianness;
 40};
 41
 42static void canvas_write(struct meson_canvas *canvas, u32 reg, u32 val)
 43{
 44	writel_relaxed(val, canvas->reg_base + reg);
 45}
 46
 47static u32 canvas_read(struct meson_canvas *canvas, u32 reg)
 48{
 49	return readl_relaxed(canvas->reg_base + reg);
 50}
 51
 52struct meson_canvas *meson_canvas_get(struct device *dev)
 53{
 54	struct device_node *canvas_node;
 55	struct platform_device *canvas_pdev;
 56	struct meson_canvas *canvas;
 57
 58	canvas_node = of_parse_phandle(dev->of_node, "amlogic,canvas", 0);
 59	if (!canvas_node)
 60		return ERR_PTR(-ENODEV);
 61
 62	canvas_pdev = of_find_device_by_node(canvas_node);
 63	of_node_put(canvas_node);
 64	if (!canvas_pdev)
 65		return ERR_PTR(-EPROBE_DEFER);
 66
 67	/*
 68	 * If priv is NULL, it's probably because the canvas hasn't
 69	 * properly initialized. Bail out with -EINVAL because, in the
 70	 * current state, this driver probe cannot return -EPROBE_DEFER
 71	 */
 72	canvas = dev_get_drvdata(&canvas_pdev->dev);
 73	put_device(&canvas_pdev->dev);
 74	if (!canvas)
 75		return ERR_PTR(-EINVAL);
 76
 77	return canvas;
 78}
 79EXPORT_SYMBOL_GPL(meson_canvas_get);
 80
 81int meson_canvas_config(struct meson_canvas *canvas, u8 canvas_index,
 82			u32 addr, u32 stride, u32 height,
 83			unsigned int wrap,
 84			unsigned int blkmode,
 85			unsigned int endian)
 86{
 87	unsigned long flags;
 88
 89	if (endian && !canvas->supports_endianness) {
 90		dev_err(canvas->dev,
 91			"Endianness is not supported on this SoC\n");
 92		return -EINVAL;
 93	}
 94
 95	spin_lock_irqsave(&canvas->lock, flags);
 96	if (!canvas->used[canvas_index]) {
 97		dev_err(canvas->dev,
 98			"Trying to setup non allocated canvas %u\n",
 99			canvas_index);
100		spin_unlock_irqrestore(&canvas->lock, flags);
101		return -EINVAL;
102	}
103
104	canvas_write(canvas, DMC_CAV_LUT_DATAL,
105		     ((addr + 7) >> 3) |
106		     (((stride + 7) >> 3) << CANVAS_WIDTH_LBIT));
107
108	canvas_write(canvas, DMC_CAV_LUT_DATAH,
109		     ((((stride + 7) >> 3) >> CANVAS_WIDTH_LWID) <<
110						CANVAS_WIDTH_HBIT) |
111		     (height << CANVAS_HEIGHT_BIT) |
112		     (wrap << CANVAS_WRAP_BIT) |
113		     (blkmode << CANVAS_BLKMODE_BIT) |
114		     (endian << CANVAS_ENDIAN_BIT));
115
116	canvas_write(canvas, DMC_CAV_LUT_ADDR,
117		     CANVAS_LUT_WR_EN | canvas_index);
118
119	/* Force a read-back to make sure everything is flushed. */
120	canvas_read(canvas, DMC_CAV_LUT_DATAH);
121	spin_unlock_irqrestore(&canvas->lock, flags);
122
123	return 0;
124}
125EXPORT_SYMBOL_GPL(meson_canvas_config);
126
127int meson_canvas_alloc(struct meson_canvas *canvas, u8 *canvas_index)
128{
129	int i;
130	unsigned long flags;
131
132	spin_lock_irqsave(&canvas->lock, flags);
133	for (i = 0; i < NUM_CANVAS; ++i) {
134		if (!canvas->used[i]) {
135			canvas->used[i] = 1;
136			spin_unlock_irqrestore(&canvas->lock, flags);
137			*canvas_index = i;
138			return 0;
139		}
140	}
141	spin_unlock_irqrestore(&canvas->lock, flags);
142
143	dev_err(canvas->dev, "No more canvas available\n");
144	return -ENODEV;
145}
146EXPORT_SYMBOL_GPL(meson_canvas_alloc);
147
148int meson_canvas_free(struct meson_canvas *canvas, u8 canvas_index)
149{
150	unsigned long flags;
151
152	spin_lock_irqsave(&canvas->lock, flags);
153	if (!canvas->used[canvas_index]) {
154		dev_err(canvas->dev,
155			"Trying to free unused canvas %u\n", canvas_index);
156		spin_unlock_irqrestore(&canvas->lock, flags);
157		return -EINVAL;
158	}
159	canvas->used[canvas_index] = 0;
160	spin_unlock_irqrestore(&canvas->lock, flags);
161
162	return 0;
163}
164EXPORT_SYMBOL_GPL(meson_canvas_free);
165
166static int meson_canvas_probe(struct platform_device *pdev)
167{
168	struct meson_canvas *canvas;
169	struct device *dev = &pdev->dev;
170
171	canvas = devm_kzalloc(dev, sizeof(*canvas), GFP_KERNEL);
172	if (!canvas)
173		return -ENOMEM;
174
175	canvas->reg_base = devm_platform_ioremap_resource(pdev, 0);
176	if (IS_ERR(canvas->reg_base))
177		return PTR_ERR(canvas->reg_base);
178
179	canvas->supports_endianness = of_device_get_match_data(dev);
180
181	canvas->dev = dev;
182	spin_lock_init(&canvas->lock);
183	dev_set_drvdata(dev, canvas);
184
185	return 0;
186}
187
188static const struct of_device_id canvas_dt_match[] = {
189	{ .compatible = "amlogic,meson8-canvas", .data = (void *)false, },
190	{ .compatible = "amlogic,meson8b-canvas", .data = (void *)false, },
191	{ .compatible = "amlogic,meson8m2-canvas", .data = (void *)false, },
192	{ .compatible = "amlogic,canvas", .data = (void *)true, },
193	{}
194};
195MODULE_DEVICE_TABLE(of, canvas_dt_match);
196
197static struct platform_driver meson_canvas_driver = {
198	.probe = meson_canvas_probe,
199	.driver = {
200		.name = "amlogic-canvas",
201		.of_match_table = canvas_dt_match,
202	},
203};
204module_platform_driver(meson_canvas_driver);
205
206MODULE_DESCRIPTION("Amlogic Canvas driver");
207MODULE_AUTHOR("Maxime Jourdan <mjourdan@baylibre.com>");
208MODULE_LICENSE("GPL");
~/ Read-only file preview.