@ -11,7 +11,9 @@
# include <asm/arch/clock.h>
# include <asm/arch/display.h>
# include <asm/arch/gpio.h>
# include <asm/global_data.h>
# include <asm/gpio.h>
# include <asm/io.h>
# include <errno.h>
# include <fdtdec.h>
@ -34,6 +36,7 @@ struct sunxi_display {
GraphicDevice graphic_device ;
bool enabled ;
enum sunxi_monitor monitor ;
unsigned int depth ;
} sunxi_display ;
/*
@ -435,6 +438,134 @@ static void sunxi_lcdc_enable(void)
setbits_le32 ( & lcdc - > ctrl , SUNXI_LCDC_CTRL_TCON_ENABLE ) ;
}
static void sunxi_lcdc_panel_enable ( void )
{
int pin ;
/*
* Start with backlight disabled to avoid the screen flashing to
* white while the lcd inits .
*/
pin = sunxi_name_to_gpio ( CONFIG_VIDEO_LCD_BL_EN ) ;
if ( pin ! = - 1 ) {
gpio_request ( pin , " lcd_backlight_enable " ) ;
gpio_direction_output ( pin , 0 ) ;
}
pin = sunxi_name_to_gpio ( CONFIG_VIDEO_LCD_BL_PWM ) ;
if ( pin ! = - 1 ) {
gpio_request ( pin , " lcd_backlight_pwm " ) ;
/* backlight pwm is inverted, set to 1 to disable backlight */
gpio_direction_output ( pin , 1 ) ;
}
/* Give the backlight some time to turn off and power up the panel. */
mdelay ( 40 ) ;
pin = sunxi_name_to_gpio ( CONFIG_VIDEO_LCD_POWER ) ;
if ( pin ! = - 1 ) {
gpio_request ( pin , " lcd_power " ) ;
gpio_direction_output ( pin , 1 ) ;
}
}
static void sunxi_lcdc_backlight_enable ( void )
{
int pin ;
/*
* We want to have scanned out at least one frame before enabling the
* backlight to avoid the screen flashing to white when we enable it .
*/
mdelay ( 40 ) ;
pin = sunxi_name_to_gpio ( CONFIG_VIDEO_LCD_BL_EN ) ;
if ( pin ! = - 1 )
gpio_direction_output ( pin , 1 ) ;
pin = sunxi_name_to_gpio ( CONFIG_VIDEO_LCD_BL_PWM ) ;
if ( pin ! = - 1 ) {
/* backlight pwm is inverted, set to 0 to enable backlight */
gpio_direction_output ( pin , 0 ) ;
}
}
static int sunxi_lcdc_get_clk_delay ( const struct ctfb_res_modes * mode )
{
int delay ;
delay = mode - > lower_margin + mode - > vsync_len + mode - > upper_margin - 2 ;
return ( delay > 30 ) ? 30 : delay ;
}
static void sunxi_lcdc_tcon0_mode_set ( const struct ctfb_res_modes * mode )
{
struct sunxi_lcdc_reg * const lcdc =
( struct sunxi_lcdc_reg * ) SUNXI_LCD0_BASE ;
int bp , clk_delay , clk_div , clk_double , pin , total , val ;
for ( pin = SUNXI_GPD ( 0 ) ; pin < = SUNXI_GPD ( 27 ) ; pin + + )
sunxi_gpio_set_cfgpin ( pin , SUNXI_GPD0_LCD0 ) ;
sunxi_lcdc_pll_set ( 0 , mode - > pixclock_khz , & clk_div , & clk_double ) ;
/* Use tcon0 */
clrsetbits_le32 ( & lcdc - > ctrl , SUNXI_LCDC_CTRL_IO_MAP_MASK ,
SUNXI_LCDC_CTRL_IO_MAP_TCON0 ) ;
clk_delay = sunxi_lcdc_get_clk_delay ( mode ) ;
writel ( SUNXI_LCDC_TCON0_CTRL_ENABLE |
SUNXI_LCDC_TCON0_CTRL_CLK_DELAY ( clk_delay ) , & lcdc - > tcon0_ctrl ) ;
writel ( SUNXI_LCDC_TCON0_DCLK_ENABLE |
SUNXI_LCDC_TCON0_DCLK_DIV ( clk_div ) , & lcdc - > tcon0_dclk ) ;
writel ( SUNXI_LCDC_X ( mode - > xres ) | SUNXI_LCDC_Y ( mode - > yres ) ,
& lcdc - > tcon0_timing_active ) ;
bp = mode - > hsync_len + mode - > left_margin ;
total = mode - > xres + mode - > right_margin + bp ;
writel ( SUNXI_LCDC_TCON0_TIMING_H_TOTAL ( total ) |
SUNXI_LCDC_TCON0_TIMING_H_BP ( bp ) , & lcdc - > tcon0_timing_h ) ;
bp = mode - > vsync_len + mode - > upper_margin ;
total = mode - > yres + mode - > lower_margin + bp ;
writel ( SUNXI_LCDC_TCON0_TIMING_V_TOTAL ( total ) |
SUNXI_LCDC_TCON0_TIMING_V_BP ( bp ) , & lcdc - > tcon0_timing_v ) ;
writel ( SUNXI_LCDC_X ( mode - > hsync_len ) | SUNXI_LCDC_Y ( mode - > vsync_len ) ,
& lcdc - > tcon0_timing_sync ) ;
/* We only support hv-sync parallel lcd-s for now */
writel ( 0 , & lcdc - > tcon0_hv_intf ) ;
writel ( 0 , & lcdc - > tcon0_cpu_intf ) ;
if ( sunxi_display . depth = = 18 | | sunxi_display . depth = = 16 ) {
writel ( SUNXI_LCDC_TCON0_FRM_SEED , & lcdc - > tcon0_frm_seed [ 0 ] ) ;
writel ( SUNXI_LCDC_TCON0_FRM_SEED , & lcdc - > tcon0_frm_seed [ 1 ] ) ;
writel ( SUNXI_LCDC_TCON0_FRM_SEED , & lcdc - > tcon0_frm_seed [ 2 ] ) ;
writel ( SUNXI_LCDC_TCON0_FRM_SEED , & lcdc - > tcon0_frm_seed [ 3 ] ) ;
writel ( SUNXI_LCDC_TCON0_FRM_SEED , & lcdc - > tcon0_frm_seed [ 4 ] ) ;
writel ( SUNXI_LCDC_TCON0_FRM_SEED , & lcdc - > tcon0_frm_seed [ 5 ] ) ;
writel ( SUNXI_LCDC_TCON0_FRM_TAB0 , & lcdc - > tcon0_frm_table [ 0 ] ) ;
writel ( SUNXI_LCDC_TCON0_FRM_TAB1 , & lcdc - > tcon0_frm_table [ 1 ] ) ;
writel ( SUNXI_LCDC_TCON0_FRM_TAB2 , & lcdc - > tcon0_frm_table [ 2 ] ) ;
writel ( SUNXI_LCDC_TCON0_FRM_TAB3 , & lcdc - > tcon0_frm_table [ 3 ] ) ;
writel ( ( ( sunxi_display . depth = = 18 ) ?
SUNXI_LCDC_TCON0_FRM_CTRL_RGB666 :
SUNXI_LCDC_TCON0_FRM_CTRL_RGB565 ) ,
& lcdc - > tcon0_frm_ctrl ) ;
}
val = 0 ;
if ( ! ( mode - > sync & FB_SYNC_HOR_HIGH_ACT ) )
val | = SUNXI_LCDC_TCON_HSYNC_MASK ;
if ( ! ( mode - > sync & FB_SYNC_VERT_HIGH_ACT ) )
val | = SUNXI_LCDC_TCON_VSYNC_MASK ;
writel ( val , & lcdc - > tcon0_io_polarity ) ;
writel ( 0 , & lcdc - > tcon0_io_tristate ) ;
}
static void sunxi_lcdc_tcon1_mode_set ( const struct ctfb_res_modes * mode ,
int * clk_div , int * clk_double )
{
@ -618,7 +749,12 @@ static void sunxi_mode_set(const struct ctfb_res_modes *mode,
}
break ;
case sunxi_monitor_lcd :
/* TODO */
sunxi_lcdc_panel_enable ( ) ;
sunxi_composer_mode_set ( mode , address ) ;
sunxi_lcdc_tcon0_mode_set ( mode ) ;
sunxi_composer_enable ( ) ;
sunxi_lcdc_enable ( ) ;
sunxi_lcdc_backlight_enable ( ) ;
break ;
case sunxi_monitor_vga :
break ;
@ -641,11 +777,11 @@ void *video_hw_init(void)
{
static GraphicDevice * graphic_device = & sunxi_display . graphic_device ;
const struct ctfb_res_modes * mode ;
struct ctfb_res_modes edid_mode ;
struct ctfb_res_modes custom ;
const char * options ;
unsigned int depth ;
int i , ret , hpd , edid ;
char mon [ 16 ] ;
char * lcd_mode = CONFIG_VIDEO_LCD_MODE ;
memset ( & sunxi_display , 0 , sizeof ( struct sunxi_display ) ) ;
@ -653,7 +789,8 @@ void *video_hw_init(void)
CONFIG_SUNXI_FB_SIZE > > 10 ) ;
gd - > fb_base = gd - > ram_top ;
video_get_ctfb_res_modes ( RES_MODE_1024x768 , 24 , & mode , & depth , & options ) ;
video_get_ctfb_res_modes ( RES_MODE_1024x768 , 24 , & mode ,
& sunxi_display . depth , & options ) ;
hpd = video_get_option_int ( options , " hpd " , 1 ) ;
edid = video_get_option_int ( options , " edid " , 1 ) ;
sunxi_display . monitor = sunxi_monitor_dvi ;
@ -678,16 +815,26 @@ void *video_hw_init(void)
ret = sunxi_hdmi_hpd_detect ( ) ;
if ( ret ) {
printf ( " HDMI connected: " ) ;
if ( edid & & sunxi_hdmi_edid_get_mode ( & edid_mode ) = = 0 )
mode = & edid_mode ;
if ( edid & & sunxi_hdmi_edid_get_mode ( & custom ) = = 0 )
mode = & custom ;
break ;
}
if ( ! hpd )
break ; /* User has requested to ignore hpd */
sunxi_hdmi_shutdown ( ) ;
return NULL ;
if ( lcd_mode [ 0 ] = = 0 )
return NULL ; /* No LCD, bail */
/* Fall back / through to LCD */
sunxi_display . monitor = sunxi_monitor_lcd ;
case sunxi_monitor_lcd :
if ( lcd_mode [ 0 ] ) {
sunxi_display . depth = video_get_params ( & custom , lcd_mode ) ;
mode = & custom ;
break ;
}
printf ( " LCD not supported on this board \n " ) ;
return NULL ;
case sunxi_monitor_vga :
@ -729,16 +876,31 @@ int sunxi_simplefb_setup(void *blob)
{
static GraphicDevice * graphic_device = & sunxi_display . graphic_device ;
int offset , ret ;
const char * pipeline = NULL ;
if ( ! sunxi_display . enabled )
return 0 ;
/* Find a framebuffer node, with pipeline == "de_be0-lcd0-hdmi" */
switch ( sunxi_display . monitor ) {
case sunxi_monitor_none :
return 0 ;
case sunxi_monitor_dvi :
case sunxi_monitor_hdmi :
pipeline = " de_be0-lcd0-hdmi " ;
break ;
case sunxi_monitor_lcd :
pipeline = " de_be0-lcd0 " ;
break ;
case sunxi_monitor_vga :
break ;
}
/* Find a prefilled simpefb node, matching out pipeline config */
offset = fdt_node_offset_by_compatible ( blob , - 1 ,
" allwinner,simple-framebuffer " ) ;
while ( offset > = 0 ) {
ret = fdt_find_string ( blob , offset , " allwinner,pipeline " ,
" de_be0-lcd0-hdmi " ) ;
pipeline ) ;
if ( ret = = 0 )
break ;
offset = fdt_node_offset_by_compatible ( blob , offset ,