1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* Copyright (C) 2020 Maxime Ripard <maxime@cerno.tech> */ |
3 | |
4 | #include <linux/device.h> |
5 | #include <linux/dma-map-ops.h> |
6 | #include <linux/init.h> |
7 | #include <linux/notifier.h> |
8 | #include <linux/of.h> |
9 | #include <linux/platform_device.h> |
10 | |
11 | static const char * const sunxi_mbus_devices[] = { |
12 | /* |
13 | * The display engine virtual devices are not strictly speaking |
14 | * connected to the MBUS, but since DRM will perform all the |
15 | * memory allocations and DMA operations through that device, we |
16 | * need to have the quirk on those devices too. |
17 | */ |
18 | "allwinner,sun4i-a10-display-engine" , |
19 | "allwinner,sun5i-a10s-display-engine" , |
20 | "allwinner,sun5i-a13-display-engine" , |
21 | "allwinner,sun6i-a31-display-engine" , |
22 | "allwinner,sun6i-a31s-display-engine" , |
23 | "allwinner,sun7i-a20-display-engine" , |
24 | "allwinner,sun8i-a23-display-engine" , |
25 | "allwinner,sun8i-a33-display-engine" , |
26 | "allwinner,sun9i-a80-display-engine" , |
27 | |
28 | /* |
29 | * And now we have the regular devices connected to the MBUS |
30 | * (that we know of). |
31 | */ |
32 | "allwinner,sun4i-a10-csi1" , |
33 | "allwinner,sun4i-a10-display-backend" , |
34 | "allwinner,sun4i-a10-display-frontend" , |
35 | "allwinner,sun4i-a10-video-engine" , |
36 | "allwinner,sun5i-a13-display-backend" , |
37 | "allwinner,sun5i-a13-video-engine" , |
38 | "allwinner,sun6i-a31-csi" , |
39 | "allwinner,sun6i-a31-display-backend" , |
40 | "allwinner,sun7i-a20-csi0" , |
41 | "allwinner,sun7i-a20-display-backend" , |
42 | "allwinner,sun7i-a20-display-frontend" , |
43 | "allwinner,sun7i-a20-video-engine" , |
44 | "allwinner,sun8i-a23-display-backend" , |
45 | "allwinner,sun8i-a23-display-frontend" , |
46 | "allwinner,sun8i-a33-display-backend" , |
47 | "allwinner,sun8i-a33-display-frontend" , |
48 | "allwinner,sun8i-a33-video-engine" , |
49 | "allwinner,sun8i-a83t-csi" , |
50 | "allwinner,sun8i-h3-csi" , |
51 | "allwinner,sun8i-h3-video-engine" , |
52 | "allwinner,sun8i-v3s-csi" , |
53 | "allwinner,sun9i-a80-display-backend" , |
54 | "allwinner,sun50i-a64-csi" , |
55 | "allwinner,sun50i-a64-video-engine" , |
56 | "allwinner,sun50i-h5-video-engine" , |
57 | NULL, |
58 | }; |
59 | |
60 | static int sunxi_mbus_notifier(struct notifier_block *nb, |
61 | unsigned long event, void *__dev) |
62 | { |
63 | struct device *dev = __dev; |
64 | int ret; |
65 | |
66 | if (event != BUS_NOTIFY_ADD_DEVICE) |
67 | return NOTIFY_DONE; |
68 | |
69 | /* |
70 | * Only the devices that need a large memory bandwidth do DMA |
71 | * directly over the memory bus (called MBUS), instead of going |
72 | * through the regular system bus. |
73 | */ |
74 | if (!of_device_compatible_match(device: dev->of_node, compat: sunxi_mbus_devices)) |
75 | return NOTIFY_DONE; |
76 | |
77 | /* |
78 | * Devices with an interconnects property have the MBUS |
79 | * relationship described in their DT and dealt with by |
80 | * of_dma_configure, so we can just skip them. |
81 | * |
82 | * Older DTs or SoCs who are not clearly understood need to set |
83 | * that DMA offset though. |
84 | */ |
85 | if (of_property_present(np: dev->of_node, propname: "interconnects" )) |
86 | return NOTIFY_DONE; |
87 | |
88 | ret = dma_direct_set_offset(dev, cpu_start: PHYS_OFFSET, dma_start: 0, SZ_4G); |
89 | if (ret) |
90 | dev_err(dev, "Couldn't setup our DMA offset: %d\n" , ret); |
91 | |
92 | return NOTIFY_DONE; |
93 | } |
94 | |
95 | static struct notifier_block sunxi_mbus_nb = { |
96 | .notifier_call = sunxi_mbus_notifier, |
97 | }; |
98 | |
99 | static const char * const sunxi_mbus_platforms[] __initconst = { |
100 | "allwinner,sun4i-a10" , |
101 | "allwinner,sun5i-a10s" , |
102 | "allwinner,sun5i-a13" , |
103 | "allwinner,sun6i-a31" , |
104 | "allwinner,sun7i-a20" , |
105 | "allwinner,sun8i-a23" , |
106 | "allwinner,sun8i-a33" , |
107 | "allwinner,sun8i-a83t" , |
108 | "allwinner,sun8i-h3" , |
109 | "allwinner,sun8i-r40" , |
110 | "allwinner,sun8i-v3" , |
111 | "allwinner,sun8i-v3s" , |
112 | "allwinner,sun9i-a80" , |
113 | "allwinner,sun50i-a64" , |
114 | "allwinner,sun50i-h5" , |
115 | "nextthing,gr8" , |
116 | NULL, |
117 | }; |
118 | |
119 | static int __init sunxi_mbus_init(void) |
120 | { |
121 | if (!of_device_compatible_match(device: of_root, compat: sunxi_mbus_platforms)) |
122 | return 0; |
123 | |
124 | bus_register_notifier(bus: &platform_bus_type, nb: &sunxi_mbus_nb); |
125 | return 0; |
126 | } |
127 | arch_initcall(sunxi_mbus_init); |
128 | |