Home | History | Annotate | Download | only in sunxi
      1 // SPDX-License-Identifier: GPL-2.0+
      2 /*
      3  * Allwinner DE2 display driver
      4  *
      5  * (C) Copyright 2017 Jernej Skrabec <jernej.skrabec (at) siol.net>
      6  */
      7 
      8 #include <common.h>
      9 #include <display.h>
     10 #include <dm.h>
     11 #include <edid.h>
     12 #include <efi_loader.h>
     13 #include <fdtdec.h>
     14 #include <fdt_support.h>
     15 #include <video.h>
     16 #include <asm/global_data.h>
     17 #include <asm/io.h>
     18 #include <asm/arch/clock.h>
     19 #include <asm/arch/display2.h>
     20 #include <dm/device-internal.h>
     21 #include <dm/uclass-internal.h>
     22 #include "simplefb_common.h"
     23 
     24 DECLARE_GLOBAL_DATA_PTR;
     25 
     26 enum {
     27 	/* Maximum LCD size we support */
     28 	LCD_MAX_WIDTH		= 3840,
     29 	LCD_MAX_HEIGHT		= 2160,
     30 	LCD_MAX_LOG2_BPP	= VIDEO_BPP32,
     31 };
     32 
     33 static void sunxi_de2_composer_init(void)
     34 {
     35 	struct sunxi_ccm_reg * const ccm =
     36 		(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
     37 
     38 #ifdef CONFIG_MACH_SUN50I
     39 	u32 reg_value;
     40 
     41 	/* set SRAM for video use (A64 only) */
     42 	reg_value = readl(SUNXI_SRAMC_BASE + 0x04);
     43 	reg_value &= ~(0x01 << 24);
     44 	writel(reg_value, SUNXI_SRAMC_BASE + 0x04);
     45 #endif
     46 
     47 	clock_set_pll10(432000000);
     48 
     49 	/* Set DE parent to pll10 */
     50 	clrsetbits_le32(&ccm->de_clk_cfg, CCM_DE2_CTRL_PLL_MASK,
     51 			CCM_DE2_CTRL_PLL10);
     52 
     53 	/* Set ahb gating to pass */
     54 	setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_DE);
     55 	setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_DE);
     56 
     57 	/* Clock on */
     58 	setbits_le32(&ccm->de_clk_cfg, CCM_DE2_CTRL_GATE);
     59 }
     60 
     61 static void sunxi_de2_mode_set(int mux, const struct display_timing *mode,
     62 			       int bpp, ulong address, bool is_composite)
     63 {
     64 	ulong de_mux_base = (mux == 0) ?
     65 			    SUNXI_DE2_MUX0_BASE : SUNXI_DE2_MUX1_BASE;
     66 	struct de_clk * const de_clk_regs =
     67 		(struct de_clk *)(SUNXI_DE2_BASE);
     68 	struct de_glb * const de_glb_regs =
     69 		(struct de_glb *)(de_mux_base +
     70 				  SUNXI_DE2_MUX_GLB_REGS);
     71 	struct de_bld * const de_bld_regs =
     72 		(struct de_bld *)(de_mux_base +
     73 				  SUNXI_DE2_MUX_BLD_REGS);
     74 	struct de_ui * const de_ui_regs =
     75 		(struct de_ui *)(de_mux_base +
     76 				 SUNXI_DE2_MUX_CHAN_REGS +
     77 				 SUNXI_DE2_MUX_CHAN_SZ * 1);
     78 	struct de_csc * const de_csc_regs =
     79 		(struct de_csc *)(de_mux_base +
     80 				  SUNXI_DE2_MUX_DCSC_REGS);
     81 	u32 size = SUNXI_DE2_WH(mode->hactive.typ, mode->vactive.typ);
     82 	int channel;
     83 	u32 format;
     84 
     85 	/* enable clock */
     86 #ifdef CONFIG_MACH_SUN8I_H3
     87 	setbits_le32(&de_clk_regs->rst_cfg, (mux == 0) ? 1 : 4);
     88 #else
     89 	setbits_le32(&de_clk_regs->rst_cfg, BIT(mux));
     90 #endif
     91 	setbits_le32(&de_clk_regs->gate_cfg, BIT(mux));
     92 	setbits_le32(&de_clk_regs->bus_cfg, BIT(mux));
     93 
     94 	clrbits_le32(&de_clk_regs->sel_cfg, 1);
     95 
     96 	writel(SUNXI_DE2_MUX_GLB_CTL_EN, &de_glb_regs->ctl);
     97 	writel(0, &de_glb_regs->status);
     98 	writel(1, &de_glb_regs->dbuff);
     99 	writel(size, &de_glb_regs->size);
    100 
    101 	for (channel = 0; channel < 4; channel++) {
    102 		void *ch = (void *)(de_mux_base + SUNXI_DE2_MUX_CHAN_REGS +
    103 				    SUNXI_DE2_MUX_CHAN_SZ * channel);
    104 		memset(ch, 0, (channel == 0) ?
    105 			sizeof(struct de_vi) : sizeof(struct de_ui));
    106 	}
    107 	memset(de_bld_regs, 0, sizeof(struct de_bld));
    108 
    109 	writel(0x00000101, &de_bld_regs->fcolor_ctl);
    110 
    111 	writel(1, &de_bld_regs->route);
    112 
    113 	writel(0, &de_bld_regs->premultiply);
    114 	writel(0xff000000, &de_bld_regs->bkcolor);
    115 
    116 	writel(0x03010301, &de_bld_regs->bld_mode[0]);
    117 
    118 	writel(size, &de_bld_regs->output_size);
    119 	writel(mode->flags & DISPLAY_FLAGS_INTERLACED ? 2 : 0,
    120 	       &de_bld_regs->out_ctl);
    121 	writel(0, &de_bld_regs->ck_ctl);
    122 
    123 	writel(0xff000000, &de_bld_regs->attr[0].fcolor);
    124 	writel(size, &de_bld_regs->attr[0].insize);
    125 
    126 	/* Disable all other units */
    127 	writel(0, de_mux_base + SUNXI_DE2_MUX_VSU_REGS);
    128 	writel(0, de_mux_base + SUNXI_DE2_MUX_GSU1_REGS);
    129 	writel(0, de_mux_base + SUNXI_DE2_MUX_GSU2_REGS);
    130 	writel(0, de_mux_base + SUNXI_DE2_MUX_GSU3_REGS);
    131 	writel(0, de_mux_base + SUNXI_DE2_MUX_FCE_REGS);
    132 	writel(0, de_mux_base + SUNXI_DE2_MUX_BWS_REGS);
    133 	writel(0, de_mux_base + SUNXI_DE2_MUX_LTI_REGS);
    134 	writel(0, de_mux_base + SUNXI_DE2_MUX_PEAK_REGS);
    135 	writel(0, de_mux_base + SUNXI_DE2_MUX_ASE_REGS);
    136 	writel(0, de_mux_base + SUNXI_DE2_MUX_FCC_REGS);
    137 
    138 	if (is_composite) {
    139 		/* set CSC coefficients */
    140 		writel(0x107, &de_csc_regs->coef11);
    141 		writel(0x204, &de_csc_regs->coef12);
    142 		writel(0x64, &de_csc_regs->coef13);
    143 		writel(0x4200, &de_csc_regs->coef14);
    144 		writel(0x1f68, &de_csc_regs->coef21);
    145 		writel(0x1ed6, &de_csc_regs->coef22);
    146 		writel(0x1c2, &de_csc_regs->coef23);
    147 		writel(0x20200, &de_csc_regs->coef24);
    148 		writel(0x1c2, &de_csc_regs->coef31);
    149 		writel(0x1e87, &de_csc_regs->coef32);
    150 		writel(0x1fb7, &de_csc_regs->coef33);
    151 		writel(0x20200, &de_csc_regs->coef34);
    152 
    153 		/* enable CSC unit */
    154 		writel(1, &de_csc_regs->csc_ctl);
    155 	} else {
    156 		writel(0, &de_csc_regs->csc_ctl);
    157 	}
    158 
    159 	switch (bpp) {
    160 	case 16:
    161 		format = SUNXI_DE2_UI_CFG_ATTR_FMT(SUNXI_DE2_FORMAT_RGB_565);
    162 		break;
    163 	case 32:
    164 	default:
    165 		format = SUNXI_DE2_UI_CFG_ATTR_FMT(SUNXI_DE2_FORMAT_XRGB_8888);
    166 		break;
    167 	}
    168 
    169 	writel(SUNXI_DE2_UI_CFG_ATTR_EN | format, &de_ui_regs->cfg[0].attr);
    170 	writel(size, &de_ui_regs->cfg[0].size);
    171 	writel(0, &de_ui_regs->cfg[0].coord);
    172 	writel((bpp / 8) * mode->hactive.typ, &de_ui_regs->cfg[0].pitch);
    173 	writel(address, &de_ui_regs->cfg[0].top_laddr);
    174 	writel(size, &de_ui_regs->ovl_size);
    175 
    176 	/* apply settings */
    177 	writel(1, &de_glb_regs->dbuff);
    178 }
    179 
    180 static int sunxi_de2_init(struct udevice *dev, ulong fbbase,
    181 			  enum video_log2_bpp l2bpp,
    182 			  struct udevice *disp, int mux, bool is_composite)
    183 {
    184 	struct video_priv *uc_priv = dev_get_uclass_priv(dev);
    185 	struct display_timing timing;
    186 	struct display_plat *disp_uc_plat;
    187 	int ret;
    188 
    189 	disp_uc_plat = dev_get_uclass_platdata(disp);
    190 	debug("Using device '%s', disp_uc_priv=%p\n", disp->name, disp_uc_plat);
    191 	if (display_in_use(disp)) {
    192 		debug("   - device in use\n");
    193 		return -EBUSY;
    194 	}
    195 
    196 	disp_uc_plat->source_id = mux;
    197 
    198 	ret = device_probe(disp);
    199 	if (ret) {
    200 		debug("%s: device '%s' display won't probe (ret=%d)\n",
    201 		      __func__, dev->name, ret);
    202 		return ret;
    203 	}
    204 
    205 	ret = display_read_timing(disp, &timing);
    206 	if (ret) {
    207 		debug("%s: Failed to read timings\n", __func__);
    208 		return ret;
    209 	}
    210 
    211 	sunxi_de2_composer_init();
    212 	sunxi_de2_mode_set(mux, &timing, 1 << l2bpp, fbbase, is_composite);
    213 
    214 	ret = display_enable(disp, 1 << l2bpp, &timing);
    215 	if (ret) {
    216 		debug("%s: Failed to enable display\n", __func__);
    217 		return ret;
    218 	}
    219 
    220 	uc_priv->xsize = timing.hactive.typ;
    221 	uc_priv->ysize = timing.vactive.typ;
    222 	uc_priv->bpix = l2bpp;
    223 	debug("fb=%lx, size=%d %d\n", fbbase, uc_priv->xsize, uc_priv->ysize);
    224 
    225 #ifdef CONFIG_EFI_LOADER
    226 	efi_add_memory_map(fbbase,
    227 			   ALIGN(timing.hactive.typ * timing.vactive.typ *
    228 			   (1 << l2bpp) / 8, EFI_PAGE_SIZE) >> EFI_PAGE_SHIFT,
    229 			   EFI_RESERVED_MEMORY_TYPE, false);
    230 #endif
    231 
    232 	return 0;
    233 }
    234 
    235 static int sunxi_de2_probe(struct udevice *dev)
    236 {
    237 	struct video_uc_platdata *plat = dev_get_uclass_platdata(dev);
    238 	struct udevice *disp;
    239 	int ret;
    240 
    241 	/* Before relocation we don't need to do anything */
    242 	if (!(gd->flags & GD_FLG_RELOC))
    243 		return 0;
    244 
    245 	ret = uclass_find_device_by_name(UCLASS_DISPLAY,
    246 					 "sunxi_lcd", &disp);
    247 	if (!ret) {
    248 		int mux;
    249 
    250 		mux = 0;
    251 
    252 		ret = sunxi_de2_init(dev, plat->base, VIDEO_BPP32, disp, mux,
    253 				     false);
    254 		if (!ret) {
    255 			video_set_flush_dcache(dev, 1);
    256 			return 0;
    257 		}
    258 	}
    259 
    260 	debug("%s: lcd display not found (ret=%d)\n", __func__, ret);
    261 
    262 	ret = uclass_find_device_by_name(UCLASS_DISPLAY,
    263 					 "sunxi_dw_hdmi", &disp);
    264 	if (!ret) {
    265 		int mux;
    266 		if (IS_ENABLED(CONFIG_MACH_SUNXI_H3_H5))
    267 			mux = 0;
    268 		else
    269 			mux = 1;
    270 
    271 		ret = sunxi_de2_init(dev, plat->base, VIDEO_BPP32, disp, mux,
    272 				     false);
    273 		if (!ret) {
    274 			video_set_flush_dcache(dev, 1);
    275 			return 0;
    276 		}
    277 	}
    278 
    279 	debug("%s: hdmi display not found (ret=%d)\n", __func__, ret);
    280 
    281 	ret = uclass_find_device_by_name(UCLASS_DISPLAY,
    282 					"sunxi_tve", &disp);
    283 	if (ret) {
    284 		debug("%s: tv not found (ret=%d)\n", __func__, ret);
    285 		return ret;
    286 	}
    287 
    288 	ret = sunxi_de2_init(dev, plat->base, VIDEO_BPP32, disp, 1, true);
    289 	if (ret)
    290 		return ret;
    291 
    292 	video_set_flush_dcache(dev, 1);
    293 
    294 	return 0;
    295 }
    296 
    297 static int sunxi_de2_bind(struct udevice *dev)
    298 {
    299 	struct video_uc_platdata *plat = dev_get_uclass_platdata(dev);
    300 
    301 	plat->size = LCD_MAX_WIDTH * LCD_MAX_HEIGHT *
    302 		(1 << LCD_MAX_LOG2_BPP) / 8;
    303 
    304 	return 0;
    305 }
    306 
    307 static const struct video_ops sunxi_de2_ops = {
    308 };
    309 
    310 U_BOOT_DRIVER(sunxi_de2) = {
    311 	.name	= "sunxi_de2",
    312 	.id	= UCLASS_VIDEO,
    313 	.ops	= &sunxi_de2_ops,
    314 	.bind	= sunxi_de2_bind,
    315 	.probe	= sunxi_de2_probe,
    316 	.flags	= DM_FLAG_PRE_RELOC,
    317 };
    318 
    319 U_BOOT_DEVICE(sunxi_de2) = {
    320 	.name = "sunxi_de2"
    321 };
    322 
    323 /*
    324  * Simplefb support.
    325  */
    326 #if defined(CONFIG_OF_BOARD_SETUP) && defined(CONFIG_VIDEO_DT_SIMPLEFB)
    327 int sunxi_simplefb_setup(void *blob)
    328 {
    329 	struct udevice *de2, *hdmi, *lcd;
    330 	struct video_priv *de2_priv;
    331 	struct video_uc_platdata *de2_plat;
    332 	int mux;
    333 	int offset, ret;
    334 	u64 start, size;
    335 	const char *pipeline = NULL;
    336 
    337 	debug("Setting up simplefb\n");
    338 
    339 	if (IS_ENABLED(CONFIG_MACH_SUNXI_H3_H5))
    340 		mux = 0;
    341 	else
    342 		mux = 1;
    343 
    344 	/* Skip simplefb setting if DE2 / HDMI is not present */
    345 	ret = uclass_find_device_by_name(UCLASS_VIDEO,
    346 					 "sunxi_de2", &de2);
    347 	if (ret) {
    348 		debug("DE2 not present\n");
    349 		return 0;
    350 	}
    351 
    352 	ret = uclass_find_device_by_name(UCLASS_DISPLAY,
    353 					 "sunxi_dw_hdmi", &hdmi);
    354 	if (ret) {
    355 		debug("HDMI not present\n");
    356 	} else if (device_active(hdmi)) {
    357 		if (mux == 0)
    358 			pipeline = "mixer0-lcd0-hdmi";
    359 		else
    360 			pipeline = "mixer1-lcd1-hdmi";
    361 	} else {
    362 		debug("HDMI present but not probed\n");
    363 	}
    364 
    365 	ret = uclass_find_device_by_name(UCLASS_DISPLAY,
    366 					 "sunxi_lcd", &lcd);
    367 	if (ret)
    368 		debug("LCD not present\n");
    369 	else if (device_active(lcd))
    370 		pipeline = "mixer0-lcd0";
    371 	else
    372 		debug("LCD present but not probed\n");
    373 
    374 	if (!pipeline) {
    375 		debug("No active display present\n");
    376 		return 0;
    377 	}
    378 
    379 	de2_priv = dev_get_uclass_priv(de2);
    380 	de2_plat = dev_get_uclass_platdata(de2);
    381 
    382 	offset = sunxi_simplefb_fdt_match(blob, pipeline);
    383 	if (offset < 0) {
    384 		eprintf("Cannot setup simplefb: node not found\n");
    385 		return 0; /* Keep older kernels working */
    386 	}
    387 
    388 	start = gd->bd->bi_dram[0].start;
    389 	size = de2_plat->base - start;
    390 	ret = fdt_fixup_memory_banks(blob, &start, &size, 1);
    391 	if (ret) {
    392 		eprintf("Cannot setup simplefb: Error reserving memory\n");
    393 		return ret;
    394 	}
    395 
    396 	ret = fdt_setup_simplefb_node(blob, offset, de2_plat->base,
    397 			de2_priv->xsize, de2_priv->ysize,
    398 			VNBYTES(de2_priv->bpix) * de2_priv->xsize,
    399 			"x8r8g8b8");
    400 	if (ret)
    401 		eprintf("Cannot setup simplefb: Error setting properties\n");
    402 
    403 	return ret;
    404 }
    405 #endif /* CONFIG_OF_BOARD_SETUP && CONFIG_VIDEO_DT_SIMPLEFB */
    406