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