Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

lxfb: GEODE: Add framebuffer support for the AMD Geode LX

Add framebuffer support for the AMD Geode LX graphics engine.

Signed-off-by: Jordan Crouse <jordan.crouse@amd.com>
Signed-off-by: Antonino Daplas <adaplas@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Jordan Crouse and committed by
Linus Torvalds
3968cb49 c8facbb6

+1373
+15
drivers/video/geode/Kconfig
··· 8 8 Say 'Y' here to allow you to select framebuffer drivers for 9 9 the AMD Geode family of processors. 10 10 11 + config FB_GEODE_LX 12 + tristate "AMD Geode LX framebuffer support (EXPERIMENTAL)" 13 + depends on FB && FB_GEODE 14 + select FB_CFB_FILLRECT 15 + select FB_CFB_COPYAREA 16 + select FB_CFB_IMAGEBLIT 17 + ---help--- 18 + Framebuffer driver for the display controller integrated into the 19 + AMD Geode LX processors. 20 + 21 + To compile this driver as a module, choose M here: the module will 22 + be called lxfb. 23 + 24 + If unsure, say N. 25 + 11 26 config FB_GEODE_GX 12 27 tristate "AMD Geode GX framebuffer support (EXPERIMENTAL)" 13 28 depends on FB && FB_GEODE && EXPERIMENTAL
+2
drivers/video/geode/Makefile
··· 2 2 3 3 obj-$(CONFIG_FB_GEODE_GX1) += gx1fb.o 4 4 obj-$(CONFIG_FB_GEODE_GX) += gxfb.o 5 + obj-$(CONFIG_FB_GEODE_LX) += lxfb.o 5 6 6 7 gx1fb-objs := gx1fb_core.o display_gx1.o video_cs5530.o 7 8 gxfb-objs := gxfb_core.o display_gx.o video_gx.o 9 + lxfb-objs := lxfb_core.o lxfb_ops.o
+199
drivers/video/geode/lxfb.h
··· 1 + #ifndef _LXFB_H_ 2 + #define _LXFB_H_ 3 + 4 + #include <linux/fb.h> 5 + 6 + #define OUTPUT_CRT 0x01 7 + #define OUTPUT_PANEL 0x02 8 + 9 + struct lxfb_par { 10 + int output; 11 + int panel_width; 12 + int panel_height; 13 + 14 + void __iomem *gp_regs; 15 + void __iomem *dc_regs; 16 + void __iomem *df_regs; 17 + }; 18 + 19 + static inline unsigned int lx_get_pitch(unsigned int xres, int bpp) 20 + { 21 + return (((xres * (bpp >> 3)) + 7) & ~7); 22 + } 23 + 24 + void lx_set_mode(struct fb_info *); 25 + void lx_get_gamma(struct fb_info *, unsigned int *, int); 26 + void lx_set_gamma(struct fb_info *, unsigned int *, int); 27 + unsigned int lx_framebuffer_size(void); 28 + int lx_blank_display(struct fb_info *, int); 29 + void lx_set_palette_reg(struct fb_info *, unsigned int, unsigned int, 30 + unsigned int, unsigned int); 31 + 32 + /* MSRS */ 33 + 34 + #define MSR_LX_GLD_CONFIG 0x48002001 35 + #define MSR_LX_GLCP_DOTPLL 0x4c000015 36 + #define MSR_LX_DF_PADSEL 0x48000011 37 + #define MSR_LX_DC_SPARE 0x80000011 38 + #define MSR_LX_DF_GLCONFIG 0x48002001 39 + 40 + #define MSR_LX_GLIU0_P2D_RO0 0x10000029 41 + 42 + #define GLCP_DOTPLL_RESET (1 << 0) 43 + #define GLCP_DOTPLL_BYPASS (1 << 15) 44 + #define GLCP_DOTPLL_HALFPIX (1 << 24) 45 + #define GLCP_DOTPLL_LOCK (1 << 25) 46 + 47 + #define DF_CONFIG_OUTPUT_MASK 0x38 48 + #define DF_OUTPUT_PANEL 0x08 49 + #define DF_OUTPUT_CRT 0x00 50 + #define DF_SIMULTANEOUS_CRT_AND_FP (1 << 15) 51 + 52 + #define DF_DEFAULT_TFT_PAD_SEL_LOW 0xDFFFFFFF 53 + #define DF_DEFAULT_TFT_PAD_SEL_HIGH 0x0000003F 54 + 55 + #define DC_SPARE_DISABLE_CFIFO_HGO 0x00000800 56 + #define DC_SPARE_VFIFO_ARB_SELECT 0x00000400 57 + #define DC_SPARE_WM_LPEN_OVRD 0x00000200 58 + #define DC_SPARE_LOAD_WM_LPEN_MASK 0x00000100 59 + #define DC_SPARE_DISABLE_INIT_VID_PRI 0x00000080 60 + #define DC_SPARE_DISABLE_VFIFO_WM 0x00000040 61 + #define DC_SPARE_DISABLE_CWD_CHECK 0x00000020 62 + #define DC_SPARE_PIX8_PAN_FIX 0x00000010 63 + #define DC_SPARE_FIRST_REQ_MASK 0x00000002 64 + 65 + /* Registers */ 66 + 67 + #define DC_UNLOCK 0x00 68 + #define DC_UNLOCK_CODE 0x4758 69 + 70 + #define DC_GENERAL_CFG 0x04 71 + #define DC_GCFG_DFLE (1 << 0) 72 + #define DC_GCFG_VIDE (1 << 3) 73 + #define DC_GCFG_VGAE (1 << 7) 74 + #define DC_GCFG_CMPE (1 << 5) 75 + #define DC_GCFG_DECE (1 << 6) 76 + #define DC_GCFG_FDTY (1 << 17) 77 + 78 + #define DC_DISPLAY_CFG 0x08 79 + #define DC_DCFG_TGEN (1 << 0) 80 + #define DC_DCFG_GDEN (1 << 3) 81 + #define DC_DCFG_VDEN (1 << 4) 82 + #define DC_DCFG_TRUP (1 << 6) 83 + #define DC_DCFG_DCEN (1 << 24) 84 + #define DC_DCFG_PALB (1 << 25) 85 + #define DC_DCFG_VISL (1 << 27) 86 + 87 + #define DC_DCFG_16BPP 0x0 88 + 89 + #define DC_DCFG_DISP_MODE_MASK 0x00000300 90 + #define DC_DCFG_DISP_MODE_8BPP 0x00000000 91 + #define DC_DCFG_DISP_MODE_16BPP 0x00000100 92 + #define DC_DCFG_DISP_MODE_24BPP 0x00000200 93 + #define DC_DCFG_DISP_MODE_32BPP 0x00000300 94 + 95 + 96 + #define DC_ARB_CFG 0x0C 97 + 98 + #define DC_FB_START 0x10 99 + #define DC_CB_START 0x14 100 + #define DC_CURSOR_START 0x18 101 + 102 + #define DC_DV_TOP 0x2C 103 + #define DC_DV_TOP_ENABLE (1 << 0) 104 + 105 + #define DC_LINE_SIZE 0x30 106 + #define DC_GRAPHICS_PITCH 0x34 107 + #define DC_H_ACTIVE_TIMING 0x40 108 + #define DC_H_BLANK_TIMING 0x44 109 + #define DC_H_SYNC_TIMING 0x48 110 + #define DC_V_ACTIVE_TIMING 0x50 111 + #define DC_V_BLANK_TIMING 0x54 112 + #define DC_V_SYNC_TIMING 0x58 113 + #define DC_FB_ACTIVE 0x5C 114 + 115 + #define DC_PAL_ADDRESS 0x70 116 + #define DC_PAL_DATA 0x74 117 + 118 + #define DC_PHY_MEM_OFFSET 0x84 119 + 120 + #define DC_DV_CTL 0x88 121 + #define DC_DV_LINE_SIZE_MASK 0x00000C00 122 + #define DC_DV_LINE_SIZE_1024 0x00000000 123 + #define DC_DV_LINE_SIZE_2048 0x00000400 124 + #define DC_DV_LINE_SIZE_4096 0x00000800 125 + #define DC_DV_LINE_SIZE_8192 0x00000C00 126 + 127 + 128 + #define DC_GFX_SCALE 0x90 129 + #define DC_IRQ_FILT_CTL 0x94 130 + 131 + 132 + #define DC_IRQ 0xC8 133 + #define DC_IRQ_MASK (1 << 0) 134 + #define DC_VSYNC_IRQ_MASK (1 << 1) 135 + #define DC_IRQ_STATUS (1 << 20) 136 + #define DC_VSYNC_IRQ_STATUS (1 << 21) 137 + 138 + #define DC_GENLCK_CTRL 0xD4 139 + #define DC_GENLCK_ENABLE (1 << 18) 140 + #define DC_GC_ALPHA_FLICK_ENABLE (1 << 25) 141 + #define DC_GC_FLICKER_FILTER_ENABLE (1 << 24) 142 + #define DC_GC_FLICKER_FILTER_MASK (0x0F << 28) 143 + 144 + #define DC_COLOR_KEY 0xB8 145 + #define DC_CLR_KEY_ENABLE (1 << 24) 146 + 147 + 148 + #define DC3_DV_LINE_SIZE_MASK 0x00000C00 149 + #define DC3_DV_LINE_SIZE_1024 0x00000000 150 + #define DC3_DV_LINE_SIZE_2048 0x00000400 151 + #define DC3_DV_LINE_SIZE_4096 0x00000800 152 + #define DC3_DV_LINE_SIZE_8192 0x00000C00 153 + 154 + #define DF_VIDEO_CFG 0x0 155 + #define DF_VCFG_VID_EN (1 << 0) 156 + 157 + #define DF_DISPLAY_CFG 0x08 158 + 159 + #define DF_DCFG_CRT_EN (1 << 0) 160 + #define DF_DCFG_HSYNC_EN (1 << 1) 161 + #define DF_DCFG_VSYNC_EN (1 << 2) 162 + #define DF_DCFG_DAC_BL_EN (1 << 3) 163 + #define DF_DCFG_CRT_HSYNC_POL (1 << 8) 164 + #define DF_DCFG_CRT_VSYNC_POL (1 << 9) 165 + #define DF_DCFG_GV_PAL_BYP (1 << 21) 166 + 167 + #define DF_DCFG_CRT_SYNC_SKW_INIT 0x10000 168 + #define DF_DCFG_CRT_SYNC_SKW_MASK 0x1c000 169 + 170 + #define DF_DCFG_PWR_SEQ_DLY_INIT 0x80000 171 + #define DF_DCFG_PWR_SEQ_DLY_MASK 0xe0000 172 + 173 + #define DF_MISC 0x50 174 + 175 + #define DF_MISC_GAM_BYPASS (1 << 0) 176 + #define DF_MISC_DAC_PWRDN (1 << 10) 177 + #define DF_MISC_A_PWRDN (1 << 11) 178 + 179 + #define DF_PAR 0x38 180 + #define DF_PDR 0x40 181 + #define DF_ALPHA_CONTROL_1 0xD8 182 + #define DF_VIDEO_REQUEST 0x120 183 + 184 + #define DF_PANEL_TIM1 0x400 185 + #define DF_DEFAULT_TFT_PMTIM1 0x0 186 + 187 + #define DF_PANEL_TIM2 0x408 188 + #define DF_DEFAULT_TFT_PMTIM2 0x08000000 189 + 190 + #define DF_FP_PM 0x410 191 + #define DF_FP_PM_P (1 << 24) 192 + 193 + #define DF_DITHER_CONTROL 0x418 194 + #define DF_DEFAULT_TFT_DITHCTL 0x00000070 195 + #define GP_BLT_STATUS 0x44 196 + #define GP_BS_BLT_BUSY (1 << 0) 197 + #define GP_BS_CB_EMPTY (1 << 4) 198 + 199 + #endif
+621
drivers/video/geode/lxfb_core.c
··· 1 + /* 2 + * Geode LX framebuffer driver. 3 + * 4 + * Copyright (C) 2007 Advanced Micro Devices, Inc. 5 + * Built from gxfb (which is Copyright (C) 2006 Arcom Control Systems Ltd.) 6 + * 7 + * This program is free software; you can redistribute it and/or modify it 8 + * under the terms of the GNU General Public License as published by the 9 + * Free Software Foundation; either version 2 of the License, or (at your 10 + * option) any later version. 11 + */ 12 + 13 + #include <linux/module.h> 14 + #include <linux/kernel.h> 15 + #include <linux/errno.h> 16 + #include <linux/string.h> 17 + #include <linux/console.h> 18 + #include <linux/mm.h> 19 + #include <linux/slab.h> 20 + #include <linux/delay.h> 21 + #include <linux/fb.h> 22 + #include <linux/init.h> 23 + #include <linux/pci.h> 24 + #include <linux/uaccess.h> 25 + 26 + #include "lxfb.h" 27 + 28 + static char *mode_option; 29 + static int noclear, nopanel, nocrt; 30 + static int fbsize; 31 + 32 + /* Most of these modes are sorted in ascending order, but 33 + * since the first entry in this table is the "default" mode, 34 + * we try to make it something sane - 640x480-60 is sane 35 + */ 36 + 37 + const struct fb_videomode geode_modedb[] __initdata = { 38 + /* 640x480-60 */ 39 + { NULL, 60, 640, 480, 39682, 48, 8, 25, 2, 88, 2, 40 + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 41 + FB_VMODE_NONINTERLACED, 0 }, 42 + /* 640x400-70 */ 43 + { NULL, 70, 640, 400, 39770, 40, 8, 28, 5, 96, 2, 44 + FB_SYNC_HOR_HIGH_ACT, 45 + FB_VMODE_NONINTERLACED, 0 }, 46 + /* 640x480-70 */ 47 + { NULL, 70, 640, 480, 35014, 88, 24, 15, 2, 64, 3, 48 + 0, FB_VMODE_NONINTERLACED, 0 }, 49 + /* 640x480-72 */ 50 + { NULL, 72, 640, 480, 32102, 120, 16, 20, 1, 40, 3, 51 + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 52 + FB_VMODE_NONINTERLACED, 0 }, 53 + /* 640x480-75 */ 54 + { NULL, 75, 640, 480, 31746, 120, 16, 16, 1, 64, 3, 55 + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 56 + FB_VMODE_NONINTERLACED, 0 }, 57 + /* 640x480-85 */ 58 + { NULL, 85, 640, 480, 27780, 80, 56, 25, 1, 56, 3, 59 + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 60 + FB_VMODE_NONINTERLACED, 0 }, 61 + /* 640x480-90 */ 62 + { NULL, 90, 640, 480, 26392, 96, 32, 22, 1, 64, 3, 63 + 0, FB_VMODE_NONINTERLACED, 0 }, 64 + /* 640x480-100 */ 65 + { NULL, 100, 640, 480, 23167, 104, 40, 25, 1, 64, 3, 66 + 0, FB_VMODE_NONINTERLACED, 0 }, 67 + /* 640x480-60 */ 68 + { NULL, 60, 640, 480, 39682, 48, 16, 25, 10, 88, 2, 69 + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 70 + FB_VMODE_NONINTERLACED, 0 }, 71 + /* 800x600-56 */ 72 + { NULL, 56, 800, 600, 27901, 128, 24, 22, 1, 72, 2, 73 + 0, FB_VMODE_NONINTERLACED, 0 }, 74 + /* 800x600-60 */ 75 + { NULL, 60, 800, 600, 25131, 72, 32, 23, 1, 136, 4, 76 + 0, FB_VMODE_NONINTERLACED, 0 }, 77 + /* 800x600-70 */ 78 + { NULL, 70, 800, 600, 21873, 120, 40, 21, 4, 80, 3, 79 + 0, FB_VMODE_NONINTERLACED, 0 }, 80 + /* 800x600-72 */ 81 + { NULL, 72, 800, 600, 20052, 64, 56, 23, 37, 120, 6, 82 + 0, FB_VMODE_NONINTERLACED, 0 }, 83 + /* 800x600-75 */ 84 + { NULL, 75, 800, 600, 20202, 160, 16, 21, 1, 80, 3, 85 + 0, FB_VMODE_NONINTERLACED, 0 }, 86 + /* 800x600-85 */ 87 + { NULL, 85, 800, 600, 17790, 152, 32, 27, 1, 64, 3, 88 + 0, FB_VMODE_NONINTERLACED, 0 }, 89 + /* 800x600-90 */ 90 + { NULL, 90, 800, 600, 16648, 128, 40, 28, 1, 88, 3, 91 + 0, FB_VMODE_NONINTERLACED, 0 }, 92 + /* 800x600-100 */ 93 + { NULL, 100, 800, 600, 14667, 136, 48, 27, 1, 88, 3, 94 + 0, FB_VMODE_NONINTERLACED, 0 }, 95 + /* 800x600-60 */ 96 + { NULL, 60, 800, 600, 25131, 88, 40, 23, 1, 128, 4, 97 + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 98 + FB_VMODE_NONINTERLACED, 0 }, 99 + /* 1024x768-60 */ 100 + { NULL, 60, 1024, 768, 15385, 160, 24, 29, 3, 136, 6, 101 + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 102 + FB_VMODE_NONINTERLACED, 0 }, 103 + /* 1024x768-70 */ 104 + { NULL, 70, 1024, 768, 13346, 144, 24, 29, 3, 136, 6, 105 + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 106 + FB_VMODE_NONINTERLACED, 0 }, 107 + /* 1024x768-72 */ 108 + { NULL, 72, 1024, 768, 12702, 168, 56, 29, 4, 112, 3, 109 + 0, FB_VMODE_NONINTERLACED, 0 }, 110 + /* 1024x768-75 */ 111 + { NULL, 75, 1024, 768, 12703, 176, 16, 28, 1, 96, 3, 112 + 0, FB_VMODE_NONINTERLACED, 0 }, 113 + /* 1024x768-85 */ 114 + { NULL, 85, 1024, 768, 10581, 208, 48, 36, 1, 96, 3, 115 + 0, FB_VMODE_NONINTERLACED, 0 }, 116 + /* 1024x768-90 */ 117 + { NULL, 90, 1024, 768, 9981, 176, 64, 37, 1, 112, 3, 118 + 0, FB_VMODE_NONINTERLACED, 0 }, 119 + /* 1024x768-100 */ 120 + { NULL, 100, 1024, 768, 8825, 184, 72, 42, 1, 112, 3, 121 + 0, FB_VMODE_NONINTERLACED, 0 }, 122 + /* 1024x768-60 */ 123 + { NULL, 60, 1024, 768, 15385, 160, 24, 29, 3, 136, 6, 124 + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 125 + FB_VMODE_NONINTERLACED, 0 }, 126 + /* 1152x864-60 */ 127 + { NULL, 60, 1152, 864, 12251, 184, 64, 27, 1, 120, 3, 128 + 0, FB_VMODE_NONINTERLACED, 0 }, 129 + /* 1152x864-70 */ 130 + { NULL, 70, 1152, 864, 10254, 192, 72, 32, 8, 120, 3, 131 + 0, FB_VMODE_NONINTERLACED, 0 }, 132 + /* 1152x864-72 */ 133 + { NULL, 72, 1152, 864, 9866, 200, 72, 33, 7, 128, 3, 134 + 0, FB_VMODE_NONINTERLACED, 0 }, 135 + /* 1152x864-75 */ 136 + { NULL, 75, 1152, 864, 9259, 256, 64, 32, 1, 128, 3, 137 + 0, FB_VMODE_NONINTERLACED, 0 }, 138 + /* 1152x864-85 */ 139 + { NULL, 85, 1152, 864, 8357, 200, 72, 37, 3, 128, 3, 140 + 0, FB_VMODE_NONINTERLACED, 0 }, 141 + /* 1152x864-90 */ 142 + { NULL, 90, 1152, 864, 7719, 208, 80, 42, 9, 128, 3, 143 + 0, FB_VMODE_NONINTERLACED, 0 }, 144 + /* 1152x864-100 */ 145 + { NULL, 100, 1152, 864, 6947, 208, 80, 48, 3, 128, 3, 146 + 0, FB_VMODE_NONINTERLACED, 0 }, 147 + /* 1152x864-60 */ 148 + { NULL, 60, 1152, 864, 12251, 184, 64, 27, 1, 120, 3, 149 + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 150 + FB_VMODE_NONINTERLACED, 0 }, 151 + /* 1280x1024-60 */ 152 + { NULL, 60, 1280, 1024, 9262, 248, 48, 38, 1, 112, 3, 153 + 0, FB_VMODE_NONINTERLACED, 0 }, 154 + /* 1280x1024-70 */ 155 + { NULL, 70, 1280, 1024, 7719, 224, 88, 38, 6, 136, 3, 156 + 0, FB_VMODE_NONINTERLACED, 0 }, 157 + /* 1280x1024-72 */ 158 + { NULL, 72, 1280, 1024, 7490, 224, 88, 39, 7, 136, 3, 159 + 0, FB_VMODE_NONINTERLACED, 0 }, 160 + /* 1280x1024-75 */ 161 + { NULL, 75, 1280, 1024, 7409, 248, 16, 38, 1, 144, 3, 162 + 0, FB_VMODE_NONINTERLACED, 0 }, 163 + /* 1280x1024-85 */ 164 + { NULL, 85, 1280, 1024, 6351, 224, 64, 44, 1, 160, 3, 165 + 0, FB_VMODE_NONINTERLACED, 0 }, 166 + /* 1280x1024-90 */ 167 + { NULL, 90, 1280, 1024, 5791, 240, 96, 51, 12, 144, 3, 168 + 0, FB_VMODE_NONINTERLACED, 0 }, 169 + /* 1280x1024-100 */ 170 + { NULL, 100, 1280, 1024, 5212, 240, 96, 57, 6, 144, 3, 171 + 0, FB_VMODE_NONINTERLACED, 0 }, 172 + /* 1280x1024-60 */ 173 + { NULL, 60, 1280, 1024, 9262, 248, 48, 38, 1, 112, 3, 174 + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 175 + FB_VMODE_NONINTERLACED, 0 }, 176 + /* 1600x1200-60 */ 177 + { NULL, 60, 1600, 1200, 6172, 304, 64, 46, 1, 192, 3, 178 + 0, FB_VMODE_NONINTERLACED, 0 }, 179 + /* 1600x1200-70 */ 180 + { NULL, 70, 1600, 1200, 5291, 304, 64, 46, 1, 192, 3, 181 + 0, FB_VMODE_NONINTERLACED, 0 }, 182 + /* 1600x1200-72 */ 183 + { NULL, 72, 1600, 1200, 5053, 288, 112, 47, 13, 176, 3, 184 + 0, FB_VMODE_NONINTERLACED, 0 }, 185 + /* 1600x1200-75 */ 186 + { NULL, 75, 1600, 1200, 4938, 304, 64, 46, 1, 192, 3, 187 + 0, FB_VMODE_NONINTERLACED, 0 }, 188 + /* 1600x1200-85 */ 189 + { NULL, 85, 1600, 1200, 4357, 304, 64, 46, 1, 192, 3, 190 + 0, FB_VMODE_NONINTERLACED, 0 }, 191 + /* 1600x1200-90 */ 192 + { NULL, 90, 1600, 1200, 3981, 304, 128, 60, 1, 176, 3, 193 + 0, FB_VMODE_NONINTERLACED, 0 }, 194 + /* 1600x1200-100 */ 195 + { NULL, 100, 1600, 1200, 3563, 304, 128, 67, 1, 176, 3, 196 + 0, FB_VMODE_NONINTERLACED, 0 }, 197 + /* 1600x1200-60 */ 198 + { NULL, 60, 1600, 1200, 6172, 304, 64, 46, 1, 192, 3, 199 + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 200 + FB_VMODE_NONINTERLACED, 0 }, 201 + /* 1920x1440-60 */ 202 + { NULL, 60, 1920, 1440, 4273, 344, 128, 56, 1, 208, 3, 203 + 0, FB_VMODE_NONINTERLACED, 0 }, 204 + /* 1920x1440-70 */ 205 + { NULL, 70, 1920, 1440, 3593, 360, 152, 55, 8, 208, 3, 206 + 0, FB_VMODE_NONINTERLACED, 0 }, 207 + /* 1920x1440-72 */ 208 + { NULL, 72, 1920, 1440, 3472, 360, 152, 68, 4, 208, 3, 209 + 0, FB_VMODE_NONINTERLACED, 0 }, 210 + /* 1920x1440-75 */ 211 + { NULL, 75, 1920, 1440, 3367, 352, 144, 56, 1, 224, 3, 212 + 0, FB_VMODE_NONINTERLACED, 0 }, 213 + /* 1920x1440-85 */ 214 + { NULL, 85, 1920, 1440, 2929, 368, 152, 68, 1, 216, 3, 215 + 0, FB_VMODE_NONINTERLACED, 0 }, 216 + }; 217 + 218 + static int lxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) 219 + { 220 + if (var->xres > 1920 || var->yres > 1440) 221 + return -EINVAL; 222 + 223 + if (var->bits_per_pixel == 32) { 224 + var->red.offset = 16; var->red.length = 8; 225 + var->green.offset = 8; var->green.length = 8; 226 + var->blue.offset = 0; var->blue.length = 8; 227 + } else if (var->bits_per_pixel == 16) { 228 + var->red.offset = 11; var->red.length = 5; 229 + var->green.offset = 5; var->green.length = 6; 230 + var->blue.offset = 0; var->blue.length = 5; 231 + } else if (var->bits_per_pixel == 8) { 232 + var->red.offset = 0; var->red.length = 8; 233 + var->green.offset = 0; var->green.length = 8; 234 + var->blue.offset = 0; var->blue.length = 8; 235 + } else 236 + return -EINVAL; 237 + 238 + var->transp.offset = 0; var->transp.length = 0; 239 + 240 + /* Enough video memory? */ 241 + if ((lx_get_pitch(var->xres, var->bits_per_pixel) * var->yres) 242 + > info->fix.smem_len) 243 + return -EINVAL; 244 + 245 + return 0; 246 + } 247 + 248 + static int lxfb_set_par(struct fb_info *info) 249 + { 250 + if (info->var.bits_per_pixel > 8) { 251 + info->fix.visual = FB_VISUAL_TRUECOLOR; 252 + fb_dealloc_cmap(&info->cmap); 253 + } else { 254 + info->fix.visual = FB_VISUAL_PSEUDOCOLOR; 255 + fb_alloc_cmap(&info->cmap, 1<<info->var.bits_per_pixel, 0); 256 + } 257 + 258 + info->fix.line_length = lx_get_pitch(info->var.xres, 259 + info->var.bits_per_pixel); 260 + 261 + lx_set_mode(info); 262 + return 0; 263 + } 264 + 265 + static inline u_int chan_to_field(u_int chan, struct fb_bitfield *bf) 266 + { 267 + chan &= 0xffff; 268 + chan >>= 16 - bf->length; 269 + return chan << bf->offset; 270 + } 271 + 272 + static int lxfb_setcolreg(unsigned regno, unsigned red, unsigned green, 273 + unsigned blue, unsigned transp, 274 + struct fb_info *info) 275 + { 276 + if (info->var.grayscale) { 277 + /* grayscale = 0.30*R + 0.59*G + 0.11*B */ 278 + red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8; 279 + } 280 + 281 + /* Truecolor has hardware independent palette */ 282 + if (info->fix.visual == FB_VISUAL_TRUECOLOR) { 283 + u32 *pal = info->pseudo_palette; 284 + u32 v; 285 + 286 + if (regno >= 16) 287 + return -EINVAL; 288 + 289 + v = chan_to_field(red, &info->var.red); 290 + v |= chan_to_field(green, &info->var.green); 291 + v |= chan_to_field(blue, &info->var.blue); 292 + 293 + pal[regno] = v; 294 + } else { 295 + if (regno >= 256) 296 + return -EINVAL; 297 + 298 + lx_set_palette_reg(info, regno, red, green, blue); 299 + } 300 + 301 + return 0; 302 + } 303 + 304 + static int lxfb_blank(int blank_mode, struct fb_info *info) 305 + { 306 + return lx_blank_display(info, blank_mode); 307 + } 308 + 309 + 310 + static int __init lxfb_map_video_memory(struct fb_info *info, 311 + struct pci_dev *dev) 312 + { 313 + struct lxfb_par *par = info->par; 314 + int ret; 315 + 316 + ret = pci_enable_device(dev); 317 + 318 + if (ret) 319 + return ret; 320 + 321 + ret = pci_request_region(dev, 0, "lxfb-framebuffer"); 322 + 323 + if (ret) 324 + return ret; 325 + 326 + ret = pci_request_region(dev, 1, "lxfb-gp"); 327 + 328 + if (ret) 329 + return ret; 330 + 331 + ret = pci_request_region(dev, 2, "lxfb-vg"); 332 + 333 + if (ret) 334 + return ret; 335 + 336 + ret = pci_request_region(dev, 3, "lxfb-vip"); 337 + 338 + if (ret) 339 + return ret; 340 + 341 + info->fix.smem_start = pci_resource_start(dev, 0); 342 + info->fix.smem_len = fbsize ? fbsize : lx_framebuffer_size(); 343 + 344 + info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len); 345 + 346 + ret = -ENOMEM; 347 + 348 + if (info->screen_base == NULL) 349 + return ret; 350 + 351 + par->gp_regs = ioremap(pci_resource_start(dev, 1), 352 + pci_resource_len(dev, 1)); 353 + 354 + if (par->gp_regs == NULL) 355 + return ret; 356 + 357 + par->dc_regs = ioremap(pci_resource_start(dev, 2), 358 + pci_resource_len(dev, 2)); 359 + 360 + if (par->dc_regs == NULL) 361 + return ret; 362 + 363 + par->df_regs = ioremap(pci_resource_start(dev, 3), 364 + pci_resource_len(dev, 3)); 365 + 366 + if (par->df_regs == NULL) 367 + return ret; 368 + 369 + writel(DC_UNLOCK_CODE, par->dc_regs + DC_UNLOCK); 370 + 371 + writel(info->fix.smem_start & 0xFF000000, 372 + par->dc_regs + DC_PHY_MEM_OFFSET); 373 + 374 + writel(0, par->dc_regs + DC_UNLOCK); 375 + 376 + dev_info(&dev->dev, "%d KB of video memory at 0x%lx\n", 377 + info->fix.smem_len / 1024, info->fix.smem_start); 378 + 379 + return 0; 380 + } 381 + 382 + static struct fb_ops lxfb_ops = { 383 + .owner = THIS_MODULE, 384 + .fb_check_var = lxfb_check_var, 385 + .fb_set_par = lxfb_set_par, 386 + .fb_setcolreg = lxfb_setcolreg, 387 + .fb_blank = lxfb_blank, 388 + /* No HW acceleration for now. */ 389 + .fb_fillrect = cfb_fillrect, 390 + .fb_copyarea = cfb_copyarea, 391 + .fb_imageblit = cfb_imageblit, 392 + }; 393 + 394 + static struct fb_info * __init lxfb_init_fbinfo(struct device *dev) 395 + { 396 + struct lxfb_par *par; 397 + struct fb_info *info; 398 + 399 + /* Alloc enough space for the pseudo palette. */ 400 + info = framebuffer_alloc(sizeof(struct lxfb_par) + sizeof(u32) * 16, 401 + dev); 402 + if (!info) 403 + return NULL; 404 + 405 + par = info->par; 406 + 407 + strcpy(info->fix.id, "Geode LX"); 408 + 409 + info->fix.type = FB_TYPE_PACKED_PIXELS; 410 + info->fix.type_aux = 0; 411 + info->fix.xpanstep = 0; 412 + info->fix.ypanstep = 0; 413 + info->fix.ywrapstep = 0; 414 + info->fix.accel = FB_ACCEL_NONE; 415 + 416 + info->var.nonstd = 0; 417 + info->var.activate = FB_ACTIVATE_NOW; 418 + info->var.height = -1; 419 + info->var.width = -1; 420 + info->var.accel_flags = 0; 421 + info->var.vmode = FB_VMODE_NONINTERLACED; 422 + 423 + info->fbops = &lxfb_ops; 424 + info->flags = FBINFO_DEFAULT; 425 + info->node = -1; 426 + 427 + info->pseudo_palette = (void *)par + sizeof(struct lxfb_par); 428 + 429 + info->var.grayscale = 0; 430 + 431 + return info; 432 + } 433 + 434 + static int __init lxfb_probe(struct pci_dev *pdev, 435 + const struct pci_device_id *id) 436 + { 437 + struct lxfb_par *par; 438 + struct fb_info *info; 439 + int ret; 440 + 441 + struct fb_videomode *modedb_ptr; 442 + int modedb_size; 443 + 444 + info = lxfb_init_fbinfo(&pdev->dev); 445 + 446 + if (info == NULL) 447 + return -ENOMEM; 448 + 449 + par = info->par; 450 + 451 + ret = lxfb_map_video_memory(info, pdev); 452 + 453 + if (ret < 0) { 454 + dev_err(&pdev->dev, 455 + "failed to map frame buffer or controller registers\n"); 456 + goto err; 457 + } 458 + 459 + /* Set up the desired outputs */ 460 + 461 + par->output = 0; 462 + par->output |= (nopanel) ? 0 : OUTPUT_PANEL; 463 + par->output |= (nocrt) ? 0 : OUTPUT_CRT; 464 + 465 + /* Set up the mode database */ 466 + 467 + modedb_ptr = (struct fb_videomode *) geode_modedb; 468 + modedb_size = ARRAY_SIZE(geode_modedb); 469 + 470 + ret = fb_find_mode(&info->var, info, mode_option, 471 + modedb_ptr, modedb_size, NULL, 16); 472 + 473 + if (ret == 0 || ret == 4) { 474 + dev_err(&pdev->dev, "could not find valid video mode\n"); 475 + ret = -EINVAL; 476 + goto err; 477 + } 478 + 479 + /* Clear the screen of garbage, unless noclear was specified, 480 + * in which case we assume the user knows what he is doing */ 481 + 482 + if (!noclear) 483 + memset_io(info->screen_base, 0, info->fix.smem_len); 484 + 485 + /* Set the mode */ 486 + 487 + lxfb_check_var(&info->var, info); 488 + lxfb_set_par(info); 489 + 490 + if (register_framebuffer(info) < 0) { 491 + ret = -EINVAL; 492 + goto err; 493 + } 494 + pci_set_drvdata(pdev, info); 495 + printk(KERN_INFO "fb%d: %s frame buffer device\n", 496 + info->node, info->fix.id); 497 + 498 + return 0; 499 + 500 + err: 501 + if (info->screen_base) { 502 + iounmap(info->screen_base); 503 + pci_release_region(pdev, 0); 504 + } 505 + if (par->gp_regs) { 506 + iounmap(par->gp_regs); 507 + pci_release_region(pdev, 1); 508 + } 509 + if (par->dc_regs) { 510 + iounmap(par->dc_regs); 511 + pci_release_region(pdev, 2); 512 + } 513 + if (par->df_regs) { 514 + iounmap(par->df_regs); 515 + pci_release_region(pdev, 3); 516 + } 517 + 518 + if (info) 519 + framebuffer_release(info); 520 + 521 + return ret; 522 + } 523 + 524 + static void lxfb_remove(struct pci_dev *pdev) 525 + { 526 + struct fb_info *info = pci_get_drvdata(pdev); 527 + struct lxfb_par *par = info->par; 528 + 529 + unregister_framebuffer(info); 530 + 531 + iounmap(info->screen_base); 532 + pci_release_region(pdev, 0); 533 + 534 + iounmap(par->gp_regs); 535 + pci_release_region(pdev, 1); 536 + 537 + iounmap(par->dc_regs); 538 + pci_release_region(pdev, 2); 539 + 540 + iounmap(par->df_regs); 541 + pci_release_region(pdev, 3); 542 + 543 + pci_set_drvdata(pdev, NULL); 544 + framebuffer_release(info); 545 + } 546 + 547 + static struct pci_device_id lxfb_id_table[] = { 548 + { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LX_VIDEO) }, 549 + { 0, } 550 + }; 551 + 552 + MODULE_DEVICE_TABLE(pci, lxfb_id_table); 553 + 554 + static struct pci_driver lxfb_driver = { 555 + .name = "lxfb", 556 + .id_table = lxfb_id_table, 557 + .probe = lxfb_probe, 558 + .remove = lxfb_remove, 559 + }; 560 + 561 + #ifndef MODULE 562 + static int __init lxfb_setup(char *options) 563 + { 564 + char *opt; 565 + 566 + if (!options || !*options) 567 + return 0; 568 + 569 + while (1) { 570 + char *opt = strsep(&options, ","); 571 + 572 + if (opt == NULL) 573 + break; 574 + 575 + if (!*opt) 576 + continue; 577 + 578 + if (!strncmp(opt, "fbsize:", 7)) 579 + fbsize = simple_strtoul(opt+7, NULL, 0); 580 + else if (!strcmp(opt, "noclear")) 581 + noclear = 1; 582 + else if (!strcmp(opt, "nopanel")) 583 + nopanel = 1; 584 + else if (!strcmp(opt, "nocrt")) 585 + nocrt = 1; 586 + else 587 + mode_option = opt; 588 + } 589 + 590 + return 0; 591 + } 592 + #endif 593 + 594 + static int __init lxfb_init(void) 595 + { 596 + #ifndef MODULE 597 + char *option = NULL; 598 + 599 + if (fb_get_options("lxfb", &option)) 600 + return -ENODEV; 601 + 602 + lxfb_setup(option); 603 + #endif 604 + return pci_register_driver(&lxfb_driver); 605 + } 606 + static void __exit lxfb_cleanup(void) 607 + { 608 + pci_unregister_driver(&lxfb_driver); 609 + } 610 + 611 + module_init(lxfb_init); 612 + module_exit(lxfb_cleanup); 613 + 614 + module_param(mode_option, charp, 0); 615 + MODULE_PARM_DESC(mode_option, "video mode (<x>x<y>[-<bpp>][@<refr>])"); 616 + 617 + module_param(fbsize, int, 0); 618 + MODULE_PARM_DESC(fbsize, "video memory size"); 619 + 620 + MODULE_DESCRIPTION("Framebuffer driver for the AMD Geode LX"); 621 + MODULE_LICENSE("GPL");
+536
drivers/video/geode/lxfb_ops.c
··· 1 + /* Geode LX framebuffer driver 2 + * 3 + * Copyright (C) 2006-2007, Advanced Micro Devices,Inc. 4 + * 5 + * This program is free software; you can redistribute it and/or modify it 6 + * under the terms of the GNU General Public License as published by the 7 + * Free Software Foundation; either version 2 of the License, or (at your 8 + * option) any later version. 9 + */ 10 + 11 + #include <linux/kernel.h> 12 + #include <linux/errno.h> 13 + #include <linux/fb.h> 14 + #include <linux/uaccess.h> 15 + #include <linux/delay.h> 16 + 17 + #include "lxfb.h" 18 + 19 + /* TODO 20 + * Support panel scaling 21 + * Add acceleration 22 + * Add support for interlacing (TV out) 23 + * Support compression 24 + */ 25 + 26 + /* This is the complete list of PLL frequencies that we can set - 27 + * we will choose the closest match to the incoming clock. 28 + * freq is the frequency of the dotclock * 1000 (for example, 29 + * 24823 = 24.983 Mhz). 30 + * pllval is the corresponding PLL value 31 + */ 32 + 33 + static const struct { 34 + unsigned int pllval; 35 + unsigned int freq; 36 + } pll_table[] = { 37 + { 0x000031AC, 24923 }, 38 + { 0x0000215D, 25175 }, 39 + { 0x00001087, 27000 }, 40 + { 0x0000216C, 28322 }, 41 + { 0x0000218D, 28560 }, 42 + { 0x000010C9, 31200 }, 43 + { 0x00003147, 31500 }, 44 + { 0x000010A7, 33032 }, 45 + { 0x00002159, 35112 }, 46 + { 0x00004249, 35500 }, 47 + { 0x00000057, 36000 }, 48 + { 0x0000219A, 37889 }, 49 + { 0x00002158, 39168 }, 50 + { 0x00000045, 40000 }, 51 + { 0x00000089, 43163 }, 52 + { 0x000010E7, 44900 }, 53 + { 0x00002136, 45720 }, 54 + { 0x00003207, 49500 }, 55 + { 0x00002187, 50000 }, 56 + { 0x00004286, 56250 }, 57 + { 0x000010E5, 60065 }, 58 + { 0x00004214, 65000 }, 59 + { 0x00001105, 68179 }, 60 + { 0x000031E4, 74250 }, 61 + { 0x00003183, 75000 }, 62 + { 0x00004284, 78750 }, 63 + { 0x00001104, 81600 }, 64 + { 0x00006363, 94500 }, 65 + { 0x00005303, 97520 }, 66 + { 0x00002183, 100187 }, 67 + { 0x00002122, 101420 }, 68 + { 0x00001081, 108000 }, 69 + { 0x00006201, 113310 }, 70 + { 0x00000041, 119650 }, 71 + { 0x000041A1, 129600 }, 72 + { 0x00002182, 133500 }, 73 + { 0x000041B1, 135000 }, 74 + { 0x00000051, 144000 }, 75 + { 0x000041E1, 148500 }, 76 + { 0x000062D1, 157500 }, 77 + { 0x000031A1, 162000 }, 78 + { 0x00000061, 169203 }, 79 + { 0x00004231, 172800 }, 80 + { 0x00002151, 175500 }, 81 + { 0x000052E1, 189000 }, 82 + { 0x00000071, 192000 }, 83 + { 0x00003201, 198000 }, 84 + { 0x00004291, 202500 }, 85 + { 0x00001101, 204750 }, 86 + { 0x00007481, 218250 }, 87 + { 0x00004170, 229500 }, 88 + { 0x00006210, 234000 }, 89 + { 0x00003140, 251182 }, 90 + { 0x00006250, 261000 }, 91 + { 0x000041C0, 278400 }, 92 + { 0x00005220, 280640 }, 93 + { 0x00000050, 288000 }, 94 + { 0x000041E0, 297000 }, 95 + { 0x00002130, 320207 } 96 + }; 97 + 98 + 99 + static void lx_set_dotpll(u32 pllval) 100 + { 101 + u32 dotpll_lo, dotpll_hi; 102 + int i; 103 + 104 + rdmsr(MSR_LX_GLCP_DOTPLL, dotpll_lo, dotpll_hi); 105 + 106 + if ((dotpll_lo & GLCP_DOTPLL_LOCK) && (dotpll_hi == pllval)) 107 + return; 108 + 109 + dotpll_hi = pllval; 110 + dotpll_lo &= ~(GLCP_DOTPLL_BYPASS | GLCP_DOTPLL_HALFPIX); 111 + dotpll_lo |= GLCP_DOTPLL_RESET; 112 + 113 + wrmsr(MSR_LX_GLCP_DOTPLL, dotpll_lo, dotpll_hi); 114 + 115 + /* Wait 100us for the PLL to lock */ 116 + 117 + udelay(100); 118 + 119 + /* Now, loop for the lock bit */ 120 + 121 + for (i = 0; i < 1000; i++) { 122 + rdmsr(MSR_LX_GLCP_DOTPLL, dotpll_lo, dotpll_hi); 123 + if (dotpll_lo & GLCP_DOTPLL_LOCK) 124 + break; 125 + } 126 + 127 + /* Clear the reset bit */ 128 + 129 + dotpll_lo &= ~GLCP_DOTPLL_RESET; 130 + wrmsr(MSR_LX_GLCP_DOTPLL, dotpll_lo, dotpll_hi); 131 + } 132 + 133 + /* Set the clock based on the frequency specified by the current mode */ 134 + 135 + static void lx_set_clock(struct fb_info *info) 136 + { 137 + unsigned int diff, min, best = 0; 138 + unsigned int freq, i; 139 + 140 + freq = (unsigned int) (0x3b9aca00 / info->var.pixclock); 141 + 142 + min = abs(pll_table[0].freq - freq); 143 + 144 + for (i = 0; i < ARRAY_SIZE(pll_table); i++) { 145 + diff = abs(pll_table[i].freq - freq); 146 + if (diff < min) { 147 + min = diff; 148 + best = i; 149 + } 150 + } 151 + 152 + lx_set_dotpll(pll_table[best].pllval & 0x7FFF); 153 + } 154 + 155 + static void lx_graphics_disable(struct fb_info *info) 156 + { 157 + struct lxfb_par *par = info->par; 158 + unsigned int val, gcfg; 159 + 160 + /* Note: This assumes that the video is in a quitet state */ 161 + 162 + writel(0, par->df_regs + DF_ALPHA_CONTROL_1); 163 + writel(0, par->df_regs + DF_ALPHA_CONTROL_1 + 32); 164 + writel(0, par->df_regs + DF_ALPHA_CONTROL_1 + 64); 165 + 166 + /* Turn off the VGA and video enable */ 167 + val = readl (par->dc_regs + DC_GENERAL_CFG) & 168 + ~(DC_GCFG_VGAE | DC_GCFG_VIDE); 169 + 170 + writel(val, par->dc_regs + DC_GENERAL_CFG); 171 + 172 + val = readl(par->df_regs + DF_VIDEO_CFG) & ~DF_VCFG_VID_EN; 173 + writel(val, par->df_regs + DF_VIDEO_CFG); 174 + 175 + writel( DC_IRQ_MASK | DC_VSYNC_IRQ_MASK | 176 + DC_IRQ_STATUS | DC_VSYNC_IRQ_STATUS, 177 + par->dc_regs + DC_IRQ); 178 + 179 + val = readl(par->dc_regs + DC_GENLCK_CTRL) & ~DC_GENLCK_ENABLE; 180 + writel(val, par->dc_regs + DC_GENLCK_CTRL); 181 + 182 + val = readl(par->dc_regs + DC_COLOR_KEY) & ~DC_CLR_KEY_ENABLE; 183 + writel(val & ~DC_CLR_KEY_ENABLE, par->dc_regs + DC_COLOR_KEY); 184 + 185 + /* We don't actually blank the panel, due to the long latency 186 + involved with bringing it back */ 187 + 188 + val = readl(par->df_regs + DF_MISC) | DF_MISC_DAC_PWRDN; 189 + writel(val, par->df_regs + DF_MISC); 190 + 191 + /* Turn off the display */ 192 + 193 + val = readl(par->df_regs + DF_DISPLAY_CFG); 194 + writel(val & ~(DF_DCFG_CRT_EN | DF_DCFG_HSYNC_EN | DF_DCFG_VSYNC_EN | 195 + DF_DCFG_DAC_BL_EN), par->df_regs + DF_DISPLAY_CFG); 196 + 197 + gcfg = readl(par->dc_regs + DC_GENERAL_CFG); 198 + gcfg &= ~(DC_GCFG_CMPE | DC_GCFG_DECE); 199 + writel(gcfg, par->dc_regs + DC_GENERAL_CFG); 200 + 201 + /* Turn off the TGEN */ 202 + val = readl(par->dc_regs + DC_DISPLAY_CFG); 203 + val &= ~DC_DCFG_TGEN; 204 + writel(val, par->dc_regs + DC_DISPLAY_CFG); 205 + 206 + /* Wait 1000 usecs to ensure that the TGEN is clear */ 207 + udelay(1000); 208 + 209 + /* Turn off the FIFO loader */ 210 + 211 + gcfg &= ~DC_GCFG_DFLE; 212 + writel(gcfg, par->dc_regs + DC_GENERAL_CFG); 213 + 214 + /* Lastly, wait for the GP to go idle */ 215 + 216 + do { 217 + val = readl(par->gp_regs + GP_BLT_STATUS); 218 + } while ((val & GP_BS_BLT_BUSY) || !(val & GP_BS_CB_EMPTY)); 219 + } 220 + 221 + static void lx_graphics_enable(struct fb_info *info) 222 + { 223 + struct lxfb_par *par = info->par; 224 + u32 temp, config; 225 + 226 + /* Set the video request register */ 227 + writel(0, par->df_regs + DF_VIDEO_REQUEST); 228 + 229 + /* Set up the polarities */ 230 + 231 + config = readl(par->df_regs + DF_DISPLAY_CFG); 232 + 233 + config &= ~(DF_DCFG_CRT_SYNC_SKW_MASK | DF_DCFG_PWR_SEQ_DLY_MASK | 234 + DF_DCFG_CRT_HSYNC_POL | DF_DCFG_CRT_VSYNC_POL); 235 + 236 + config |= (DF_DCFG_CRT_SYNC_SKW_INIT | DF_DCFG_PWR_SEQ_DLY_INIT | 237 + DF_DCFG_GV_PAL_BYP); 238 + 239 + if (info->var.sync & FB_SYNC_HOR_HIGH_ACT) 240 + config |= DF_DCFG_CRT_HSYNC_POL; 241 + 242 + if (info->var.sync & FB_SYNC_VERT_HIGH_ACT) 243 + config |= DF_DCFG_CRT_VSYNC_POL; 244 + 245 + if (par->output & OUTPUT_PANEL) { 246 + u32 msrlo, msrhi; 247 + 248 + writel(DF_DEFAULT_TFT_PMTIM1, 249 + par->df_regs + DF_PANEL_TIM1); 250 + writel(DF_DEFAULT_TFT_PMTIM2, 251 + par->df_regs + DF_PANEL_TIM2); 252 + writel(DF_DEFAULT_TFT_DITHCTL, 253 + par->df_regs + DF_DITHER_CONTROL); 254 + 255 + msrlo = DF_DEFAULT_TFT_PAD_SEL_LOW; 256 + msrhi = DF_DEFAULT_TFT_PAD_SEL_HIGH; 257 + 258 + wrmsr(MSR_LX_DF_PADSEL, msrlo, msrhi); 259 + } 260 + 261 + if (par->output & OUTPUT_CRT) { 262 + config |= DF_DCFG_CRT_EN | DF_DCFG_HSYNC_EN | 263 + DF_DCFG_VSYNC_EN | DF_DCFG_DAC_BL_EN; 264 + } 265 + 266 + writel(config, par->df_regs + DF_DISPLAY_CFG); 267 + 268 + /* Turn the CRT dacs back on */ 269 + 270 + if (par->output & OUTPUT_CRT) { 271 + temp = readl(par->df_regs + DF_MISC); 272 + temp &= ~(DF_MISC_DAC_PWRDN | DF_MISC_A_PWRDN); 273 + writel(temp, par->df_regs + DF_MISC); 274 + } 275 + 276 + /* Turn the panel on (if it isn't already) */ 277 + 278 + if (par->output & OUTPUT_PANEL) { 279 + temp = readl(par->df_regs + DF_FP_PM); 280 + 281 + if (!(temp & 0x09)) 282 + writel(temp | DF_FP_PM_P, par->df_regs + DF_FP_PM); 283 + } 284 + 285 + temp = readl(par->df_regs + DF_MISC); 286 + temp = readl(par->df_regs + DF_DISPLAY_CFG); 287 + } 288 + 289 + unsigned int lx_framebuffer_size(void) 290 + { 291 + unsigned int val; 292 + 293 + /* The frame buffer size is reported by a VSM in VSA II */ 294 + /* Virtual Register Class = 0x02 */ 295 + /* VG_MEM_SIZE (1MB units) = 0x00 */ 296 + 297 + outw(0xFC53, 0xAC1C); 298 + outw(0x0200, 0xAC1C); 299 + 300 + val = (unsigned int)(inw(0xAC1E)) & 0xFE; 301 + return (val << 20); 302 + } 303 + 304 + void lx_set_mode(struct fb_info *info) 305 + { 306 + struct lxfb_par *par = info->par; 307 + u64 msrval; 308 + 309 + unsigned int max, dv, val, size; 310 + 311 + unsigned int gcfg, dcfg; 312 + int hactive, hblankstart, hsyncstart, hsyncend, hblankend, htotal; 313 + int vactive, vblankstart, vsyncstart, vsyncend, vblankend, vtotal; 314 + 315 + /* Unlock the DC registers */ 316 + writel(DC_UNLOCK_CODE, par->dc_regs + DC_UNLOCK); 317 + 318 + lx_graphics_disable(info); 319 + 320 + lx_set_clock(info); 321 + 322 + /* Set output mode */ 323 + 324 + rdmsrl(MSR_LX_DF_GLCONFIG, msrval); 325 + msrval &= ~DF_CONFIG_OUTPUT_MASK; 326 + 327 + if (par->output & OUTPUT_PANEL) { 328 + msrval |= DF_OUTPUT_PANEL; 329 + 330 + if (par->output & OUTPUT_CRT) 331 + msrval |= DF_SIMULTANEOUS_CRT_AND_FP; 332 + else 333 + msrval &= ~DF_SIMULTANEOUS_CRT_AND_FP; 334 + } else { 335 + msrval |= DF_OUTPUT_CRT; 336 + } 337 + 338 + wrmsrl(MSR_LX_DF_GLCONFIG, msrval); 339 + 340 + /* Clear the various buffers */ 341 + /* FIXME: Adjust for panning here */ 342 + 343 + writel(0, par->dc_regs + DC_FB_START); 344 + writel(0, par->dc_regs + DC_CB_START); 345 + writel(0, par->dc_regs + DC_CURSOR_START); 346 + 347 + /* FIXME: Add support for interlacing */ 348 + /* FIXME: Add support for scaling */ 349 + 350 + val = readl(par->dc_regs + DC_GENLCK_CTRL); 351 + val &= ~(DC_GC_ALPHA_FLICK_ENABLE | 352 + DC_GC_FLICKER_FILTER_ENABLE | DC_GC_FLICKER_FILTER_MASK); 353 + 354 + /* Default scaling params */ 355 + 356 + writel((0x4000 << 16) | 0x4000, par->dc_regs + DC_GFX_SCALE); 357 + writel(0, par->dc_regs + DC_IRQ_FILT_CTL); 358 + writel(val, par->dc_regs + DC_GENLCK_CTRL); 359 + 360 + /* FIXME: Support compression */ 361 + 362 + if (info->fix.line_length > 4096) 363 + dv = DC_DV_LINE_SIZE_8192; 364 + else if (info->fix.line_length > 2048) 365 + dv = DC_DV_LINE_SIZE_4096; 366 + else if (info->fix.line_length > 1024) 367 + dv = DC_DV_LINE_SIZE_2048; 368 + else 369 + dv = DC_DV_LINE_SIZE_1024; 370 + 371 + max = info->fix.line_length * info->var.yres; 372 + max = (max + 0x3FF) & 0xFFFFFC00; 373 + 374 + writel(max | DC_DV_TOP_ENABLE, par->dc_regs + DC_DV_TOP); 375 + 376 + val = readl(par->dc_regs + DC_DV_CTL) & ~DC_DV_LINE_SIZE_MASK; 377 + writel(val | dv, par->dc_regs + DC_DV_CTL); 378 + 379 + size = info->var.xres * (info->var.bits_per_pixel >> 3); 380 + 381 + writel(info->fix.line_length >> 3, par->dc_regs + DC_GRAPHICS_PITCH); 382 + writel((size + 7) >> 3, par->dc_regs + DC_LINE_SIZE); 383 + 384 + /* Set default watermark values */ 385 + 386 + rdmsrl(MSR_LX_DC_SPARE, msrval); 387 + 388 + msrval &= ~(DC_SPARE_DISABLE_CFIFO_HGO | DC_SPARE_VFIFO_ARB_SELECT | 389 + DC_SPARE_LOAD_WM_LPEN_MASK | DC_SPARE_WM_LPEN_OVRD | 390 + DC_SPARE_DISABLE_INIT_VID_PRI | DC_SPARE_DISABLE_VFIFO_WM); 391 + msrval |= DC_SPARE_DISABLE_VFIFO_WM | DC_SPARE_DISABLE_INIT_VID_PRI; 392 + wrmsrl(MSR_LX_DC_SPARE, msrval); 393 + 394 + gcfg = DC_GCFG_DFLE; /* Display fifo enable */ 395 + gcfg |= 0xB600; /* Set default priority */ 396 + gcfg |= DC_GCFG_FDTY; /* Set the frame dirty mode */ 397 + 398 + dcfg = DC_DCFG_VDEN; /* Enable video data */ 399 + dcfg |= DC_DCFG_GDEN; /* Enable graphics */ 400 + dcfg |= DC_DCFG_TGEN; /* Turn on the timing generator */ 401 + dcfg |= DC_DCFG_TRUP; /* Update timings immediately */ 402 + dcfg |= DC_DCFG_PALB; /* Palette bypass in > 8 bpp modes */ 403 + dcfg |= DC_DCFG_VISL; 404 + dcfg |= DC_DCFG_DCEN; /* Always center the display */ 405 + 406 + /* Set the current BPP mode */ 407 + 408 + switch (info->var.bits_per_pixel) { 409 + case 8: 410 + dcfg |= DC_DCFG_DISP_MODE_8BPP; 411 + break; 412 + 413 + case 16: 414 + dcfg |= DC_DCFG_DISP_MODE_16BPP | DC_DCFG_16BPP; 415 + break; 416 + 417 + case 32: 418 + case 24: 419 + dcfg |= DC_DCFG_DISP_MODE_24BPP; 420 + break; 421 + } 422 + 423 + /* Now - set up the timings */ 424 + 425 + hactive = info->var.xres; 426 + hblankstart = hactive; 427 + hsyncstart = hblankstart + info->var.right_margin; 428 + hsyncend = hsyncstart + info->var.hsync_len; 429 + hblankend = hsyncend + info->var.left_margin; 430 + htotal = hblankend; 431 + 432 + vactive = info->var.yres; 433 + vblankstart = vactive; 434 + vsyncstart = vblankstart + info->var.lower_margin; 435 + vsyncend = vsyncstart + info->var.vsync_len; 436 + vblankend = vsyncend + info->var.upper_margin; 437 + vtotal = vblankend; 438 + 439 + writel((hactive - 1) | ((htotal - 1) << 16), 440 + par->dc_regs + DC_H_ACTIVE_TIMING); 441 + writel((hblankstart - 1) | ((hblankend - 1) << 16), 442 + par->dc_regs + DC_H_BLANK_TIMING); 443 + writel((hsyncstart - 1) | ((hsyncend - 1) << 16), 444 + par->dc_regs + DC_H_SYNC_TIMING); 445 + 446 + writel((vactive - 1) | ((vtotal - 1) << 16), 447 + par->dc_regs + DC_V_ACTIVE_TIMING); 448 + 449 + writel((vblankstart - 1) | ((vblankend - 1) << 16), 450 + par->dc_regs + DC_V_BLANK_TIMING); 451 + 452 + writel((vsyncstart - 1) | ((vsyncend - 1) << 16), 453 + par->dc_regs + DC_V_SYNC_TIMING); 454 + 455 + writel( (info->var.xres - 1) << 16 | (info->var.yres - 1), 456 + par->dc_regs + DC_FB_ACTIVE); 457 + 458 + /* And re-enable the graphics output */ 459 + lx_graphics_enable(info); 460 + 461 + /* Write the two main configuration registers */ 462 + writel(dcfg, par->dc_regs + DC_DISPLAY_CFG); 463 + writel(0, par->dc_regs + DC_ARB_CFG); 464 + writel(gcfg, par->dc_regs + DC_GENERAL_CFG); 465 + 466 + /* Lock the DC registers */ 467 + writel(0, par->dc_regs + DC_UNLOCK); 468 + } 469 + 470 + void lx_set_palette_reg(struct fb_info *info, unsigned regno, 471 + unsigned red, unsigned green, unsigned blue) 472 + { 473 + struct lxfb_par *par = info->par; 474 + int val; 475 + 476 + /* Hardware palette is in RGB 8-8-8 format. */ 477 + 478 + val = (red << 8) & 0xff0000; 479 + val |= (green) & 0x00ff00; 480 + val |= (blue >> 8) & 0x0000ff; 481 + 482 + writel(regno, par->dc_regs + DC_PAL_ADDRESS); 483 + writel(val, par->dc_regs + DC_PAL_DATA); 484 + } 485 + 486 + int lx_blank_display(struct fb_info *info, int blank_mode) 487 + { 488 + struct lxfb_par *par = info->par; 489 + u32 dcfg, fp_pm; 490 + int blank, hsync, vsync; 491 + 492 + /* CRT power saving modes. */ 493 + switch (blank_mode) { 494 + case FB_BLANK_UNBLANK: 495 + blank = 0; hsync = 1; vsync = 1; 496 + break; 497 + case FB_BLANK_NORMAL: 498 + blank = 1; hsync = 1; vsync = 1; 499 + break; 500 + case FB_BLANK_VSYNC_SUSPEND: 501 + blank = 1; hsync = 1; vsync = 0; 502 + break; 503 + case FB_BLANK_HSYNC_SUSPEND: 504 + blank = 1; hsync = 0; vsync = 1; 505 + break; 506 + case FB_BLANK_POWERDOWN: 507 + blank = 1; hsync = 0; vsync = 0; 508 + break; 509 + default: 510 + return -EINVAL; 511 + } 512 + 513 + dcfg = readl(par->df_regs + DF_DISPLAY_CFG); 514 + dcfg &= ~(DF_DCFG_DAC_BL_EN 515 + | DF_DCFG_HSYNC_EN | DF_DCFG_VSYNC_EN); 516 + if (!blank) 517 + dcfg |= DF_DCFG_DAC_BL_EN; 518 + if (hsync) 519 + dcfg |= DF_DCFG_HSYNC_EN; 520 + if (vsync) 521 + dcfg |= DF_DCFG_VSYNC_EN; 522 + writel(dcfg, par->df_regs + DF_DISPLAY_CFG); 523 + 524 + /* Power on/off flat panel */ 525 + 526 + if (par->output & OUTPUT_PANEL) { 527 + fp_pm = readl(par->df_regs + DF_FP_PM); 528 + if (blank_mode == FB_BLANK_POWERDOWN) 529 + fp_pm &= ~DF_FP_PM_P; 530 + else 531 + fp_pm |= DF_FP_PM_P; 532 + writel(fp_pm, par->df_regs + DF_FP_PM); 533 + } 534 + 535 + return 0; 536 + }