1 // SPDX-License-Identifier: GPL-2.0+
2 /* Copyright (C) 2019 Stephan Gerhold */
3 
4 #include <dm.h>
5 #include <log.h>
6 #include <video.h>
7 #include <asm/io.h>
8 #include <linux/bitfield.h>
9 #include <linux/iopoll.h>
10 
11 #define MCDE_EXTSRC0A0			0x200
12 #define MCDE_EXTSRC0CONF		0x20C
13 #define MCDE_EXTSRC0CONF_BPP		GENMASK(11, 8)
14 #define MCDE_OVL0CONF			0x404
15 #define MCDE_OVL0CONF_PPL		GENMASK(10, 0)
16 #define MCDE_OVL0CONF_LPF		GENMASK(26, 16)
17 #define MCDE_CHNL0SYNCHMOD		0x608
18 #define MCDE_CHNL0SYNCHMOD_SRC_SYNCH	GENMASK(1, 0)
19 #define MCDE_CHNL0SYNCHSW		0x60C
20 #define MCDE_CHNL0SYNCHSW_SW_TRIG	BIT(0)
21 #define MCDE_CRA0			0x800
22 #define MCDE_CRA0_FLOEN			BIT(0)
23 
24 #define MCDE_FLOW_COMPLETION_TIMEOUT	200000	/* us */
25 
26 enum mcde_bpp {
27 	MCDE_EXTSRC0CONF_BPP_1BPP_PAL,
28 	MCDE_EXTSRC0CONF_BPP_2BPP_PAL,
29 	MCDE_EXTSRC0CONF_BPP_4BPP_PAL,
30 	MCDE_EXTSRC0CONF_BPP_8BPP_PAL,
31 	MCDE_EXTSRC0CONF_BPP_RGB444,
32 	MCDE_EXTSRC0CONF_BPP_ARGB4444,
33 	MCDE_EXTSRC0CONF_BPP_IRGB1555,
34 	MCDE_EXTSRC0CONF_BPP_RGB565,
35 	MCDE_EXTSRC0CONF_BPP_RGB888,
36 	MCDE_EXTSRC0CONF_BPP_XRGB8888,
37 	MCDE_EXTSRC0CONF_BPP_ARGB8888,
38 	MCDE_EXTSRC0CONF_BPP_YCBCR422,
39 };
40 
41 enum mcde_src_synch {
42 	MCDE_CHNL0SYNCHMOD_SRC_SYNCH_HARDWARE,
43 	MCDE_CHNL0SYNCHMOD_SRC_SYNCH_NO_SYNCH,
44 	MCDE_CHNL0SYNCHMOD_SRC_SYNCH_SOFTWARE,
45 };
46 
47 struct mcde_simple_priv {
48 	fdt_addr_t base;
49 	enum mcde_src_synch src_synch;
50 };
51 
mcde_simple_probe(struct udevice * dev)52 static int mcde_simple_probe(struct udevice *dev)
53 {
54 	struct mcde_simple_priv *priv = dev_get_priv(dev);
55 	struct video_uc_plat *plat = dev_get_uclass_plat(dev);
56 	struct video_priv *uc_priv = dev_get_uclass_priv(dev);
57 	u32 val;
58 
59 	priv->base = dev_read_addr(dev);
60 	if (priv->base == FDT_ADDR_T_NONE)
61 		return -EINVAL;
62 
63 	plat->base = readl(priv->base + MCDE_EXTSRC0A0);
64 	if (!plat->base)
65 		return -ENODEV;
66 
67 	val = readl(priv->base + MCDE_OVL0CONF);
68 	uc_priv->xsize = FIELD_GET(MCDE_OVL0CONF_PPL, val);
69 	uc_priv->ysize = FIELD_GET(MCDE_OVL0CONF_LPF, val);
70 	uc_priv->rot = 0;
71 
72 	val = readl(priv->base + MCDE_EXTSRC0CONF);
73 	switch (FIELD_GET(MCDE_EXTSRC0CONF_BPP, val)) {
74 	case MCDE_EXTSRC0CONF_BPP_RGB565:
75 		uc_priv->bpix = VIDEO_BPP16;
76 		break;
77 	case MCDE_EXTSRC0CONF_BPP_XRGB8888:
78 	case MCDE_EXTSRC0CONF_BPP_ARGB8888:
79 		uc_priv->bpix = VIDEO_BPP32;
80 		break;
81 	default:
82 		printf("unsupported format: %#x\n", val);
83 		return -EINVAL;
84 	}
85 
86 	val = readl(priv->base + MCDE_CHNL0SYNCHMOD);
87 	priv->src_synch = FIELD_GET(MCDE_CHNL0SYNCHMOD_SRC_SYNCH, val);
88 
89 	plat->size = uc_priv->xsize * uc_priv->ysize * VNBYTES(uc_priv->bpix);
90 	debug("MCDE base: %#lx, xsize: %d, ysize: %d, bpp: %d\n",
91 	      plat->base, uc_priv->xsize, uc_priv->ysize, VNBITS(uc_priv->bpix));
92 
93 	video_set_flush_dcache(dev, true);
94 	return 0;
95 }
96 
mcde_simple_video_sync(struct udevice * dev)97 static int mcde_simple_video_sync(struct udevice *dev)
98 {
99 	struct mcde_simple_priv *priv = dev_get_priv(dev);
100 	unsigned int val;
101 
102 	if (priv->src_synch != MCDE_CHNL0SYNCHMOD_SRC_SYNCH_SOFTWARE)
103 		return 0;
104 
105 	/* Enable flow */
106 	val = readl(priv->base + MCDE_CRA0);
107 	val |= MCDE_CRA0_FLOEN;
108 	writel(val, priv->base + MCDE_CRA0);
109 
110 	/* Trigger a software sync */
111 	writel(MCDE_CHNL0SYNCHSW_SW_TRIG, priv->base + MCDE_CHNL0SYNCHSW);
112 
113 	/* Disable flow */
114 	val = readl(priv->base + MCDE_CRA0);
115 	val &= ~MCDE_CRA0_FLOEN;
116 	writel(val, priv->base + MCDE_CRA0);
117 
118 	/* Wait for completion */
119 	return readl_poll_timeout(priv->base + MCDE_CRA0, val,
120 				  !(val & MCDE_CRA0_FLOEN),
121 				  MCDE_FLOW_COMPLETION_TIMEOUT);
122 }
123 
124 static struct video_ops mcde_simple_ops = {
125 	.video_sync = mcde_simple_video_sync,
126 };
127 
128 static const struct udevice_id mcde_simple_ids[] = {
129 	{ .compatible = "ste,mcde" },
130 	{ }
131 };
132 
133 U_BOOT_DRIVER(mcde_simple) = {
134 	.name		= "mcde_simple",
135 	.id		= UCLASS_VIDEO,
136 	.ops		= &mcde_simple_ops,
137 	.of_match	= mcde_simple_ids,
138 	.probe		= mcde_simple_probe,
139 	.priv_auto	= sizeof(struct mcde_simple_priv),
140 };
141