# HG changeset patch # User Paul Boddie # Date 1499613240 -7200 # Node ID 2b8d17cf5a881ae745831d5902b5dc5549c81170 # Parent 1871eb0ee98c257d6a965ec807bc22000306377e Moved initialisation details to the generic LCD module, changing the address computation functions to use information from the display structure. Moved clock and power management operations into the generic LCD module, thus focusing the jz4740 LCD module on specific LCD-related functionality. diff -r 1871eb0ee98c -r 2b8d17cf5a88 stage2/jzlcd.c --- a/stage2/jzlcd.c Sun Jul 09 16:48:29 2017 +0200 +++ b/stage2/jzlcd.c Sun Jul 09 17:14:00 2017 +0200 @@ -22,7 +22,6 @@ #include "sdram.h" #include "jzlcd.h" -#include "cpu.h" #include "board.h" extern vidinfo_t panel_info; @@ -114,6 +113,7 @@ static uint32_t lcd_get_size(vidinfo_t *vid) { /* Lines must be aligned to a word boundary. */ + uint32_t line_length = ALIGN((vid->jz_fb->w * vid->jz_fb->bpp) / 8, sizeof(uint32_t)); return line_length * vid->jz_fb->h; } @@ -121,12 +121,14 @@ static uint32_t lcd_get_aligned_size(vidinfo_t *vid) { /* LCD_CTRL_BST_16 requires 16-word alignment. */ + return ALIGN(lcd_get_size(vid), 16 * sizeof(uint32_t)); } static uint32_t lcd_get_min_size(vidinfo_t *vid) { /* Lines must be aligned to a word boundary. */ + uint32_t line_length = ALIGN((vid->jz_fb->w * 32) / 8, sizeof(uint32_t)); return line_length * vid->jz_fb->h; } @@ -134,6 +136,7 @@ static uint32_t lcd_get_aligned_min_size(vidinfo_t *vid) { /* LCD_CTRL_BST_16 requires 16-word alignment. */ + return ALIGN(lcd_get_min_size(vid), 16 * sizeof(uint32_t)); } @@ -158,15 +161,6 @@ return 3 * sizeof(struct jz_fb_dma_descriptor); } -static uint32_t lcd_get_total_size(vidinfo_t *vid) -{ - uint32_t size = lcd_get_aligned_size(vid) * lcd_get_panels(vid); - uint32_t min_size = lcd_get_aligned_min_size(vid); - - /* Round up to nearest full page, or MMU section if defined. */ - return ALIGN((size >= min_size ? size : min_size) + lcd_get_aligned_palette_size(vid) + lcd_get_descriptors_size(), PAGE_SIZE); -} - /* Functions returning addresses of each data region. */ @@ -175,7 +169,7 @@ { /* Use memory at the end of the allocated region for the palette. */ - return get_memory_size() - lcd_get_aligned_palette_size(vid); + return vid->jz_mem.screen + vid->jz_mem.total - lcd_get_aligned_palette_size(vid); } static uint32_t lcd_get_descriptors(vidinfo_t *vid) @@ -185,11 +179,11 @@ return lcd_get_palette(vid) - lcd_get_descriptors_size(); } -static uint32_t lcd_get_framebuffer(uint16_t panel, vidinfo_t *vid) +static uint32_t lcd_get_framebuffer(uint8_t panel, vidinfo_t *vid) { /* Framebuffers for panels are allocated at the start of the region. */ - return get_memory_size() - lcd_get_total_size(vid) + (panel * lcd_get_aligned_size(vid)); + return vid->jz_mem.screen + (panel * lcd_get_aligned_size(vid)); } @@ -359,60 +353,49 @@ -static void jz_lcd_set_timing(vidinfo_t *vid) -{ - uint32_t pclk = lcd_get_pixel_clock(vid); - uint32_t val; +/* Public functions. */ + +/* Return the total size of the required memory. */ -#ifdef CONFIG_CPU_JZ4730 - val = __cpm_get_pllout() / pclk; - REG_CPM_CFCR2 = val - 1; - val = pclk * 4 ; - if ( val > 150000000 ) { - val = 150000000; - } - val = __cpm_get_pllout() / val; - val--; - if ( val > 0xF ) - val = 0xF; -#else - int pll_div; +uint32_t jz4740_lcd_get_total_size(vidinfo_t *vid) +{ + uint32_t size = lcd_get_aligned_size(vid) * lcd_get_panels(vid); + uint32_t min_size = lcd_get_aligned_min_size(vid); + + /* Round up to nearest full page, or MMU section if defined. */ - pll_div = REG_CPM_CPCCR & CPM_CPCCR_PCS; /* clock source,0:pllout/2 1: pllout */ - pll_div = pll_div ? 1 : 2 ; - val = ( __cpm_get_pllout()/pll_div ) / pclk; - val--; - if ( val > 0x1ff ) { - val = 0x1ff; - } - __cpm_set_pixdiv(val); + return ALIGN((size >= min_size ? size : min_size) + + lcd_get_aligned_palette_size(vid) + lcd_get_descriptors_size(), + PAGE_SIZE); +} - val = pclk * 3 ; /* LCDClock > 2.5*Pixclock */ - if ( val > 150000000 ) { - val = 150000000; - } - val = ( __cpm_get_pllout()/pll_div ) / val; - val--; - if ( val > 0x1f ) { - val = 0x1f; - } -#endif - __cpm_set_ldiv( val ); - REG_CPM_CPCCR = REG_CPM_CPCCR | CPM_CPCCR_CE; /* update divide */ +/* Return the calculated pixel clock frequency for the display. */ + +uint32_t jz4740_lcd_get_pixel_clock(vidinfo_t *vid) +{ + return lcd_get_pixel_clock(vid); } /* Initialise the LCD controller with the memory, panel and framebuffer details. Return the pixel clock frequency. */ -static void jz_lcd_ctrl_init(void *lcd_base, void *fb_vaddr, vidinfo_t *vid) +void jz4740_lcd_ctrl_init(void *lcd_base, void *fb_vaddr, vidinfo_t *vid) { struct jz_mem_info *fbi = &vid->jz_mem; - struct jz_fb_dma_descriptor *descriptors = (struct jz_fb_dma_descriptor *) lcd_get_descriptors(vid); + struct jz_fb_dma_descriptor *descriptors; /* Set the LCD controller address. */ vid->lcd = lcd_base; + /* Initialise the total region size. */ + + fbi->total = jz4740_lcd_get_total_size(vid); + + /* Obtain a reference to the descriptors. */ + + descriptors = (struct jz_fb_dma_descriptor *) lcd_get_descriptors(vid); + /* Position framebuffer regions at the given address. */ fbi->screen = (uint32_t) fb_vaddr; @@ -484,7 +467,7 @@ /* Initialise the LCD registers. */ -static void jz_lcd_hw_init(vidinfo_t *vid) +void jz4740_lcd_hw_init(vidinfo_t *vid) { struct jzfb_info *jzfb = vid->jz_fb; uint32_t val = 0; @@ -564,17 +547,9 @@ lcd_ctrl_set(vid, LCD_CFG, jzfb->cfg); } -static void jz_lcd_timing_init(vidinfo_t *vid) -{ - __cpm_stop_lcd(); - jz_lcd_set_timing(vid); - __cpm_start_lcd(); - udelay(1000); -} - /* Initialise DMA for the driver. */ -static void jz_lcd_dma_init(vidinfo_t *vid) +void jz4740_lcd_dma_init(vidinfo_t *vid) { struct jz_mem_info *fbi = &vid->jz_mem; uint32_t mode = vid->jz_fb->cfg & MODE_MASK; @@ -621,22 +596,3 @@ lcd_ctrl_set(vid, LCD_CTRL, lcd_ctrl_get(vid, LCD_CTRL) & ~LCD_CTRL_ENA); } - -uint32_t lcd_ctrl_init() -{ - vidinfo_t *vid = &panel_info; - struct jz_mem_info *fbi = &vid->jz_mem; - void *fb_vaddr; - - /* Start from the top of memory and obtain the framebuffer region. */ - - fb_vaddr = (void *) lcd_get_framebuffer(0, vid); - - jz_lcd_ctrl_init((void *) LCD_BASE_KSEG1, fb_vaddr, vid); - flush_cache_all(); - jz_lcd_hw_init(vid); - jz_lcd_timing_init(vid); - jz_lcd_dma_init(vid); - - return fbi->screen; -} diff -r 1871eb0ee98c -r 2b8d17cf5a88 stage2/jzlcd.h --- a/stage2/jzlcd.h Sun Jul 09 16:48:29 2017 +0200 +++ b/stage2/jzlcd.h Sun Jul 09 17:14:00 2017 +0200 @@ -27,11 +27,6 @@ #include -void lcd_set_bpp(uint8_t bpp); -uint32_t lcd_ctrl_init(); -void lcd_enable(); -void lcd_disable(); - /* Framebuffer characteristics. */ struct jzfb_info { @@ -85,6 +80,18 @@ void *lcd; /* address of LCD controller registers */ } vidinfo_t; +/* Public functions. */ + +uint32_t jz4740_lcd_get_total_size(vidinfo_t *vid); +uint32_t jz4740_lcd_get_pixel_clock(vidinfo_t *vid); +void jz4740_lcd_ctrl_init(void *lcd_base, void *fb_vaddr, vidinfo_t *vid); +void jz4740_lcd_hw_init(vidinfo_t *vid); +void jz4740_lcd_dma_init(vidinfo_t *vid); +void lcd_set_bpp(uint8_t bpp); +uint32_t lcd_ctrl_init(); +void lcd_enable(); +void lcd_disable(); + /* Alignment/rounding macros. */ #define ALIGN(x,a) __ALIGN_MASK((x),(typeof(x))(a)-1) diff -r 1871eb0ee98c -r 2b8d17cf5a88 stage2/lcd.c --- a/stage2/lcd.c Sun Jul 09 16:48:29 2017 +0200 +++ b/stage2/lcd.c Sun Jul 09 17:14:00 2017 +0200 @@ -22,11 +22,14 @@ #include "jzlcd.h" #include "sdram.h" +#include "cpu.h" #include "board.h" extern vidinfo_t panel_info; static uint32_t lcd_base; + + static uint16_t get_line_length() { return ALIGN((panel_info.jz_fb->w * panel_info.jz_fb->bpp) / 8, sizeof(uint32_t)); @@ -254,8 +257,101 @@ } } + + /* LCD initialisation. */ +#ifdef CONFIG_CPU_JZ4730 +void jz4730_set_lcd_frequencies(uint32_t pclk, uint8_t ratio) +{ + uint32_t val; + + val = __cpm_get_pllout() / pclk; + REG_CPM_CFCR2 = val - 1; + val = pclk * ratio; + + if (val > 150000000) { + val = 150000000; + } + + val = __cpm_get_pllout() / val; + val--; + + if (val > 0xF) + val = 0xF; + + __cpm_set_ldiv(val); + REG_CPM_CPCCR = REG_CPM_CPCCR | CPM_CPCCR_CE; /* update divide */ +} +#else +void jz4740_set_lcd_frequencies(uint32_t pclk, uint8_t ratio) +{ + uint32_t val; + int pll_div; + + pll_div = REG_CPM_CPCCR & CPM_CPCCR_PCS; /* clock source,0:pllout/2 1: pllout */ + pll_div = pll_div ? 1 : 2; + val = (__cpm_get_pllout() / pll_div) / pclk; + val--; + + if ( val > 0x1ff ) { + val = 0x1ff; + } + + __cpm_set_pixdiv(val); + + val = pclk * ratio; /* LCDClock > 2.5*Pixclock */ + + if ( val > 150000000 ) { + val = 150000000; + } + + val = (__cpm_get_pllout() / pll_div) / val; + val--; + + if (val > 0x1f) + val = 0x1f; + + __cpm_set_ldiv(val); + REG_CPM_CPCCR = REG_CPM_CPCCR | CPM_CPCCR_CE; /* update divide */ +} +#endif + +void lcd_set_timing(vidinfo_t *vid) +{ + uint32_t pclk = jz4740_lcd_get_pixel_clock(vid); + + __cpm_stop_lcd(); + +#ifdef CONFIG_CPU_JZ4730 + jz4730_set_lcd_frequencies(pclk, 4); +#else + jz4740_set_lcd_frequencies(pclk, 3); +#endif + + __cpm_start_lcd(); + udelay(1000); +} + +uint32_t lcd_ctrl_init() +{ + vidinfo_t *vid = &panel_info; + struct jz_mem_info *fbi = &vid->jz_mem; + void *fb_vaddr; + + /* Start from the top of memory and obtain the framebuffer region. */ + + fb_vaddr = (void *) (get_memory_size() - jz4740_lcd_get_total_size(vid)); + + jz4740_lcd_ctrl_init((void *) LCD_BASE_KSEG1, fb_vaddr, vid); + flush_cache_all(); + jz4740_lcd_hw_init(vid); + lcd_set_timing(vid); + jz4740_lcd_dma_init(vid); + + return fbi->screen; +} + void lcd_init() { __lcd_display_pin_init();