blob: 2ba5d0de1529180a830c664db5b4140df224af48 [file] [log] [blame]
Stephan Gerhold36f654a2021-07-02 19:21:56 +02001// SPDX-License-Identifier: GPL-2.0+
2/* Copyright (C) 2019 Stephan Gerhold */
3
Stephan Gerhold36f654a2021-07-02 19:21:56 +02004#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
26enum 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
41enum mcde_src_synch {
42 MCDE_CHNL0SYNCHMOD_SRC_SYNCH_HARDWARE,
43 MCDE_CHNL0SYNCHMOD_SRC_SYNCH_NO_SYNCH,
44 MCDE_CHNL0SYNCHMOD_SRC_SYNCH_SOFTWARE,
45};
46
47struct mcde_simple_priv {
48 fdt_addr_t base;
49 enum mcde_src_synch src_synch;
50};
51
52static 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
97static 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
124static struct video_ops mcde_simple_ops = {
125 .video_sync = mcde_simple_video_sync,
126};
127
128static const struct udevice_id mcde_simple_ids[] = {
129 { .compatible = "ste,mcde" },
130 { }
131};
132
133U_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};