📄 s3c2410_sm501.c
字号:
/* sm501_blank * Save the old colormap and video mode. */ disp->var = fbi->fb.var; if (disp->cmap.len) fb_copy_cmap(&fbi->fb.cmap, &disp->cmap, 0); } fbi->currcon = con; disp = fb_display + con; /* * Make sure that our colourmap contains 256 entries. */ fb_alloc_cmap(&fbi->fb.cmap, 256, 0); if (disp->cmap.len) cmap = &disp->cmap; else cmap = fb_default_cmap(1 << disp->var.bits_per_pixel); fb_copy_cmap(cmap, &fbi->fb.cmap, 0); fbi->fb.var = disp->var; fbi->fb.var.activate = FB_ACTIVATE_NOW; sm501_set_var(&fbi->fb.var, con, info); return 0;}static void sm501_blank(int blank, struct fb_info *info){ struct sm501_info *fbi = (struct sm501_info *)info; DPRINTK("sm501_blank: blank=%d info->modename=%s\n", blank, fbi->fb.modename); switch (blank) {case VESA_POWERDOWN:case VESA_VSYNC_SUSPEND:case VESA_HSYNC_SUSPEND: sm501_schedule_task(fbi, C_DISABLE);/* if (sm501_blank_helper) sm501_blank_helper(blank); */ printk("disable pw\n"); //hqj break;case VESA_NO_BLANKING:/* if (sm501_blank_helper) sm501_blank_helper(blank);*/ sm501_schedule_task(fbi, C_ENABLE); }}static int sm501_updatevar(int con, struct fb_info *info){ DPRINTK("entered\n"); return 0;}/** NOTE! The following functions are purely helpers for set_ctrlr_state.* Do not call them directly; set_ctrlr_state does the correct serialisation* to ensure that things happen in the right way 100% of time time.* -- rmk*//** FIXME: move LCD power stuff into sm501_power_up_lcd()* Also, I'm expecting that the backlight stuff should* be handled differently.*/static void sm501_backlight_on(struct sm501_info *fbi){ DPRINTK("backlight on\n");}static void sm501_backlight_off(struct sm501_info *fbi){ DPRINTK("backlight off\n");}static void sm501_power_up_lcd(struct sm501_info *fbi){ DPRINTK("LCD power on\n");}static void sm501_power_down_lcd(struct sm501_info *fbi){ DPRINTK("LCD power off\n");}static void sm501_power_up_chip(struct sm501_info *fbi){ u_long power_mode_ctrl = regRead32(POWER_MODE_CTRL); u_long timeout = 100000; if (FIELD_GET(power_mode_ctrl, POWER_MODE_CTRL, MODE) != POWER_MODE_CTRL_MODE_SLEEP) { // already powered up - remember the current mode and return sm501_last_power_mode = FIELD_GET(power_mode_ctrl, POWER_MODE_CTRL, MODE); return; } power_mode_ctrl = FIELD_VALUE(power_mode_ctrl, POWER_MODE_CTRL, MODE, sm501_last_power_mode); regWrite32(POWER_MODE_CTRL, power_mode_ctrl); while (FIELD_GET(regRead32(POWER_MODE_CTRL), POWER_MODE_CTRL, SLEEP_STATUS) != POWER_MODE_CTRL_SLEEP_STATUS_INACTIVE) { timeout--; if (!timeout) { printk(KERN_WARNING "Silicon Motion 501 wakeup timed out\n"); break; } }}static void sm501_power_down_chip(struct sm501_info *fbi){ u_long power_mode_ctrl = regRead32(POWER_MODE_CTRL); DPRINTK("power off SM501 chip\n"); sm501_last_power_mode = FIELD_GET(power_mode_ctrl, POWER_MODE_CTRL, MODE); power_mode_ctrl = FIELD_SET(power_mode_ctrl, POWER_MODE_CTRL, MODE, SLEEP); regWrite32(POWER_MODE_CTRL, power_mode_ctrl);}static void sm501_enable_controller(struct sm501_info *fbi){ if (fbi->fb_type & SM501_PANEL) { u_long panel_ctrl = regRead32(PANEL_DISPLAY_CTRL); DPRINTK("Enabling LCD controller\n"); panel_ctrl = FIELD_SET(panel_ctrl, PANEL_DISPLAY_CTRL, PLANE, ENABLE); regWrite32(PANEL_DISPLAY_CTRL, panel_ctrl); } if (fbi->fb_type & (SM501_CRT | SM501_DUPLICATE)) { u_long panel_ctrl = regRead32(CRT_DISPLAY_CTRL); DPRINTK("Enabling CRT controller\n"); panel_ctrl = FIELD_SET(panel_ctrl, CRT_DISPLAY_CTRL, PLANE, ENABLE); panel_ctrl = FIELD_SET(panel_ctrl, CRT_DISPLAY_CTRL, BLANK, OFF); panel_ctrl = FIELD_SET(panel_ctrl, CRT_DISPLAY_CTRL, SELECT, PANEL); //hqj regWrite32(CRT_DISPLAY_CTRL, panel_ctrl); }}static void sm501_disable_controller(struct sm501_info *fbi){ u_long panel_ctrl = 0; DECLARE_WAITQUEUE(wait, current); add_wait_queue(&fbi->ctrlr_wait, &wait); set_current_state(TASK_UNINTERRUPTIBLE); if (fbi->fb_type & SM501_PANEL) { DPRINTK("Disabling LCD controller\n"); panel_ctrl = regRead32(PANEL_DISPLAY_CTRL); panel_ctrl = FIELD_SET(panel_ctrl, PANEL_DISPLAY_CTRL, PLANE, DISABLE); regWrite32(PANEL_DISPLAY_CTRL, panel_ctrl); } if (fbi->fb_type & (SM501_CRT | SM501_DUPLICATE)) { DPRINTK("Disabling CRT controller\n"); panel_ctrl = regRead32(CRT_DISPLAY_CTRL); panel_ctrl = FIELD_SET(panel_ctrl, CRT_DISPLAY_CTRL, PLANE, DISABLE); panel_ctrl = FIELD_SET(panel_ctrl, CRT_DISPLAY_CTRL, BLANK, ON); regWrite32(CRT_DISPLAY_CTRL, panel_ctrl); } schedule_timeout(20 * HZ / 1000); current->state = TASK_RUNNING; remove_wait_queue(&fbi->ctrlr_wait, &wait);}/** This function must be called from task context only, since it will* sleep when disabling the LCD controller, or if we get two contending* processes trying to alter state.*/static void set_ctrlr_state(struct sm501_info *fbi, u_int state){ u_int old_state; down(&fbi->ctrlr_sem); old_state = fbi->state; switch (state) {case C_DISABLE: /* * Disable controller */ if (old_state != C_DISABLE) { fbi->state = state; if (fbi->fb_type & SM501_PANEL) { sm501_backlight_off(fbi); } sm501_disable_controller(fbi); if (fbi->fb_type & SM501_PANEL) { sm501_power_down_lcd(fbi); } } break;case C_REENABLE: /* * Re-enable the controller only if it was already * enabled. This is so we reprogram the control * registers. */ if (old_state == C_ENABLE) { sm501_disable_controller(fbi); sm501_enable_controller(fbi); } break;case C_ENABLE: /* * Power up the LCD screen, enable controller, and * turn on the backlight. */ if (old_state != C_ENABLE) { fbi->state = C_ENABLE; if (fbi->fb_type & SM501_PANEL) { sm501_power_up_lcd(fbi); } sm501_enable_controller(fbi); if (fbi->fb_type & SM501_PANEL) { sm501_backlight_on(fbi); } } break; } up(&fbi->ctrlr_sem);}/** Our LCD controller task (which is called when we blank or unblank)* via keventd.*/static void sm501_task(void *dummy){ struct sm501_info *fbi = dummy; u_int state = xchg(&fbi->task_state, -1); set_ctrlr_state(fbi, state);}#ifdef CONFIG_PM/** Power management hook. Note that we won't be called from IRQ context,* unlike the blank functions above, so we may sleep.*/static intsm501_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data){ struct sm501_info *fbi = pm_dev->data; DPRINTK("pm_callback: %d\n", req); if (req == PM_SUSPEND || req == PM_RESUME) { int state = (int)data; if (state == 0) { /* Enter D0. */ set_ctrlr_state(fbi, C_ENABLE); } else { /* Enter D1-D3. Disable the LCD controller. */ set_ctrlr_state(fbi, C_DISABLE); } } DPRINTK("done\n"); return 0;}#endifstatic int __init sm501_map_video_memory(struct sm501_info *fbi, int detect){ u_long fb_address; fbi->palette_size = 256; if (detect & SM501_PANEL) { fb_address = FIELD_GET(regRead32(PANEL_FB_ADDRESS), PANEL_FB_ADDRESS, ADDRESS); fbi->palette = (u32 *)(sm501Reg + PANEL_PALETTE_RAM); } else { fb_address = FIELD_GET(regRead32(CRT_FB_ADDRESS), CRT_FB_ADDRESS, ADDRESS); fbi->palette = (u32 *)(sm501Reg + CRT_PALETTE_RAM); } /* virtual address */ DPRINTK("fb address: %#lx\n", fb_address); fbi->fb_virt = fb_address + sm501Mem; /* physical address */ fbi->fb.fix.smem_start = fb_address + pSM501_BASE; return 0;}/* Fake monspecs to fill in fbinfo structure */static struct fb_monspecs monspecs __initdata = { 30000, 70000, 50, 65, 0 /* Generic */};static struct sm501_mach_info * __init sm501_get_panel_info(void){ static struct sm501_mach_info info; int bpp_bits, bpp_data, bpp_lookup[] = {8, 16, 32, -1}; int i; int clock, clock_lookup[] = {366000000, 288000000, 240000000, 192000000}; int divider, divider_lookup[] = {1, 3, 5, -1}; int shift; bpp_bits = FIELD_GET(regRead32(PANEL_DISPLAY_CTRL), PANEL_DISPLAY_CTRL, FORMAT); bpp_data = bpp_lookup[bpp_bits]; if (bpp_data == -1) { printk("Invalid value for bpp. PANEL_DISPLAY_CTRL: %#lx, BPP index: %#x\n", regRead32(PANEL_DISPLAY_CTRL), bpp_bits); return NULL; } info.bpp = bpp_data; //printk("sm501_get_panel_info CURRENT_POWER_CLOCK=%x\n",regRead32(CURRENT_POWER_CLOCK)); // This yeilds a pixclock from the PCD value. i = FIELD_GET(regRead32(CURRENT_POWER_CLOCK), CURRENT_POWER_CLOCK, P2XCLK_SELECT); if (i == CURRENT_POWER_CLOCK_P2XCLK_SELECT_288) { clock = 288000000; //printk("sm501_get_panel_info P2XCLK_SELECT= CURRENT_POWER_CLOCK_P2XCLK_SELECT_288\n"); } else { i = FIELD_GET(regRead32(SYSTEM_DRAM_CTRL), SYSTEM_DRAM_CTRL, DIVIDER); clock = clock_lookup[i]; // printk("sm501_get_panel_info P2XCLK_SELECT!= CURRENT_POWER_CLOCK_P2XCLK_SELECT_288\n"); } i = FIELD_GET(regRead32(CURRENT_POWER_CLOCK), CURRENT_POWER_CLOCK, P2XCLK_DIVIDER); divider = divider_lookup[i]; if (divider == -1) { //printk("Invalid value for panel clock divider. CURRENT_POWER_CLOCK: %#lx, divider index: %#x\n", //regRead32(CURRENT_POWER_CLOCK), i); return NULL; } shift = FIELD_GET(regRead32(CURRENT_POWER_CLOCK), CURRENT_POWER_CLOCK, P2XCLK_SHIFT); DPRINTK("clock: %d, divider: %d, shift: %d\n", clock, divider, shift); info.pixclock = (clock / divider) >> shift; info.xres = FIELD_GET(regRead32(PANEL_PLANE_BR), PANEL_PLANE_BR, RIGHT) - FIELD_GET(regRead32(PANEL_PLANE_TL), PANEL_PLANE_TL, LEFT) + 1; info.yres = FIELD_GET(regRead32(PANEL_PLANE_BR), PANEL_PLANE_BR, BOTTOM) - FIELD_GET(regRead32(PANEL_PLANE_TL), PANEL_PLANE_TL, TOP) + 1; info.hsync_len = FIELD_GET(regRead32(PANEL_HORIZONTAL_SYNC), PANEL_HORIZONTAL_SYNC, WIDTH); info.left_margin = FIELD_GET(regRead32(PANEL_PLANE_TL), PANEL_PLANE_TL, LEFT); info.right_margin = FIELD_GET(regRead32(PANEL_PLANE_BR), PANEL_PLANE_BR, RIGHT); info.vsync_len = FIELD_GET(regRead32(PANEL_VERTICAL_SYNC), PANEL_VERTICAL_SYNC, HEIGHT); info.upper_margin = FIELD_GET(regRead32(PANEL_PLANE_TL), PANEL_PLANE_TL, TOP); info.lower_margin = FIELD_GET(regRead32(PANEL_PLANE_BR), PANEL_PLANE_BR, BOTTOM); info.sync = 0; i = FIELD_GET(regRead32(PANEL_DISPLAY_CTRL), PANEL_DISPLAY_CTRL, VSYNC_PHASE); if (i == PANEL_DISPLAY_CTRL_VSYNC_PHASE_ACTIVE_HIGH) info.sync |= FB_SYNC_HOR_HIGH_ACT; i = FIELD_GET(regRead32(PANEL_DISPLAY_CTRL), PANEL_DISPLAY_CTRL, HSYNC_PHASE); if (i == PANEL_DISPLAY_CTRL_HSYNC_PHASE_ACTIVE_HIGH) info.sync |= FB_SYNC_VERT_HIGH_ACT; //#if DEBUG /* printk("PANEL:\n"); printk("pixclock: %ld\n", info.pixclock); printk("bpp : %d\n", info.bpp); printk("xres : %d\n", info.xres); printk("yres : %d\n", info.yres); printk("hsync : %d\n", info.hsync_len); printk("vsync : %d\n", info.vsync_len); printk("left : %d\n", info.left_margin); printk("upper : %d\n", info.upper_margin); printk("right : %d\n", info.right_margin); printk("lower : %d\n", info.lower_margin); printk("sync : %d\n", info.sync); printk("\n"); printk("CRT_HORIZONTAL_TOTAL=%#lx\n",regRead32(MISC_CTRL)); printk("DRAM_CTRL=%#lx\n",regRead32(DRAM_CTRL)); printk("ARBITRATION_CTRL=%#lx\n",regRead32(ARBITRATION_CTRL)); printk("POWER_MODE1_GATE=%#lx\n",regRead32(POWER_MODE1_GATE)); printk("POWER_MODE0_CLOCK=%#lx\n",regRead32(POWER_MODE0_CLOCK)); printk("POWER_MODE1_CLOCK=%#lx\n",regRead32(POWER_MODE1_CLOCK)); printk("POWER_MODE_CTRL=%#lx\n",regRead32(POWER_MODE_CTRL)); printk("ENDIAN_CTRL=%#lx\n",regRead32(ENDIAN_CTRL)); printk("SYSTEM_DRAM_CTRL=%#lx\n",regRead32(SYSTEM_DRAM_CTRL)); printk("PANEL_DISPLAY_CTRL=%#lx\n",regRead32(PANEL_DISPLAY_CTRL)); printk("PANEL_PAN_CTRL=%#lx\n",regRead32(PANEL_PAN_CTRL)); printk("PANEL_COLOR_KEY=%#lx\n",regRead32(PANEL_COLOR_KEY)); printk("PANEL_FB_ADDRESS=%#lx\n",regRead32(PANEL_FB_ADDRESS)); printk("PANEL_FB_WIDTH=%#lx\n",regRead32(PANEL_FB_WIDTH)); printk("PANEL_WINDOW_WIDTH=%#lx\n",regRead32(PANEL_WINDOW_WIDTH)); printk("PANEL_WINDOW_HEIGHT=%#lx\n",regRead32(PANEL_WINDOW_HEIGHT)); printk("PANEL_PLANE_TL=%#lx\n",regRead32(PANEL_PLANE_TL)); printk("PANEL_PLANE_BR=%#lx\n",regRead32(PANEL_PLANE_BR)); printk("PANEL_HORIZONTAL_TOTAL=%#lx\n",regRead32(PANEL_HORIZONTAL_TOTAL)); printk("PANEL_HORIZONTAL_SYNC=%#lx\n",regRead32(PANEL_HORIZONTAL_SYNC)); printk("PANEL_VERTICAL_TOTAL=%#lx\n",regRead32(PANEL_VERTICAL_TOTAL)); printk("PANEL_VERTICAL_SYNC=%#lx\n",regRead32(PANEL_VERTICAL_SYNC)); printk("CRT_DISPLAY_CTRL=%#lx\n",regRead32(CRT_DISPLAY_CTRL)); printk("CRT_FB_ADDRESS=%#lx\n",regRead32(CRT_FB_ADDRESS)); printk("CRT_FB_WIDTH=%#lx\n",regRead32(CRT_FB_WIDTH)); printk("CRT_HORIZONTAL_TOTAL=%#lx\n",regRead32(CRT_HORIZONTAL_TOTAL)); printk("CRT_HORIZONTAL_SYNC=%#lx\n",regRead32(CRT_HORIZONTAL_SYNC)); printk("CRT_VERTICAL_TOTAL=%#lx\n",regRead32(CRT_VERTICAL_TOTAL)); printk("CRT_VERTICAL_SYNC=%#lx\n",regRead32(CRT_VERTICAL_SYNC)); printk("\n");*/ //#endif return &info;}static struct sm501_mach_info * __init sm501_get_crt_info(void){ static struct sm501_mach_info info; int bpp_bits, bpp_data, bpp_lookup[] = {8, 16, 32, -1}; int i; int clock, clock_lookup[] = {366000000, 288000000, 240000000, 192000000}; int divider, divider_lookup[] = {1, 3, -1, -1}; int shift; bpp_bits = FIELD_GET(regRead32(CRT_DISPLAY_CTRL), CRT_DISPLAY_CTRL, FORMAT); bpp_data = bpp_lookup[bpp_bits]; if (bpp_data == -1) { printk("Invalid value for bpp. CRT_DISPLAY_CTRL: %#lx, BPP index: %#x\n", regRead32(CRT_DISPLAY_CTRL), bpp_bits); return NULL; } info.bpp = bpp_data; // This yeilds a pixclock from the PCD value. i = FIELD_GET(regRead32(CURRENT_POWER_CLOCK), CURRENT_POWER_CLOCK, P2XCLK_SELECT); if (i == CURRENT_POWER_CLOCK_P2XCLK_SELECT_288) { printk(" CURRENT_POWER_CLOCK_P2XCLK_SELECT_288\n"); clock = 288000000;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -