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 27enum 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 42enum mcde_src_synch { 43 MCDE_CHNL0SYNCHMOD_SRC_SYNCH_HARDWARE, 44 MCDE_CHNL0SYNCHMOD_SRC_SYNCH_NO_SYNCH, 45 MCDE_CHNL0SYNCHMOD_SRC_SYNCH_SOFTWARE, 46}; 47 48struct mcde_simple_priv { 49 fdt_addr_t base; 50 enum mcde_src_synch src_synch; 51}; 52 53static 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 98static 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 125static struct video_ops mcde_simple_ops = { 126 .video_sync = mcde_simple_video_sync, 127}; 128 129static const struct udevice_id mcde_simple_ids[] = { 130 { .compatible = "ste,mcde" }, 131 { } 132}; 133 134U_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}; 142