diff options
author | Olof Johansson <olof@lixom.net> | 2018-09-25 14:16:12 -0400 |
---|---|---|
committer | Olof Johansson <olof@lixom.net> | 2018-09-25 14:16:12 -0400 |
commit | bf1da406909b13903873d1f91346f99303fd8cb3 (patch) | |
tree | dc744892ec43a9af5e440e716bde1cdb00e36ccb | |
parent | 63c65b872562a2faf8a3a289c117d0c0e3bceb5a (diff) | |
parent | d4983983d98710e4927fdb8de8e987c303b3fba3 (diff) |
Merge tag 'amlogic-drivers' of https://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic into next/drivers
Amlogic ARM64 driver updates for v4.20
- add meson-canvas driver and bindings
- firmware: Add serial number sysfs entry
* tag 'amlogic-drivers' of https://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic:
soc: amlogic: add meson-canvas driver
dt-bindings: soc: amlogic: add meson-canvas documentation
firmware: meson_sm: Add serial number sysfs entry
Signed-off-by: Olof Johansson <olof@lixom.net>
-rw-r--r-- | Documentation/devicetree/bindings/soc/amlogic/amlogic,canvas.txt | 29 | ||||
-rw-r--r-- | drivers/firmware/meson/meson_sm.c | 56 | ||||
-rw-r--r-- | drivers/soc/amlogic/Kconfig | 7 | ||||
-rw-r--r-- | drivers/soc/amlogic/Makefile | 1 | ||||
-rw-r--r-- | drivers/soc/amlogic/meson-canvas.c | 185 | ||||
-rw-r--r-- | include/linux/firmware/meson/meson_sm.h | 1 | ||||
-rw-r--r-- | include/linux/soc/amlogic/meson-canvas.h | 65 |
7 files changed, 344 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/soc/amlogic/amlogic,canvas.txt b/Documentation/devicetree/bindings/soc/amlogic/amlogic,canvas.txt new file mode 100644 index 000000000000..436d2106e80d --- /dev/null +++ b/Documentation/devicetree/bindings/soc/amlogic/amlogic,canvas.txt | |||
@@ -0,0 +1,29 @@ | |||
1 | Amlogic Canvas | ||
2 | ================================ | ||
3 | |||
4 | A canvas is a collection of metadata that describes a pixel buffer. | ||
5 | Those metadata include: width, height, phyaddr, wrapping, block mode | ||
6 | and endianness. | ||
7 | |||
8 | Many IPs within Amlogic SoCs rely on canvas indexes to read/write pixel data | ||
9 | rather than use the phy addresses directly. For instance, this is the case for | ||
10 | the video decoders and the display. | ||
11 | |||
12 | Amlogic SoCs have 256 canvas. | ||
13 | |||
14 | Device Tree Bindings: | ||
15 | --------------------- | ||
16 | |||
17 | Video Lookup Table | ||
18 | -------------------------- | ||
19 | |||
20 | Required properties: | ||
21 | - compatible: "amlogic,canvas" | ||
22 | - reg: Base physical address and size of the canvas registers. | ||
23 | |||
24 | Example: | ||
25 | |||
26 | canvas: video-lut@48 { | ||
27 | compatible = "amlogic,canvas"; | ||
28 | reg = <0x0 0x48 0x0 0x14>; | ||
29 | }; | ||
diff --git a/drivers/firmware/meson/meson_sm.c b/drivers/firmware/meson/meson_sm.c index 0ec2ca87318c..29fbc818a573 100644 --- a/drivers/firmware/meson/meson_sm.c +++ b/drivers/firmware/meson/meson_sm.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <linux/printk.h> | 24 | #include <linux/printk.h> |
25 | #include <linux/types.h> | 25 | #include <linux/types.h> |
26 | #include <linux/sizes.h> | 26 | #include <linux/sizes.h> |
27 | #include <linux/slab.h> | ||
27 | 28 | ||
28 | #include <linux/firmware/meson/meson_sm.h> | 29 | #include <linux/firmware/meson/meson_sm.h> |
29 | 30 | ||
@@ -48,6 +49,7 @@ struct meson_sm_chip gxbb_chip = { | |||
48 | CMD(SM_EFUSE_READ, 0x82000030), | 49 | CMD(SM_EFUSE_READ, 0x82000030), |
49 | CMD(SM_EFUSE_WRITE, 0x82000031), | 50 | CMD(SM_EFUSE_WRITE, 0x82000031), |
50 | CMD(SM_EFUSE_USER_MAX, 0x82000033), | 51 | CMD(SM_EFUSE_USER_MAX, 0x82000033), |
52 | CMD(SM_GET_CHIP_ID, 0x82000044), | ||
51 | { /* sentinel */ }, | 53 | { /* sentinel */ }, |
52 | }, | 54 | }, |
53 | }; | 55 | }; |
@@ -214,6 +216,57 @@ int meson_sm_call_write(void *buffer, unsigned int size, unsigned int cmd_index, | |||
214 | } | 216 | } |
215 | EXPORT_SYMBOL(meson_sm_call_write); | 217 | EXPORT_SYMBOL(meson_sm_call_write); |
216 | 218 | ||
219 | #define SM_CHIP_ID_LENGTH 119 | ||
220 | #define SM_CHIP_ID_OFFSET 4 | ||
221 | #define SM_CHIP_ID_SIZE 12 | ||
222 | |||
223 | static ssize_t serial_show(struct device *dev, struct device_attribute *attr, | ||
224 | char *buf) | ||
225 | { | ||
226 | uint8_t *id_buf; | ||
227 | int ret; | ||
228 | |||
229 | id_buf = kmalloc(SM_CHIP_ID_LENGTH, GFP_KERNEL); | ||
230 | if (!id_buf) | ||
231 | return -ENOMEM; | ||
232 | |||
233 | ret = meson_sm_call_read(id_buf, SM_CHIP_ID_LENGTH, SM_GET_CHIP_ID, | ||
234 | 0, 0, 0, 0, 0); | ||
235 | if (ret < 0) { | ||
236 | kfree(id_buf); | ||
237 | return ret; | ||
238 | } | ||
239 | |||
240 | ret = sprintf(buf, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", | ||
241 | id_buf[SM_CHIP_ID_OFFSET + 0], | ||
242 | id_buf[SM_CHIP_ID_OFFSET + 1], | ||
243 | id_buf[SM_CHIP_ID_OFFSET + 2], | ||
244 | id_buf[SM_CHIP_ID_OFFSET + 3], | ||
245 | id_buf[SM_CHIP_ID_OFFSET + 4], | ||
246 | id_buf[SM_CHIP_ID_OFFSET + 5], | ||
247 | id_buf[SM_CHIP_ID_OFFSET + 6], | ||
248 | id_buf[SM_CHIP_ID_OFFSET + 7], | ||
249 | id_buf[SM_CHIP_ID_OFFSET + 8], | ||
250 | id_buf[SM_CHIP_ID_OFFSET + 9], | ||
251 | id_buf[SM_CHIP_ID_OFFSET + 10], | ||
252 | id_buf[SM_CHIP_ID_OFFSET + 11]); | ||
253 | |||
254 | kfree(id_buf); | ||
255 | |||
256 | return ret; | ||
257 | } | ||
258 | |||
259 | static DEVICE_ATTR_RO(serial); | ||
260 | |||
261 | static struct attribute *meson_sm_sysfs_attributes[] = { | ||
262 | &dev_attr_serial.attr, | ||
263 | NULL, | ||
264 | }; | ||
265 | |||
266 | static const struct attribute_group meson_sm_sysfs_attr_group = { | ||
267 | .attrs = meson_sm_sysfs_attributes, | ||
268 | }; | ||
269 | |||
217 | static const struct of_device_id meson_sm_ids[] = { | 270 | static const struct of_device_id meson_sm_ids[] = { |
218 | { .compatible = "amlogic,meson-gxbb-sm", .data = &gxbb_chip }, | 271 | { .compatible = "amlogic,meson-gxbb-sm", .data = &gxbb_chip }, |
219 | { /* sentinel */ }, | 272 | { /* sentinel */ }, |
@@ -242,6 +295,9 @@ static int __init meson_sm_probe(struct platform_device *pdev) | |||
242 | fw.chip = chip; | 295 | fw.chip = chip; |
243 | pr_info("secure-monitor enabled\n"); | 296 | pr_info("secure-monitor enabled\n"); |
244 | 297 | ||
298 | if (sysfs_create_group(&pdev->dev.kobj, &meson_sm_sysfs_attr_group)) | ||
299 | goto out_in_base; | ||
300 | |||
245 | return 0; | 301 | return 0; |
246 | 302 | ||
247 | out_in_base: | 303 | out_in_base: |
diff --git a/drivers/soc/amlogic/Kconfig b/drivers/soc/amlogic/Kconfig index b04f6e4aedbc..2f282b472912 100644 --- a/drivers/soc/amlogic/Kconfig +++ b/drivers/soc/amlogic/Kconfig | |||
@@ -1,5 +1,12 @@ | |||
1 | menu "Amlogic SoC drivers" | 1 | menu "Amlogic SoC drivers" |
2 | 2 | ||
3 | config MESON_CANVAS | ||
4 | tristate "Amlogic Meson Canvas driver" | ||
5 | depends on ARCH_MESON || COMPILE_TEST | ||
6 | default n | ||
7 | help | ||
8 | Say yes to support the canvas IP for Amlogic SoCs. | ||
9 | |||
3 | config MESON_GX_SOCINFO | 10 | config MESON_GX_SOCINFO |
4 | bool "Amlogic Meson GX SoC Information driver" | 11 | bool "Amlogic Meson GX SoC Information driver" |
5 | depends on ARCH_MESON || COMPILE_TEST | 12 | depends on ARCH_MESON || COMPILE_TEST |
diff --git a/drivers/soc/amlogic/Makefile b/drivers/soc/amlogic/Makefile index 8fa321893928..0ab16d35ac36 100644 --- a/drivers/soc/amlogic/Makefile +++ b/drivers/soc/amlogic/Makefile | |||
@@ -1,3 +1,4 @@ | |||
1 | obj-$(CONFIG_MESON_CANVAS) += meson-canvas.o | ||
1 | obj-$(CONFIG_MESON_GX_SOCINFO) += meson-gx-socinfo.o | 2 | obj-$(CONFIG_MESON_GX_SOCINFO) += meson-gx-socinfo.o |
2 | obj-$(CONFIG_MESON_GX_PM_DOMAINS) += meson-gx-pwrc-vpu.o | 3 | obj-$(CONFIG_MESON_GX_PM_DOMAINS) += meson-gx-pwrc-vpu.o |
3 | obj-$(CONFIG_MESON_MX_SOCINFO) += meson-mx-socinfo.o | 4 | obj-$(CONFIG_MESON_MX_SOCINFO) += meson-mx-socinfo.o |
diff --git a/drivers/soc/amlogic/meson-canvas.c b/drivers/soc/amlogic/meson-canvas.c new file mode 100644 index 000000000000..fce33ca76bb6 --- /dev/null +++ b/drivers/soc/amlogic/meson-canvas.c | |||
@@ -0,0 +1,185 @@ | |||
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/regmap.h> | ||
12 | #include <linux/soc/amlogic/meson-canvas.h> | ||
13 | #include <linux/of_address.h> | ||
14 | #include <linux/of_platform.h> | ||
15 | #include <linux/io.h> | ||
16 | |||
17 | #define NUM_CANVAS 256 | ||
18 | |||
19 | /* DMC Registers */ | ||
20 | #define DMC_CAV_LUT_DATAL 0x00 | ||
21 | #define CANVAS_WIDTH_LBIT 29 | ||
22 | #define CANVAS_WIDTH_LWID 3 | ||
23 | #define DMC_CAV_LUT_DATAH 0x04 | ||
24 | #define CANVAS_WIDTH_HBIT 0 | ||
25 | #define CANVAS_HEIGHT_BIT 9 | ||
26 | #define CANVAS_WRAP_BIT 22 | ||
27 | #define CANVAS_BLKMODE_BIT 24 | ||
28 | #define CANVAS_ENDIAN_BIT 26 | ||
29 | #define DMC_CAV_LUT_ADDR 0x08 | ||
30 | #define CANVAS_LUT_WR_EN BIT(9) | ||
31 | #define CANVAS_LUT_RD_EN BIT(8) | ||
32 | |||
33 | struct meson_canvas { | ||
34 | struct device *dev; | ||
35 | void __iomem *reg_base; | ||
36 | spinlock_t lock; /* canvas device lock */ | ||
37 | u8 used[NUM_CANVAS]; | ||
38 | }; | ||
39 | |||
40 | static void canvas_write(struct meson_canvas *canvas, u32 reg, u32 val) | ||
41 | { | ||
42 | writel_relaxed(val, canvas->reg_base + reg); | ||
43 | } | ||
44 | |||
45 | static u32 canvas_read(struct meson_canvas *canvas, u32 reg) | ||
46 | { | ||
47 | return readl_relaxed(canvas->reg_base + reg); | ||
48 | } | ||
49 | |||
50 | struct meson_canvas *meson_canvas_get(struct device *dev) | ||
51 | { | ||
52 | struct device_node *canvas_node; | ||
53 | struct platform_device *canvas_pdev; | ||
54 | |||
55 | canvas_node = of_parse_phandle(dev->of_node, "amlogic,canvas", 0); | ||
56 | if (!canvas_node) | ||
57 | return ERR_PTR(-ENODEV); | ||
58 | |||
59 | canvas_pdev = of_find_device_by_node(canvas_node); | ||
60 | if (!canvas_pdev) | ||
61 | return ERR_PTR(-EPROBE_DEFER); | ||
62 | |||
63 | return dev_get_drvdata(&canvas_pdev->dev); | ||
64 | } | ||
65 | EXPORT_SYMBOL_GPL(meson_canvas_get); | ||
66 | |||
67 | int meson_canvas_config(struct meson_canvas *canvas, u8 canvas_index, | ||
68 | u32 addr, u32 stride, u32 height, | ||
69 | unsigned int wrap, | ||
70 | unsigned int blkmode, | ||
71 | unsigned int endian) | ||
72 | { | ||
73 | unsigned long flags; | ||
74 | |||
75 | spin_lock_irqsave(&canvas->lock, flags); | ||
76 | if (!canvas->used[canvas_index]) { | ||
77 | dev_err(canvas->dev, | ||
78 | "Trying to setup non allocated canvas %u\n", | ||
79 | canvas_index); | ||
80 | spin_unlock_irqrestore(&canvas->lock, flags); | ||
81 | return -EINVAL; | ||
82 | } | ||
83 | |||
84 | canvas_write(canvas, DMC_CAV_LUT_DATAL, | ||
85 | ((addr + 7) >> 3) | | ||
86 | (((stride + 7) >> 3) << CANVAS_WIDTH_LBIT)); | ||
87 | |||
88 | canvas_write(canvas, DMC_CAV_LUT_DATAH, | ||
89 | ((((stride + 7) >> 3) >> CANVAS_WIDTH_LWID) << | ||
90 | CANVAS_WIDTH_HBIT) | | ||
91 | (height << CANVAS_HEIGHT_BIT) | | ||
92 | (wrap << CANVAS_WRAP_BIT) | | ||
93 | (blkmode << CANVAS_BLKMODE_BIT) | | ||
94 | (endian << CANVAS_ENDIAN_BIT)); | ||
95 | |||
96 | canvas_write(canvas, DMC_CAV_LUT_ADDR, | ||
97 | CANVAS_LUT_WR_EN | canvas_index); | ||
98 | |||
99 | /* Force a read-back to make sure everything is flushed. */ | ||
100 | canvas_read(canvas, DMC_CAV_LUT_DATAH); | ||
101 | spin_unlock_irqrestore(&canvas->lock, flags); | ||
102 | |||
103 | return 0; | ||
104 | } | ||
105 | EXPORT_SYMBOL_GPL(meson_canvas_config); | ||
106 | |||
107 | int meson_canvas_alloc(struct meson_canvas *canvas, u8 *canvas_index) | ||
108 | { | ||
109 | int i; | ||
110 | unsigned long flags; | ||
111 | |||
112 | spin_lock_irqsave(&canvas->lock, flags); | ||
113 | for (i = 0; i < NUM_CANVAS; ++i) { | ||
114 | if (!canvas->used[i]) { | ||
115 | canvas->used[i] = 1; | ||
116 | spin_unlock_irqrestore(&canvas->lock, flags); | ||
117 | *canvas_index = i; | ||
118 | return 0; | ||
119 | } | ||
120 | } | ||
121 | spin_unlock_irqrestore(&canvas->lock, flags); | ||
122 | |||
123 | dev_err(canvas->dev, "No more canvas available\n"); | ||
124 | return -ENODEV; | ||
125 | } | ||
126 | EXPORT_SYMBOL_GPL(meson_canvas_alloc); | ||
127 | |||
128 | int meson_canvas_free(struct meson_canvas *canvas, u8 canvas_index) | ||
129 | { | ||
130 | unsigned long flags; | ||
131 | |||
132 | spin_lock_irqsave(&canvas->lock, flags); | ||
133 | if (!canvas->used[canvas_index]) { | ||
134 | dev_err(canvas->dev, | ||
135 | "Trying to free unused canvas %u\n", canvas_index); | ||
136 | spin_unlock_irqrestore(&canvas->lock, flags); | ||
137 | return -EINVAL; | ||
138 | } | ||
139 | canvas->used[canvas_index] = 0; | ||
140 | spin_unlock_irqrestore(&canvas->lock, flags); | ||
141 | |||
142 | return 0; | ||
143 | } | ||
144 | EXPORT_SYMBOL_GPL(meson_canvas_free); | ||
145 | |||
146 | static int meson_canvas_probe(struct platform_device *pdev) | ||
147 | { | ||
148 | struct resource *res; | ||
149 | struct meson_canvas *canvas; | ||
150 | struct device *dev = &pdev->dev; | ||
151 | |||
152 | canvas = devm_kzalloc(dev, sizeof(*canvas), GFP_KERNEL); | ||
153 | if (!canvas) | ||
154 | return -ENOMEM; | ||
155 | |||
156 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
157 | canvas->reg_base = devm_ioremap_resource(dev, res); | ||
158 | if (IS_ERR(canvas->reg_base)) | ||
159 | return PTR_ERR(canvas->reg_base); | ||
160 | |||
161 | canvas->dev = dev; | ||
162 | spin_lock_init(&canvas->lock); | ||
163 | dev_set_drvdata(dev, canvas); | ||
164 | |||
165 | return 0; | ||
166 | } | ||
167 | |||
168 | static const struct of_device_id canvas_dt_match[] = { | ||
169 | { .compatible = "amlogic,canvas" }, | ||
170 | {} | ||
171 | }; | ||
172 | MODULE_DEVICE_TABLE(of, canvas_dt_match); | ||
173 | |||
174 | static struct platform_driver meson_canvas_driver = { | ||
175 | .probe = meson_canvas_probe, | ||
176 | .driver = { | ||
177 | .name = "amlogic-canvas", | ||
178 | .of_match_table = canvas_dt_match, | ||
179 | }, | ||
180 | }; | ||
181 | module_platform_driver(meson_canvas_driver); | ||
182 | |||
183 | MODULE_DESCRIPTION("Amlogic Canvas driver"); | ||
184 | MODULE_AUTHOR("Maxime Jourdan <mjourdan@baylibre.com>"); | ||
185 | MODULE_LICENSE("GPL"); | ||
diff --git a/include/linux/firmware/meson/meson_sm.h b/include/linux/firmware/meson/meson_sm.h index 37a5eaea69dd..f98c20dd266e 100644 --- a/include/linux/firmware/meson/meson_sm.h +++ b/include/linux/firmware/meson/meson_sm.h | |||
@@ -17,6 +17,7 @@ enum { | |||
17 | SM_EFUSE_READ, | 17 | SM_EFUSE_READ, |
18 | SM_EFUSE_WRITE, | 18 | SM_EFUSE_WRITE, |
19 | SM_EFUSE_USER_MAX, | 19 | SM_EFUSE_USER_MAX, |
20 | SM_GET_CHIP_ID, | ||
20 | }; | 21 | }; |
21 | 22 | ||
22 | struct meson_sm_firmware; | 23 | struct meson_sm_firmware; |
diff --git a/include/linux/soc/amlogic/meson-canvas.h b/include/linux/soc/amlogic/meson-canvas.h new file mode 100644 index 000000000000..b4dde2fbeb3f --- /dev/null +++ b/include/linux/soc/amlogic/meson-canvas.h | |||
@@ -0,0 +1,65 @@ | |||
1 | /* SPDX-License-Identifier: GPL-2.0+ */ | ||
2 | /* | ||
3 | * Copyright (C) 2018 BayLibre, SAS | ||
4 | */ | ||
5 | #ifndef __SOC_MESON_CANVAS_H | ||
6 | #define __SOC_MESON_CANVAS_H | ||
7 | |||
8 | #include <linux/kernel.h> | ||
9 | |||
10 | #define MESON_CANVAS_WRAP_NONE 0x00 | ||
11 | #define MESON_CANVAS_WRAP_X 0x01 | ||
12 | #define MESON_CANVAS_WRAP_Y 0x02 | ||
13 | |||
14 | #define MESON_CANVAS_BLKMODE_LINEAR 0x00 | ||
15 | #define MESON_CANVAS_BLKMODE_32x32 0x01 | ||
16 | #define MESON_CANVAS_BLKMODE_64x64 0x02 | ||
17 | |||
18 | #define MESON_CANVAS_ENDIAN_SWAP16 0x1 | ||
19 | #define MESON_CANVAS_ENDIAN_SWAP32 0x3 | ||
20 | #define MESON_CANVAS_ENDIAN_SWAP64 0x7 | ||
21 | #define MESON_CANVAS_ENDIAN_SWAP128 0xf | ||
22 | |||
23 | struct meson_canvas; | ||
24 | |||
25 | /** | ||
26 | * meson_canvas_get() - get a canvas provider instance | ||
27 | * | ||
28 | * @dev: consumer device pointer | ||
29 | */ | ||
30 | struct meson_canvas *meson_canvas_get(struct device *dev); | ||
31 | |||
32 | /** | ||
33 | * meson_canvas_alloc() - take ownership of a canvas | ||
34 | * | ||
35 | * @canvas: canvas provider instance retrieved from meson_canvas_get() | ||
36 | * @canvas_index: will be filled with the canvas ID | ||
37 | */ | ||
38 | int meson_canvas_alloc(struct meson_canvas *canvas, u8 *canvas_index); | ||
39 | |||
40 | /** | ||
41 | * meson_canvas_free() - remove ownership from a canvas | ||
42 | * | ||
43 | * @canvas: canvas provider instance retrieved from meson_canvas_get() | ||
44 | * @canvas_index: canvas ID that was obtained via meson_canvas_alloc() | ||
45 | */ | ||
46 | int meson_canvas_free(struct meson_canvas *canvas, u8 canvas_index); | ||
47 | |||
48 | /** | ||
49 | * meson_canvas_config() - configure a canvas | ||
50 | * | ||
51 | * @canvas: canvas provider instance retrieved from meson_canvas_get() | ||
52 | * @canvas_index: canvas ID that was obtained via meson_canvas_alloc() | ||
53 | * @addr: physical address to the pixel buffer | ||
54 | * @stride: width of the buffer | ||
55 | * @height: height of the buffer | ||
56 | * @wrap: undocumented | ||
57 | * @blkmode: block mode (linear, 32x32, 64x64) | ||
58 | * @endian: byte swapping (swap16, swap32, swap64, swap128) | ||
59 | */ | ||
60 | int meson_canvas_config(struct meson_canvas *canvas, u8 canvas_index, | ||
61 | u32 addr, u32 stride, u32 height, | ||
62 | unsigned int wrap, unsigned int blkmode, | ||
63 | unsigned int endian); | ||
64 | |||
65 | #endif | ||