146432Sphk// SPDX-License-Identifier: GPL-2.0
246432Sphk/* Copyright (C) 2020 Maxime Ripard <maxime@cerno.tech> */
346432Sphk
446432Sphk#include <linux/device.h>
546432Sphk#include <linux/dma-map-ops.h>
646432Sphk#include <linux/init.h>
746432Sphk#include <linux/notifier.h>
846432Sphk#include <linux/of.h>
946432Sphk#include <linux/platform_device.h>
10117280Scharnier
11117280Scharnierstatic const char * const sunxi_mbus_devices[] = {
12117280Scharnier	/*
13112705Smaxim	 * The display engine virtual devices are not strictly speaking
1446155Sphk	 * connected to the MBUS, but since DRM will perform all the
15158428Smatteo	 * memory allocations and DMA operations through that device, we
1678723Sdd	 * need to have the quirk on those devices too.
1746155Sphk	 */
1878723Sdd	"allwinner,sun4i-a10-display-engine",
1946155Sphk	"allwinner,sun5i-a10s-display-engine",
2078723Sdd	"allwinner,sun5i-a13-display-engine",
21129848Smaxim	"allwinner,sun6i-a31-display-engine",
22112705Smaxim	"allwinner,sun6i-a31s-display-engine",
23112705Smaxim	"allwinner,sun7i-a20-display-engine",
24133743Smaxim	"allwinner,sun8i-a23-display-engine",
25112705Smaxim	"allwinner,sun8i-a33-display-engine",
2678723Sdd	"allwinner,sun9i-a80-display-engine",
2778723Sdd
2878723Sdd	/*
2978723Sdd	 * And now we have the regular devices connected to the MBUS
3078723Sdd	 * (that we know of).
31112705Smaxim	 */
32133743Smaxim	"allwinner,sun4i-a10-csi1",
33112705Smaxim	"allwinner,sun4i-a10-display-backend",
34129848Smaxim	"allwinner,sun4i-a10-display-frontend",
35129848Smaxim	"allwinner,sun4i-a10-video-engine",
36129848Smaxim	"allwinner,sun5i-a13-display-backend",
37129848Smaxim	"allwinner,sun5i-a13-video-engine",
38129848Smaxim	"allwinner,sun6i-a31-csi",
39129848Smaxim	"allwinner,sun6i-a31-display-backend",
40129848Smaxim	"allwinner,sun7i-a20-csi0",
41129848Smaxim	"allwinner,sun7i-a20-display-backend",
42129848Smaxim	"allwinner,sun7i-a20-display-frontend",
43129848Smaxim	"allwinner,sun7i-a20-video-engine",
44129848Smaxim	"allwinner,sun8i-a23-display-backend",
45129848Smaxim	"allwinner,sun8i-a23-display-frontend",
46129848Smaxim	"allwinner,sun8i-a33-display-backend",
47129848Smaxim	"allwinner,sun8i-a33-display-frontend",
48129848Smaxim	"allwinner,sun8i-a33-video-engine",
49129848Smaxim	"allwinner,sun8i-a83t-csi",
5046155Sphk	"allwinner,sun8i-h3-csi",
5146155Sphk	"allwinner,sun8i-h3-video-engine",
5246155Sphk	"allwinner,sun8i-v3s-csi",
53137808Sdelphij	"allwinner,sun9i-a80-display-backend",
5446155Sphk	"allwinner,sun50i-a64-csi",
55137808Sdelphij	"allwinner,sun50i-a64-video-engine",
5646155Sphk	"allwinner,sun50i-h5-video-engine",
57136051Sstefanf	NULL,
58158475Smatteo};
59158475Smatteo
60133743Smaximstatic int sunxi_mbus_notifier(struct notifier_block *nb,
61137807Sdelphij			       unsigned long event, void *__dev)
62158475Smatteo{
63153056Sphilip	struct device *dev = __dev;
6446155Sphk	int ret;
65153056Sphilip
66158475Smatteo	if (event != BUS_NOTIFY_ADD_DEVICE)
67153056Sphilip		return NOTIFY_DONE;
68153056Sphilip
69112705Smaxim	/*
70158428Smatteo	 * Only the devices that need a large memory bandwidth do DMA
71112705Smaxim	 * directly over the memory bus (called MBUS), instead of going
72113277Smike	 * through the regular system bus.
73113277Smike	 */
74113277Smike	if (!of_device_compatible_match(dev->of_node, sunxi_mbus_devices))
75153056Sphilip		return NOTIFY_DONE;
76153056Sphilip
77153056Sphilip	/*
78153056Sphilip	 * Devices with an interconnects property have the MBUS
79158428Smatteo	 * relationship described in their DT and dealt with by
80158475Smatteo	 * of_dma_configure, so we can just skip them.
81158475Smatteo	 *
82158475Smatteo	 * Older DTs or SoCs who are not clearly understood need to set
83158475Smatteo	 * that DMA offset though.
84158428Smatteo	 */
85112705Smaxim	if (of_property_present(dev->of_node, "interconnects"))
86112705Smaxim		return NOTIFY_DONE;
87129848Smaxim
88112705Smaxim	ret = dma_direct_set_offset(dev, PHYS_OFFSET, 0, SZ_4G);
89129848Smaxim	if (ret)
90129848Smaxim		dev_err(dev, "Couldn't setup our DMA offset: %d\n", ret);
91129848Smaxim
92129848Smaxim	return NOTIFY_DONE;
93133743Smaxim}
94133743Smaxim
95133743Smaximstatic struct notifier_block sunxi_mbus_nb = {
96112705Smaxim	.notifier_call = sunxi_mbus_notifier,
97112705Smaxim};
98112705Smaxim
99113277Smikestatic const char * const sunxi_mbus_platforms[] __initconst = {
100112705Smaxim	"allwinner,sun4i-a10",
101112705Smaxim	"allwinner,sun5i-a10s",
102112705Smaxim	"allwinner,sun5i-a13",
103112705Smaxim	"allwinner,sun6i-a31",
104129848Smaxim	"allwinner,sun7i-a20",
105129848Smaxim	"allwinner,sun8i-a23",
106133743Smaxim	"allwinner,sun8i-a33",
107133743Smaxim	"allwinner,sun8i-a83t",
108129848Smaxim	"allwinner,sun8i-h3",
109129848Smaxim	"allwinner,sun8i-r40",
110131182Spjd	"allwinner,sun8i-v3",
111131182Spjd	"allwinner,sun8i-v3s",
112131182Spjd	"allwinner,sun9i-a80",
113131182Spjd	"allwinner,sun50i-a64",
11451399Sphk	"allwinner,sun50i-h5",
11551399Sphk	"nextthing,gr8",
116131182Spjd	NULL,
117112705Smaxim};
118112972Smaxim
119112972Smaximstatic int __init sunxi_mbus_init(void)
12046432Sphk{
121153056Sphilip	if (!of_device_compatible_match(of_root, sunxi_mbus_platforms))
122153056Sphilip		return 0;
123153056Sphilip
124153056Sphilip	bus_register_notifier(&platform_bus_type, &sunxi_mbus_nb);
125153056Sphilip	return 0;
126113277Smike}
127113277Smikearch_initcall(sunxi_mbus_init);
128112972Smaxim