| /* |
| * (C) Copyright 2012 |
| * Marvell Semiconductor <www.marvell.com> |
| * Written-by: Green Wan <gwan@marvell.com> |
| * Jun Nie <njun@marvell.com> |
| * Kevin Liu <kliu5@marvell.com> |
| * |
| * SPDX-License-Identifier: GPL-2.0+ |
| */ |
| |
| #include <config.h> |
| #include <common.h> |
| #include <malloc.h> |
| #include <linux/types.h> |
| #include <asm/io.h> |
| #include <i2c.h> |
| #include <asm/gpio.h> |
| #include <mmp_disp.h> |
| |
| struct mmp_disp_info *mmp_disp_fbi; |
| int g_panel_id; |
| |
| struct lcd_regs *get_regs(struct mmp_disp_info *fbi) |
| { |
| struct lcd_regs *regs = (struct lcd_regs *)((uintptr_t)fbi->reg_base); |
| |
| if (fbi->id == 0) |
| regs = (struct lcd_regs *)((uintptr_t)fbi->reg_base + 0xc0); |
| if (fbi->id == 2) |
| regs = (struct lcd_regs *)((uintptr_t)fbi->reg_base + 0x200); |
| |
| return regs; |
| } |
| |
| u32 dma_ctrl_read(struct mmp_disp_info *fbi, int ctrl1) |
| { |
| u32 reg = (uintptr_t)fbi->reg_base + dma_ctrl(ctrl1, fbi->id); |
| return __raw_readl((uintptr_t)reg); |
| } |
| |
| void dma_ctrl_write(struct mmp_disp_info *fbi, int ctrl1, u32 value) |
| { |
| u32 reg = (u32)(uintptr_t)fbi->reg_base + dma_ctrl(ctrl1, fbi->id); |
| __raw_writel(value, (uintptr_t)reg); |
| } |
| |
| void dma_ctrl_set(struct mmp_disp_info *fbi, int ctrl1, u32 mask, u32 value) |
| { |
| u32 reg = (u32)(uintptr_t)fbi->reg_base + dma_ctrl(ctrl1, fbi->id); |
| u32 tmp1, tmp2; |
| |
| tmp1 = __raw_readl((uintptr_t)reg); |
| tmp2 = tmp1; |
| tmp2 &= ~mask; |
| tmp2 |= value; |
| if (tmp1 != tmp2) |
| __raw_writel(tmp2, (uintptr_t)reg); |
| } |
| |
| static void set_pix_fmt(struct mmp_disp_plat_info *mi, int pix_fmt) |
| { |
| switch (pix_fmt) { |
| case PIX_FMT_RGB565: |
| mi->bits_per_pixel = 16; |
| break; |
| case PIX_FMT_BGR565: |
| mi->bits_per_pixel = 16; |
| break; |
| case PIX_FMT_RGB1555: |
| mi->bits_per_pixel = 16; |
| break; |
| case PIX_FMT_BGR1555: |
| mi->bits_per_pixel = 16; |
| break; |
| case PIX_FMT_RGB888PACK: |
| mi->bits_per_pixel = 24; |
| break; |
| case PIX_FMT_BGR888PACK: |
| mi->bits_per_pixel = 24; |
| break; |
| case PIX_FMT_RGB888UNPACK: |
| mi->bits_per_pixel = 32; |
| break; |
| case PIX_FMT_BGR888UNPACK: |
| mi->bits_per_pixel = 32; |
| break; |
| case PIX_FMT_RGBA888: |
| mi->bits_per_pixel = 32; |
| break; |
| case PIX_FMT_BGRA888: |
| mi->bits_per_pixel = 32; |
| break; |
| } |
| } |
| |
| /* |
| * The hardware clock divider has an integer and a fractional |
| * stage: |
| * |
| * clk2 = clk_in / integer_divider |
| * clk_out = clk2 * (1 - (fractional_divider >> 12)) |
| * |
| * Calculate integer and fractional divider for given clk_in |
| * and clk_out. |
| */ |
| static void set_clock_divider(struct mmp_disp_info *fbi) |
| { |
| struct mmp_disp_plat_info *mi = fbi->mi; |
| struct dsi_info *di = (struct dsi_info *)mi->phy_info; |
| u32 val = mi->sclk_div, reg; |
| |
| /* for lcd controller */ |
| writel(val & (~0xf00), fbi->reg_base + clk_div(fbi->id)); |
| /* for dsi clock */ |
| if (mi->phy_type & (DSI | DSI2DPI)) { |
| if (di->id == 1) { |
| reg = readl(fbi->reg_base + clk_div(0)); |
| reg &= ~0xf00; |
| reg |= val & 0xf00; |
| writel(reg, fbi->reg_base + clk_div(0)); |
| } else if (di->id == 2) { |
| reg = readl(fbi->reg_base + clk_div(1)); |
| reg &= ~0xf00; |
| reg |= val & 0xf00; |
| writel(reg, fbi->reg_base + clk_div(1)); |
| writel(val & (~0xf00), fbi->reg_base + clk_div(2)); |
| } |
| } |
| } |
| |
| static u32 dma_ctrl0_update(int active, struct mmp_disp_plat_info *mi, |
| u32 x, u32 pix_fmt) |
| { |
| int tmp, shift1, shift2; |
| |
| tmp = 0x100; |
| shift1 = 16; |
| shift2 = 12; |
| |
| if (active) |
| x |= tmp; |
| else |
| x &= ~tmp; |
| |
| /* If we are in a pseudo-color mode, we need to enable |
| * palette lookup */ |
| if (pix_fmt == PIX_FMT_PSEUDOCOLOR) |
| x |= 0x10000000; |
| |
| /* Configure hardware pixel format */ |
| x &= ~(0xF << shift1); |
| x |= (pix_fmt >> 1) << shift1; |
| |
| /* Check YUV422PACK */ |
| x &= ~((1 << 9) | (1 << 11) | (1 << 10) | (1 << 12)); |
| if (((pix_fmt >> 1) == 5) || (pix_fmt & 0x1000)) { |
| x |= 1 << 9; |
| x |= (mi->panel_rbswap) << 12; |
| if (pix_fmt == 11) |
| x |= 1 << 11; |
| if (pix_fmt & 0x1000) |
| x |= 1 << 10; |
| } else { |
| /* Check red and blue pixel swap. |
| * 1. source data swap. BGR[M:L] rather than RGB[M:L] is |
| * stored in memeory as source format. |
| * 2. panel output data swap |
| */ |
| x |= (((pix_fmt & 1) ^ 1) ^ (mi->panel_rbswap)) << shift2; |
| } |
| /* enable horizontal smooth filter for both graphic and video layers */ |
| x |= CFG_GRA_HSMOOTH(1) | CFG_DMA_HSMOOTH(1); |
| |
| return x; |
| } |
| |
| static void set_dma_control0(struct mmp_disp_info *fbi) |
| { |
| struct mmp_disp_plat_info *mi; |
| u32 x = 0, active, pix_fmt = fbi->pix_fmt; |
| |
| /* Set bit to enable graphics DMA */ |
| dma_ctrl_set(fbi, 0, CFG_ARBFAST_ENA(1), CFG_ARBFAST_ENA(1)); |
| |
| mi = fbi->mi; |
| active = fbi->active; |
| x = dma_ctrl_read(fbi, 0); |
| active = 1; |
| x = dma_ctrl0_update(active, mi, x, pix_fmt); |
| dma_ctrl_write(fbi, 0, x); |
| /* enable multiple burst request in DMA AXI bus arbiter for |
| * faster read |
| */ |
| x = readl(fbi->reg_base + LCD_SPU_DMA_CTRL0); |
| x |= CFG_ARBFAST_ENA(1); |
| writel(x, fbi->reg_base + LCD_SPU_DMA_CTRL0); |
| } |
| |
| static void set_graphics_start(struct mmp_disp_info *fb, int xoffset, |
| int yoffset) |
| { |
| struct mmp_disp_info *fbi = fb; |
| int pixel_offset; |
| unsigned int phys_addr; |
| static int debugcount; |
| #ifdef CONFIG_VDMA |
| struct mmp_vdma_reg *vdma_reg = (struct mmp_vdma_reg *)fbi->vdma_reg_base; |
| struct mmp_vdma_ch_reg *ch_reg = &vdma_reg->ch0_reg; |
| #else |
| struct lcd_regs *regs = get_regs(fbi); |
| #endif |
| if (debugcount < 10) |
| debugcount++; |
| |
| pixel_offset = (yoffset * ALIGN(fbi->mi->modes->xres, 16)) + xoffset; |
| phys_addr = (unsigned int)fbi->fb_start + |
| (pixel_offset * (fbi->mi->bits_per_pixel >> 3)); |
| |
| |
| #ifdef CONFIG_VDMA |
| /* Set VDMA Source address */ |
| writel(phys_addr, &ch_reg->src_addr); |
| #else |
| writel(phys_addr, ®s->g_0); |
| #endif |
| } |
| |
| static void set_screen(struct mmp_disp_info *fbi, struct mmp_disp_plat_info *mi) |
| { |
| struct lcd_regs *regs = get_regs(fbi); |
| struct dsi_info *di = NULL; |
| u32 x, h_porch, vsync_ctrl, vec = 10; |
| u32 xres = mi->modes->xres, yres = mi->modes->yres; |
| u32 xres_z = mi->modes->xres, yres_z = mi->modes->yres; |
| u32 bits_per_pixel = mi->bits_per_pixel; |
| |
| if (mi->phy_type & (DSI2DPI | DSI)) { |
| di = (struct dsi_info *)mi->phy_info; |
| vec = ((di->lanes <= 2) ? 1 : 2) * 10 * di->bpp / 8 / di->lanes; |
| } |
| /* resolution, active */ |
| writel((mi->modes->yres << 16) | mi->modes->xres, ®s->screen_active); |
| /* pitch, pixels per line */ |
| x = readl(®s->g_pitch); |
| x = (x & ~0xFFFF) | ((ALIGN(xres, 16) * bits_per_pixel) >> 3); |
| writel(x, ®s->g_pitch); |
| /* resolution, src size */ |
| writel((yres << 16) | xres, ®s->g_size); |
| |
| /* resolution, dst size */ |
| if (DISP_GEN4(fbi->mi->version)) { |
| if (xres != xres_z || yres != yres_z) |
| printf("resize not support for graphic layer of GEN4\n"); |
| } else { |
| writel((yres_z << 16) | xres_z, ®s->g_size_z); |
| } |
| |
| /* h porch, left/right margin */ |
| if (mi->phy_type & (DSI2DPI | DSI)) { |
| h_porch = (mi->modes->xres + mi->modes->right_margin) * vec / 10 |
| - mi->modes->xres; |
| h_porch = (mi->modes->left_margin * vec / 10) << 16 | h_porch; |
| } else { |
| h_porch = (mi->modes->left_margin) << 16 | mi->modes->right_margin; |
| } |
| writel(h_porch, ®s->screen_h_porch); |
| /* v porch, upper/lower margin */ |
| writel((mi->modes->upper_margin << 16) | mi->modes->lower_margin, |
| ®s->screen_v_porch); |
| |
| /* vsync ctrl */ |
| if (mi->phy_type & (DSI2DPI | DSI)) { |
| vsync_ctrl = (((mi->modes->xres + mi->modes->right_margin) * vec / 10) << 16) |
| | ((mi->modes->xres + mi->modes->right_margin) * vec / 10); |
| } else { |
| vsync_ctrl = ((mi->modes->xres + mi->modes->right_margin) << 16) |
| | (mi->modes->xres + mi->modes->right_margin); |
| } |
| writel(vsync_ctrl, ®s->vsync_ctrl); /* FIXME */ |
| |
| /* blank color */ |
| writel(0x00000000, ®s->blank_color); |
| } |
| |
| static void set_dumb_panel_control(struct mmp_disp_info *fbi, |
| struct mmp_disp_plat_info *mi) |
| { |
| u32 x; |
| |
| x = readl(fbi->reg_base + intf_ctrl(fbi->id)) & 0x00000001; |
| x |= (fbi->is_blanked ? 0x7 : mi->dumb_mode) << 28; |
| x |= (mi->modes->sync & 2) ? 0 : 0x00000008; |
| x |= (mi->modes->sync & 1) ? 0 : 0x00000004; |
| x |= (mi->modes->sync & 8) ? 0 : 0x00000020; |
| |
| x |= mi->gpio_output_data << 20; |
| x |= mi->gpio_output_mask << 12; |
| x |= mi->panel_rgb_reverse_lanes ? 0x00000080 : 0; |
| x |= mi->invert_composite_blank ? 0x00000040 : 0; |
| x |= mi->invert_pix_val_ena ? 0x00000010 : 0; |
| x |= mi->invert_pixclock ? 0x00000002 : 0; |
| |
| writel(x, fbi->reg_base + intf_ctrl(fbi->id)); /* FIXME */ |
| } |
| |
| static void set_dumb_screen_dimensions(struct mmp_disp_info *fbi, |
| struct mmp_disp_plat_info *mi) |
| { |
| struct lcd_regs *regs = get_regs(fbi); |
| struct dsi_info *di = NULL; |
| int x; |
| int y; |
| int vec = 10; |
| |
| /* FIXME - need to double check (*3) and (*2) */ |
| if (mi->phy_type & (DSI2DPI | DSI)) { |
| di = (struct dsi_info *)mi->phy_info; |
| vec = ((di->lanes <= 2) ? 1 : 2) * 10 * di->bpp / 8 / di->lanes; |
| if (di->master_mode) { |
| if (DISP_GEN4(fbi->mi->version)) |
| writel(timing_master_config_dc4(fbi->id, |
| di->id - 1, di->id - 1), |
| fbi->reg_base + TIMING_MASTER_CONTROL_DC4); |
| else |
| writel(timing_master_config(fbi->id, |
| di->id - 1, di->id - 1), |
| fbi->reg_base + TIMING_MASTER_CONTROL); |
| } |
| } |
| |
| x = mi->modes->xres + mi->modes->right_margin + |
| mi->modes->hsync_len + mi->modes->left_margin; |
| x = x * vec / 10; |
| y = mi->modes->yres + mi->modes->lower_margin + |
| mi->modes->vsync_len + mi->modes->upper_margin; |
| |
| writel((y << 16) | x, ®s->screen_size); |
| } |
| |
| static int mmp_disp_set_par(struct mmp_disp_info *fb, |
| struct mmp_disp_plat_info *mi) |
| { |
| struct mmp_disp_info *fbi = fb; |
| int pix_fmt; |
| u32 x; |
| |
| /* Determine which pixel format we're going to use */ |
| pix_fmt = mi->pix_fmt; /* choose one */ |
| |
| if (pix_fmt < 0) |
| return pix_fmt; |
| fbi->pix_fmt = pix_fmt; |
| |
| set_pix_fmt(mi, pix_fmt); |
| |
| /* Calculate clock divisor. */ |
| set_clock_divider(fbi); |
| |
| /* Configure graphics DMA parameters. |
| * Configure global panel parameters. |
| */ |
| set_screen(fbi, mi); |
| /* Configure dumb panel ctrl regs & timings */ |
| set_dumb_panel_control(fbi, mi); |
| set_dumb_screen_dimensions(fbi, mi); |
| x = readl(fbi->reg_base + intf_ctrl(fbi->id)); |
| if ((x & 1) == 0) |
| writel(x | 1, fbi->reg_base + intf_ctrl(fbi->id)); |
| |
| set_graphics_start(fbi, 0, 0); |
| set_dma_control0(fbi); |
| return 0; |
| } |
| |
| static void mmp_disp_set_default(struct mmp_disp_info *fbi, |
| struct mmp_disp_plat_info *mi) |
| { |
| struct lcd_regs *regs = get_regs(fbi); |
| u32 dma_ctrl1 = 0x20320081; |
| |
| u32 burst_length = (mi->burst_len == 16) ? |
| CFG_CYC_BURST_LEN16 : CFG_CYC_BURST_LEN8; |
| /* Configure default register values */ |
| writel(mi->io_pin_allocation_mode | burst_length, |
| fbi->reg_base + SPU_IOPAD_CONTROL); |
| /* enable 16 cycle burst length to get better formance */ |
| writel(0x00000000, ®s->blank_color); |
| writel(0x00000000, ®s->g_1); |
| writel(0x00000000, ®s->g_start); |
| |
| /* |
| * vsync in LCD internal controller is always positive, |
| * we default configure dma trigger @vsync falling edge, |
| * so that DMA idle time between DMA frame done and |
| * next DMA transfer begin can be as large as possible |
| */ |
| dma_ctrl1 |= CFG_VSYNC_INV_MASK; |
| dma_ctrl_write(fbi, 1, dma_ctrl1); |
| } |
| |
| static void rect_fill(void *addr, int left, int up, int right, |
| int down, int width, unsigned int color, int pix_fmt) |
| { |
| int i, j; |
| for (j = up; j < down; j++) |
| for (i = left; i < right; i++) |
| if (pix_fmt == PIX_FMT_RGB565) |
| *((unsigned short *)addr + j * width + i) = color; |
| else if (pix_fmt == PIX_FMT_RGBA888) |
| *((unsigned int *)addr + j * width + i) = color; |
| } |
| |
| void test_panel(int xres, int yres, int pix_fmt) |
| { |
| int w = xres, h = yres, bpp = 2; |
| int x = w / 8, y = h / 8; |
| int color_blue = 0x1f, color_green = 0x7e0, color_red = 0xf800; |
| |
| printf("panel test: white background, test RGB color\r\n"); |
| |
| if (pix_fmt == PIX_FMT_RGB565) { |
| color_blue = 0x1f; |
| color_green = 0x7e0; |
| color_red = 0xf800; |
| bpp = 2; |
| } else if (pix_fmt == PIX_FMT_RGBA888) { |
| color_blue = 0xff0000ff; |
| color_green = 0xff00ff00; |
| color_red = 0xffff0000; |
| bpp = 4; |
| } |
| |
| memset((void *)DEFAULT_FB_BASE, 0xff, |
| w * h * bpp); |
| udelay(50 * 1000); |
| rect_fill((void *)DEFAULT_FB_BASE, x, y, w - x, |
| h - y, w, color_blue, pix_fmt); |
| udelay(50 * 1000); |
| rect_fill((void *)DEFAULT_FB_BASE, x * 2, y * 2, |
| w - x * 2, h - y * 2, w, color_green, pix_fmt); |
| udelay(50 * 1000); |
| rect_fill((void *)DEFAULT_FB_BASE, x * 3, y * 3, |
| w - x * 3, h - y * 3, w, color_red, pix_fmt); |
| udelay(50 * 1000); |
| |
| flush_cache(DEFAULT_FB_BASE, DEFAULT_FB_SIZE); |
| } |
| |
| #ifdef CONFIG_VDMA |
| static void vdma_enable(struct mmp_disp_info *fbi) |
| { |
| struct lcd_regs *regs = get_regs(fbi); |
| struct mmp_vdma_reg *vdma_reg = |
| (struct mmp_vdma_reg *)(fbi->vdma_reg_base); |
| struct mmp_vdma_ch_reg *ch_reg = &vdma_reg->ch0_reg; |
| u32 pitch, size, src_sz, height; |
| u32 tmp, tmp1, tmp2, mask, set; |
| |
| /* |
| * Select VDMA Channel 0: VMDA1 |
| * LCD_VDMA_SEL_CTRL bit21:20->0 : PN graphic path use VMDA1 |
| * LCD_VDMA_SEL_CTRL bit2:0->0 : VDMA1 map to PN graphic path |
| */ |
| tmp = readl(fbi->reg_base + LCD_VDMA_SEL_CTRL); |
| tmp &= ~((0x3 << 20) | 0x7); |
| writel(tmp, fbi->reg_base + LCD_VDMA_SEL_CTRL); |
| |
| if (!DISP_GEN4(fbi->mi->version)) { |
| /* Select PN Graphic SQU Line Buffer @0x2ac bit27:26 ->0 */ |
| tmp = readl(fbi->reg_base + LCD_SCALING_SQU_CTL_INDEX); |
| tmp &= ~(0x3 << 26); |
| writel(tmp, fbi->reg_base + LCD_SCALING_SQU_CTL_INDEX); |
| } |
| |
| pitch = ((ALIGN(fbi->mi->modes->xres, 16) |
| * fbi->mi->bits_per_pixel) >> 3) & 0xffff; |
| |
| /* |
| * Set source address in SQU of LCD Controller |
| * and destination address in SQU of VDMA |
| */ |
| if (DISP_GEN4(fbi->mi->version)) { |
| writel(0x00000000, ®s->g_squln); |
| writel(0x00000000, &ch_reg->dst_addr); |
| } else { |
| if (pitch * VDMA_SRAM_LINES > 64*1024) { |
| printf("error: requested vdma size exceed 64KB!\n"); |
| hang(); |
| } |
| /* The sram bank size is 64k and use the tail for vdma */ |
| writel(CONFIG_SRAM_BASE + 64 * 1024 - pitch * VDMA_SRAM_LINES, |
| fbi->reg_base + LCD_PN_SQULN_CTRL); |
| writel(CONFIG_SRAM_BASE + 64 * 1024 - pitch * VDMA_SRAM_LINES, |
| &ch_reg->dst_addr); |
| } |
| |
| /* Set and Enable Panel Graphic Path SQU Line Buffers */ |
| tmp2 = readl(fbi->reg_base + LCD_PN_SQULN_CTRL); |
| tmp1 = tmp2; |
| tmp1 &= ~0x3f; |
| tmp1 |= ((VDMA_SRAM_LINES / 2 - 1) << 1) | 0x1; |
| if (tmp1 != tmp2) |
| writel(tmp1, fbi->reg_base + LCD_PN_SQULN_CTRL); |
| |
| height = fbi->mi->modes->yres & 0xffff; |
| src_sz = pitch * height; |
| size = height << 16 | pitch; |
| /* FIXME: set dst and src with the same pitch */ |
| pitch |= pitch << 16; |
| writel(pitch, &ch_reg->pitch); |
| writel(src_sz, &ch_reg->src_size); |
| writel(size, &ch_reg->dst_size); |
| |
| tmp = readl(&ch_reg->ctrl) & (~(0xff << 8)); |
| tmp |= VDMA_SRAM_LINES << 8; |
| writel(tmp, &ch_reg->ctrl); |
| |
| /* Enable VDMA Channel 0 */ |
| if (DISP_GEN4(fbi->mi->version)) { |
| mask = (0x1f << 20) | 0x3; |
| set = (0x10 << 20) | 0x1; |
| /* FIXME: bypass decompression */ |
| tmp = readl((uintptr_t)&vdma_reg->dec_ctrl) | (1 << 31); |
| writel(tmp, &vdma_reg->dec_ctrl); |
| } else { |
| mask = (0x3 << 4) | (0x3 << 6) | 0x3; |
| set = (0x2 << 4) | (0x2 << 6) | 0x1; |
| } |
| tmp2 = readl(&ch_reg->ctrl); |
| tmp1 = tmp2; |
| tmp1 &= ~mask; |
| tmp1 |= set; |
| if (tmp1 != tmp2) |
| writel(tmp1, &ch_reg->ctrl); |
| |
| /*Load All VDMA Path 0 Configure Registers */ |
| tmp = readl(&vdma_reg->main_ctrl) | (1 << 24); |
| writel(tmp, &vdma_reg->main_ctrl); |
| } |
| #endif |
| |
| void *mmp_disp_init(struct mmp_disp_plat_info *mi) |
| { |
| struct mmp_disp_info *fbi = malloc(sizeof(struct mmp_disp_info)); |
| struct dsi_info *di = NULL; |
| #if defined(DEBUG_MMP_DISP) |
| u32 i; |
| #endif |
| int ret = 0; |
| |
| memset(fbi, 0, sizeof(struct mmp_disp_info)); |
| /* Initialize private data */ |
| fbi->panel_rbswap = mi->panel_rbswap; |
| fbi->id = mi->index; |
| mmp_disp_fbi = fbi; |
| fbi->mi = mi; |
| |
| fbi->is_blanked = 0; |
| fbi->debug = 0; |
| fbi->active = mi->active; |
| |
| /* Map LCD controller registers */ |
| fbi->reg_base = (void *)DISPLAY_CONTROLLER_BASE; |
| #ifdef CONFIG_VDMA |
| /* Map VDMA Controller Registers */ |
| fbi->vdma_reg_base = (void *)VDMA_CONTROLLER_BASE; |
| #endif |
| |
| if (mi->phy_type & (DSI2DPI | DSI)) { |
| di = (struct dsi_info *)mi->phy_info; |
| di->regs = DSI1_REG_BASE; /* DSI 1 */ |
| } |
| |
| /* |
| * Allocate framebuffer memory |
| */ |
| fbi->fb_size = DEFAULT_FB_SIZE; |
| fbi->fb_start = (unsigned int *)DEFAULT_FB_BASE; |
| memset(fbi->fb_start, 0x0, fbi->fb_size); |
| |
| /* LCD_TOP_CTRL control reg */ |
| writel(VDMA_ENABLE, fbi->reg_base + LCD_TOP_CTRL); |
| |
| /* Get DISP Subsystem Verison */ |
| fbi->mi->version = readl(fbi->reg_base + LCD_VERSION); |
| |
| /* |
| * Fill in sane defaults |
| */ |
| mmp_disp_set_default(fbi, mi); /* FIXME */ |
| mmp_disp_set_par(fbi, mi); |
| |
| #ifdef CONFIG_VDMA |
| vdma_enable(fbi); |
| #endif |
| /* Load All Configure Registers with Shadow Registers */ |
| if (DISP_GEN4(fbi->mi->version)) |
| writel(1 << 30, fbi->reg_base + LCD_SHADOW_CTRL); |
| |
| if (mi->phy_type & (DSI2DPI | DSI)) { |
| /* phy interface init */ |
| ret = mmp_disp_dsi_init(fbi); |
| if (ret) |
| goto err; |
| } |
| |
| /* dump all lcd and dsi registers for debug purpose */ |
| #if defined(DEBUG_MMP_DISP) |
| printf("lcd regs:\n"); |
| for (i = 0; i < 0x300; i += 4) { |
| if (!(i % 16) && i) |
| printf("\n0x%3x: ", i); |
| printf(" %8x", readl(fbi->reg_base + i)); |
| } |
| if (mi->phy_type & (DSI2DPI | DSI)) { |
| printf("\n dsi regs:"); |
| for (i = 0x0; i < 0x200; i += 4) { |
| if (!(i % 16)) |
| printf("\n0x%3x: ", i); |
| printf(" %8x", readl(di->regs + i)); |
| } |
| } |
| printf("\n"); |
| test_panel(fbi->mi->modes->xres, fbi->mi->modes->yres, fbi->pix_fmt); |
| #endif |
| |
| return (void *)fbi; |
| |
| err: |
| free(fbi); |
| return NULL; |
| } |