0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/delay.h>
0011 #include <linux/errno.h>
0012 #include <linux/fb.h>
0013 #include <linux/interrupt.h>
0014 #include <linux/pci.h>
0015 #include <linux/slab.h>
0016 #include <linux/module.h>
0017
0018 #include "carminefb.h"
0019 #include "carminefb_regs.h"
0020
0021 #if !defined(__LITTLE_ENDIAN) && !defined(__BIG_ENDIAN)
0022 #error "The endianness of the target host has not been defined."
0023 #endif
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034 #define CARMINEFB_DEFAULT_VIDEO_MODE 1
0035
0036 static unsigned int fb_mode = CARMINEFB_DEFAULT_VIDEO_MODE;
0037 module_param(fb_mode, uint, 0444);
0038 MODULE_PARM_DESC(fb_mode, "Initial video mode as integer.");
0039
0040 static char *fb_mode_str;
0041 module_param(fb_mode_str, charp, 0444);
0042 MODULE_PARM_DESC(fb_mode_str, "Initial video mode in characters.");
0043
0044
0045
0046
0047
0048
0049
0050 static int fb_displays = CARMINE_USE_DISPLAY0 | CARMINE_USE_DISPLAY1;
0051 module_param(fb_displays, int, 0444);
0052 MODULE_PARM_DESC(fb_displays, "Bit mode, which displays are used");
0053
0054 struct carmine_hw {
0055 void __iomem *v_regs;
0056 void __iomem *screen_mem;
0057 struct fb_info *fb[MAX_DISPLAY];
0058 };
0059
0060 struct carmine_resolution {
0061 u32 htp;
0062 u32 hsp;
0063 u32 hsw;
0064 u32 hdp;
0065 u32 vtr;
0066 u32 vsp;
0067 u32 vsw;
0068 u32 vdp;
0069 u32 disp_mode;
0070 };
0071
0072 struct carmine_fb {
0073 void __iomem *display_reg;
0074 void __iomem *screen_base;
0075 u32 smem_offset;
0076 u32 cur_mode;
0077 u32 new_mode;
0078 struct carmine_resolution *res;
0079 u32 pseudo_palette[16];
0080 };
0081
0082 static struct fb_fix_screeninfo carminefb_fix = {
0083 .id = "Carmine",
0084 .type = FB_TYPE_PACKED_PIXELS,
0085 .visual = FB_VISUAL_TRUECOLOR,
0086 .accel = FB_ACCEL_NONE,
0087 };
0088
0089 static const struct fb_videomode carmine_modedb[] = {
0090 {
0091 .name = "640x480",
0092 .xres = 640,
0093 .yres = 480,
0094 }, {
0095 .name = "800x600",
0096 .xres = 800,
0097 .yres = 600,
0098 },
0099 };
0100
0101 static struct carmine_resolution car_modes[] = {
0102 {
0103
0104 .htp = 800,
0105 .hsp = 672,
0106 .hsw = 96,
0107 .hdp = 640,
0108 .vtr = 525,
0109 .vsp = 490,
0110 .vsw = 2,
0111 .vdp = 480,
0112 .disp_mode = 0x1400,
0113 },
0114 {
0115
0116 .htp = 1060,
0117 .hsp = 864,
0118 .hsw = 72,
0119 .hdp = 800,
0120 .vtr = 628,
0121 .vsp = 601,
0122 .vsw = 2,
0123 .vdp = 600,
0124 .disp_mode = 0x0d00,
0125 }
0126 };
0127
0128 static int carmine_find_mode(const struct fb_var_screeninfo *var)
0129 {
0130 int i;
0131
0132 for (i = 0; i < ARRAY_SIZE(car_modes); i++)
0133 if (car_modes[i].hdp == var->xres &&
0134 car_modes[i].vdp == var->yres)
0135 return i;
0136 return -EINVAL;
0137 }
0138
0139 static void c_set_disp_reg(const struct carmine_fb *par,
0140 u32 offset, u32 val)
0141 {
0142 writel(val, par->display_reg + offset);
0143 }
0144
0145 static u32 c_get_disp_reg(const struct carmine_fb *par,
0146 u32 offset)
0147 {
0148 return readl(par->display_reg + offset);
0149 }
0150
0151 static void c_set_hw_reg(const struct carmine_hw *hw,
0152 u32 offset, u32 val)
0153 {
0154 writel(val, hw->v_regs + offset);
0155 }
0156
0157 static u32 c_get_hw_reg(const struct carmine_hw *hw,
0158 u32 offset)
0159 {
0160 return readl(hw->v_regs + offset);
0161 }
0162
0163 static int carmine_setcolreg(unsigned regno, unsigned red, unsigned green,
0164 unsigned blue, unsigned transp, struct fb_info *info)
0165 {
0166 if (regno >= 16)
0167 return 1;
0168
0169 red >>= 8;
0170 green >>= 8;
0171 blue >>= 8;
0172 transp >>= 8;
0173
0174 ((__be32 *)info->pseudo_palette)[regno] = cpu_to_be32(transp << 24 |
0175 red << 0 | green << 8 | blue << 16);
0176 return 0;
0177 }
0178
0179 static int carmine_check_var(struct fb_var_screeninfo *var,
0180 struct fb_info *info)
0181 {
0182 int ret;
0183
0184 ret = carmine_find_mode(var);
0185 if (ret < 0)
0186 return ret;
0187
0188 if (var->grayscale || var->rotate || var->nonstd)
0189 return -EINVAL;
0190
0191 var->xres_virtual = var->xres;
0192 var->yres_virtual = var->yres;
0193
0194 var->bits_per_pixel = 32;
0195
0196 #ifdef __BIG_ENDIAN
0197 var->transp.offset = 24;
0198 var->red.offset = 0;
0199 var->green.offset = 8;
0200 var->blue.offset = 16;
0201 #else
0202 var->transp.offset = 24;
0203 var->red.offset = 16;
0204 var->green.offset = 8;
0205 var->blue.offset = 0;
0206 #endif
0207
0208 var->red.length = 8;
0209 var->green.length = 8;
0210 var->blue.length = 8;
0211 var->transp.length = 8;
0212
0213 var->red.msb_right = 0;
0214 var->green.msb_right = 0;
0215 var->blue.msb_right = 0;
0216 var->transp.msb_right = 0;
0217 return 0;
0218 }
0219
0220 static void carmine_init_display_param(struct carmine_fb *par)
0221 {
0222 u32 width;
0223 u32 height;
0224 u32 param;
0225 u32 window_size;
0226 u32 soffset = par->smem_offset;
0227
0228 c_set_disp_reg(par, CARMINE_DISP_REG_C_TRANS, 0);
0229 c_set_disp_reg(par, CARMINE_DISP_REG_MLMR_TRANS, 0);
0230 c_set_disp_reg(par, CARMINE_DISP_REG_CURSOR_MODE,
0231 CARMINE_CURSOR0_PRIORITY_MASK |
0232 CARMINE_CURSOR1_PRIORITY_MASK |
0233 CARMINE_CURSOR_CUTZ_MASK);
0234
0235
0236 c_set_disp_reg(par, CARMINE_DISP_REG_CUR1_POS, 0 << 16 | 0);
0237 c_set_disp_reg(par, CARMINE_DISP_REG_CUR2_POS, 0 << 16 | 0);
0238
0239
0240 c_set_disp_reg(par, CARMINE_DISP_REG_L0_EXT_MODE, CARMINE_WINDOW_MODE |
0241 CARMINE_EXT_CMODE_DIRECT24_RGBA);
0242 c_set_disp_reg(par, CARMINE_DISP_REG_L1_EXT_MODE,
0243 CARMINE_EXT_CMODE_DIRECT24_RGBA);
0244 c_set_disp_reg(par, CARMINE_DISP_REG_L2_EXT_MODE, CARMINE_EXTEND_MODE |
0245 CARMINE_EXT_CMODE_DIRECT24_RGBA);
0246 c_set_disp_reg(par, CARMINE_DISP_REG_L3_EXT_MODE, CARMINE_EXTEND_MODE |
0247 CARMINE_EXT_CMODE_DIRECT24_RGBA);
0248 c_set_disp_reg(par, CARMINE_DISP_REG_L4_EXT_MODE, CARMINE_EXTEND_MODE |
0249 CARMINE_EXT_CMODE_DIRECT24_RGBA);
0250 c_set_disp_reg(par, CARMINE_DISP_REG_L5_EXT_MODE, CARMINE_EXTEND_MODE |
0251 CARMINE_EXT_CMODE_DIRECT24_RGBA);
0252 c_set_disp_reg(par, CARMINE_DISP_REG_L6_EXT_MODE, CARMINE_EXTEND_MODE |
0253 CARMINE_EXT_CMODE_DIRECT24_RGBA);
0254 c_set_disp_reg(par, CARMINE_DISP_REG_L7_EXT_MODE, CARMINE_EXTEND_MODE |
0255 CARMINE_EXT_CMODE_DIRECT24_RGBA);
0256
0257
0258 width = par->res->hdp * 4 / CARMINE_DISP_WIDTH_UNIT;
0259 width = width << CARMINE_DISP_WIDTH_SHIFT;
0260
0261 height = par->res->vdp - 1;
0262 param = width | height;
0263
0264 c_set_disp_reg(par, CARMINE_DISP_REG_L0_MODE_W_H, param);
0265 c_set_disp_reg(par, CARMINE_DISP_REG_L1_WIDTH, width);
0266 c_set_disp_reg(par, CARMINE_DISP_REG_L2_MODE_W_H, param);
0267 c_set_disp_reg(par, CARMINE_DISP_REG_L3_MODE_W_H, param);
0268 c_set_disp_reg(par, CARMINE_DISP_REG_L4_MODE_W_H, param);
0269 c_set_disp_reg(par, CARMINE_DISP_REG_L5_MODE_W_H, param);
0270 c_set_disp_reg(par, CARMINE_DISP_REG_L6_MODE_W_H, param);
0271 c_set_disp_reg(par, CARMINE_DISP_REG_L7_MODE_W_H, param);
0272
0273
0274 window_size = (par->res->vdp - 1) << CARMINE_DISP_WIN_H_SHIFT;
0275 window_size |= par->res->hdp;
0276
0277 c_set_disp_reg(par, CARMINE_DISP_REG_L0_WIN_POS, 0);
0278 c_set_disp_reg(par, CARMINE_DISP_REG_L0_WIN_SIZE, window_size);
0279 c_set_disp_reg(par, CARMINE_DISP_REG_L1_WIN_POS, 0);
0280 c_set_disp_reg(par, CARMINE_DISP_REG_L1_WIN_SIZE, window_size);
0281 c_set_disp_reg(par, CARMINE_DISP_REG_L2_WIN_POS, 0);
0282 c_set_disp_reg(par, CARMINE_DISP_REG_L2_WIN_SIZE, window_size);
0283 c_set_disp_reg(par, CARMINE_DISP_REG_L3_WIN_POS, 0);
0284 c_set_disp_reg(par, CARMINE_DISP_REG_L3_WIN_SIZE, window_size);
0285 c_set_disp_reg(par, CARMINE_DISP_REG_L4_WIN_POS, 0);
0286 c_set_disp_reg(par, CARMINE_DISP_REG_L4_WIN_SIZE, window_size);
0287 c_set_disp_reg(par, CARMINE_DISP_REG_L5_WIN_POS, 0);
0288 c_set_disp_reg(par, CARMINE_DISP_REG_L5_WIN_SIZE, window_size);
0289 c_set_disp_reg(par, CARMINE_DISP_REG_L6_WIN_POS, 0);
0290 c_set_disp_reg(par, CARMINE_DISP_REG_L6_WIN_SIZE, window_size);
0291 c_set_disp_reg(par, CARMINE_DISP_REG_L7_WIN_POS, 0);
0292 c_set_disp_reg(par, CARMINE_DISP_REG_L7_WIN_SIZE, window_size);
0293
0294
0295 c_set_disp_reg(par, CARMINE_DISP_REG_L0_ORG_ADR, soffset);
0296 c_set_disp_reg(par, CARMINE_DISP_REG_L1_ORG_ADR, soffset);
0297 c_set_disp_reg(par, CARMINE_DISP_REG_L2_ORG_ADR1, soffset);
0298 c_set_disp_reg(par, CARMINE_DISP_REG_L3_ORG_ADR1, soffset);
0299 c_set_disp_reg(par, CARMINE_DISP_REG_L4_ORG_ADR1, soffset);
0300 c_set_disp_reg(par, CARMINE_DISP_REG_L5_ORG_ADR1, soffset);
0301 c_set_disp_reg(par, CARMINE_DISP_REG_L6_ORG_ADR1, soffset);
0302 c_set_disp_reg(par, CARMINE_DISP_REG_L7_ORG_ADR1, soffset);
0303
0304
0305 c_set_disp_reg(par, CARMINE_DISP_REG_L0_DISP_ADR, soffset);
0306 c_set_disp_reg(par, CARMINE_DISP_REG_L2_DISP_ADR1, soffset);
0307 c_set_disp_reg(par, CARMINE_DISP_REG_L3_DISP_ADR1, soffset);
0308 c_set_disp_reg(par, CARMINE_DISP_REG_L4_DISP_ADR1, soffset);
0309 c_set_disp_reg(par, CARMINE_DISP_REG_L5_DISP_ADR1, soffset);
0310 c_set_disp_reg(par, CARMINE_DISP_REG_L6_DISP_ADR0, soffset);
0311 c_set_disp_reg(par, CARMINE_DISP_REG_L7_DISP_ADR0, soffset);
0312
0313
0314 c_set_disp_reg(par, CARMINE_DISP_REG_L0_DISP_POS, 0);
0315 c_set_disp_reg(par, CARMINE_DISP_REG_L2_DISP_POS, 0);
0316 c_set_disp_reg(par, CARMINE_DISP_REG_L3_DISP_POS, 0);
0317 c_set_disp_reg(par, CARMINE_DISP_REG_L4_DISP_POS, 0);
0318 c_set_disp_reg(par, CARMINE_DISP_REG_L5_DISP_POS, 0);
0319 c_set_disp_reg(par, CARMINE_DISP_REG_L6_DISP_POS, 0);
0320 c_set_disp_reg(par, CARMINE_DISP_REG_L7_DISP_POS, 0);
0321
0322
0323 c_set_disp_reg(par, CARMINE_DISP_REG_BLEND_MODE_L0, 0);
0324 c_set_disp_reg(par, CARMINE_DISP_REG_BLEND_MODE_L1, 0);
0325 c_set_disp_reg(par, CARMINE_DISP_REG_BLEND_MODE_L2, 0);
0326 c_set_disp_reg(par, CARMINE_DISP_REG_BLEND_MODE_L3, 0);
0327 c_set_disp_reg(par, CARMINE_DISP_REG_BLEND_MODE_L4, 0);
0328 c_set_disp_reg(par, CARMINE_DISP_REG_BLEND_MODE_L5, 0);
0329 c_set_disp_reg(par, CARMINE_DISP_REG_BLEND_MODE_L6, 0);
0330 c_set_disp_reg(par, CARMINE_DISP_REG_BLEND_MODE_L7, 0);
0331
0332
0333 c_set_disp_reg(par, CARMINE_DISP_REG_L0_TRANS, 0);
0334 c_set_disp_reg(par, CARMINE_DISP_REG_L1_TRANS, 0);
0335 c_set_disp_reg(par, CARMINE_DISP_REG_L2_TRANS, 0);
0336 c_set_disp_reg(par, CARMINE_DISP_REG_L3_TRANS, 0);
0337 c_set_disp_reg(par, CARMINE_DISP_REG_L4_TRANS, 0);
0338 c_set_disp_reg(par, CARMINE_DISP_REG_L5_TRANS, 0);
0339 c_set_disp_reg(par, CARMINE_DISP_REG_L6_TRANS, 0);
0340 c_set_disp_reg(par, CARMINE_DISP_REG_L7_TRANS, 0);
0341
0342
0343 c_set_disp_reg(par, CARMINE_DISP_REG_L0RM, 0);
0344 c_set_disp_reg(par, CARMINE_DISP_REG_L2RM, 0);
0345 c_set_disp_reg(par, CARMINE_DISP_REG_L3RM, 0);
0346 c_set_disp_reg(par, CARMINE_DISP_REG_L4RM, 0);
0347 c_set_disp_reg(par, CARMINE_DISP_REG_L5RM, 0);
0348 c_set_disp_reg(par, CARMINE_DISP_REG_L6RM, 0);
0349 c_set_disp_reg(par, CARMINE_DISP_REG_L7RM, 0);
0350
0351 c_set_disp_reg(par, CARMINE_DISP_REG_L0PX, 0);
0352 c_set_disp_reg(par, CARMINE_DISP_REG_L2PX, 0);
0353 c_set_disp_reg(par, CARMINE_DISP_REG_L3PX, 0);
0354 c_set_disp_reg(par, CARMINE_DISP_REG_L4PX, 0);
0355 c_set_disp_reg(par, CARMINE_DISP_REG_L5PX, 0);
0356 c_set_disp_reg(par, CARMINE_DISP_REG_L6PX, 0);
0357 c_set_disp_reg(par, CARMINE_DISP_REG_L7PX, 0);
0358
0359 c_set_disp_reg(par, CARMINE_DISP_REG_L0PY, 0);
0360 c_set_disp_reg(par, CARMINE_DISP_REG_L2PY, 0);
0361 c_set_disp_reg(par, CARMINE_DISP_REG_L3PY, 0);
0362 c_set_disp_reg(par, CARMINE_DISP_REG_L4PY, 0);
0363 c_set_disp_reg(par, CARMINE_DISP_REG_L5PY, 0);
0364 c_set_disp_reg(par, CARMINE_DISP_REG_L6PY, 0);
0365 c_set_disp_reg(par, CARMINE_DISP_REG_L7PY, 0);
0366 }
0367
0368 static void set_display_parameters(struct carmine_fb *par)
0369 {
0370 u32 mode;
0371 u32 hdp, vdp, htp, hsp, hsw, vtr, vsp, vsw;
0372
0373
0374
0375
0376
0377 hdp = par->res->hdp - 1;
0378 vdp = par->res->vdp - 1;
0379 htp = par->res->htp - 1;
0380 hsp = par->res->hsp - 1;
0381 hsw = par->res->hsw - 1;
0382 vtr = par->res->vtr - 1;
0383 vsp = par->res->vsp - 1;
0384 vsw = par->res->vsw - 1;
0385
0386 c_set_disp_reg(par, CARMINE_DISP_REG_H_TOTAL,
0387 htp << CARMINE_DISP_HTP_SHIFT);
0388 c_set_disp_reg(par, CARMINE_DISP_REG_H_PERIOD,
0389 (hdp << CARMINE_DISP_HDB_SHIFT) | hdp);
0390 c_set_disp_reg(par, CARMINE_DISP_REG_V_H_W_H_POS,
0391 (vsw << CARMINE_DISP_VSW_SHIFT) |
0392 (hsw << CARMINE_DISP_HSW_SHIFT) |
0393 (hsp));
0394 c_set_disp_reg(par, CARMINE_DISP_REG_V_TOTAL,
0395 vtr << CARMINE_DISP_VTR_SHIFT);
0396 c_set_disp_reg(par, CARMINE_DISP_REG_V_PERIOD_POS,
0397 (vdp << CARMINE_DISP_VDP_SHIFT) | vsp);
0398
0399
0400 mode = c_get_disp_reg(par, CARMINE_DISP_REG_DCM1);
0401 mode = (mode & ~CARMINE_DISP_DCM_MASK) |
0402 (par->res->disp_mode & CARMINE_DISP_DCM_MASK);
0403
0404 mode |= CARMINE_DEN | CARMINE_L0E;
0405 c_set_disp_reg(par, CARMINE_DISP_REG_DCM1, mode);
0406 }
0407
0408 static int carmine_set_par(struct fb_info *info)
0409 {
0410 struct carmine_fb *par = info->par;
0411 int ret;
0412
0413 ret = carmine_find_mode(&info->var);
0414 if (ret < 0)
0415 return ret;
0416
0417 par->new_mode = ret;
0418 if (par->cur_mode != par->new_mode) {
0419
0420 par->cur_mode = par->new_mode;
0421 par->res = &car_modes[par->new_mode];
0422
0423 carmine_init_display_param(par);
0424 set_display_parameters(par);
0425 }
0426
0427 info->fix.line_length = info->var.xres * info->var.bits_per_pixel / 8;
0428 return 0;
0429 }
0430
0431 static int init_hardware(struct carmine_hw *hw)
0432 {
0433 u32 flags;
0434 u32 loops;
0435 u32 ret;
0436
0437
0438
0439 c_set_hw_reg(hw, CARMINE_CTL_REG + CARMINE_CTL_REG_CLOCK_ENABLE,
0440 CARMINE_DFLT_IP_CLOCK_ENABLE);
0441
0442
0443 c_set_hw_reg(hw, CARMINE_DISP0_REG + CARMINE_DISP_REG_DCM1, 0);
0444 c_set_hw_reg(hw, CARMINE_DISP1_REG + CARMINE_DISP_REG_DCM1, 0);
0445
0446
0447 c_set_hw_reg(hw, CARMINE_CTL_REG + CARMINE_CTL_REG_SOFTWARE_RESET, 1);
0448 c_set_hw_reg(hw, CARMINE_CTL_REG + CARMINE_CTL_REG_SOFTWARE_RESET, 0);
0449
0450
0451 flags = CARMINE_DFLT_IP_DCTL_IO_CONT1 << 16 |
0452 CARMINE_DFLT_IP_DCTL_IO_CONT0;
0453 c_set_hw_reg(hw, CARMINE_DCTL_REG + CARMINE_DCTL_REG_IOCONT1_IOCONT0,
0454 flags);
0455
0456
0457 flags = CARMINE_DFLT_IP_DCTL_MODE << 16 | CARMINE_DFLT_IP_DCTL_ADD;
0458 c_set_hw_reg(hw, CARMINE_DCTL_REG + CARMINE_DCTL_REG_MODE_ADD,
0459 flags);
0460
0461 flags = CARMINE_DFLT_IP_DCTL_SET_TIME1 << 16 |
0462 CARMINE_DFLT_IP_DCTL_EMODE;
0463 c_set_hw_reg(hw, CARMINE_DCTL_REG + CARMINE_DCTL_REG_SETTIME1_EMODE,
0464 flags);
0465
0466 flags = CARMINE_DFLT_IP_DCTL_REFRESH << 16 |
0467 CARMINE_DFLT_IP_DCTL_SET_TIME2;
0468 c_set_hw_reg(hw, CARMINE_DCTL_REG + CARMINE_DCTL_REG_REFRESH_SETTIME2,
0469 flags);
0470
0471 flags = CARMINE_DFLT_IP_DCTL_RESERVE2 << 16 |
0472 CARMINE_DFLT_IP_DCTL_FIFO_DEPTH;
0473 c_set_hw_reg(hw, CARMINE_DCTL_REG + CARMINE_DCTL_REG_RSV2_RSV1, flags);
0474
0475 flags = CARMINE_DFLT_IP_DCTL_DDRIF2 << 16 | CARMINE_DFLT_IP_DCTL_DDRIF1;
0476 c_set_hw_reg(hw, CARMINE_DCTL_REG + CARMINE_DCTL_REG_DDRIF2_DDRIF1,
0477 flags);
0478
0479 flags = CARMINE_DFLT_IP_DCTL_RESERVE0 << 16 |
0480 CARMINE_DFLT_IP_DCTL_STATES;
0481 c_set_hw_reg(hw, CARMINE_DCTL_REG + CARMINE_DCTL_REG_RSV0_STATES,
0482 flags);
0483
0484
0485 if (CARMINE_DCTL_DLL_RESET) {
0486 for (loops = 0; loops < CARMINE_DCTL_INIT_WAIT_LIMIT; loops++) {
0487
0488 ret = c_get_hw_reg(hw, CARMINE_DCTL_REG +
0489 CARMINE_DCTL_REG_RSV0_STATES);
0490 ret &= CARMINE_DCTL_REG_STATES_MASK;
0491 if (!ret)
0492 break;
0493
0494 mdelay(CARMINE_DCTL_INIT_WAIT_INTERVAL);
0495 }
0496
0497 if (loops >= CARMINE_DCTL_INIT_WAIT_LIMIT) {
0498 printk(KERN_ERR "DRAM init failed\n");
0499 return -EIO;
0500 }
0501 }
0502
0503 flags = CARMINE_DFLT_IP_DCTL_MODE_AFT_RST << 16 |
0504 CARMINE_DFLT_IP_DCTL_ADD;
0505 c_set_hw_reg(hw, CARMINE_DCTL_REG + CARMINE_DCTL_REG_MODE_ADD, flags);
0506
0507 flags = CARMINE_DFLT_IP_DCTL_RESERVE0 << 16 |
0508 CARMINE_DFLT_IP_DCTL_STATES_AFT_RST;
0509 c_set_hw_reg(hw, CARMINE_DCTL_REG + CARMINE_DCTL_REG_RSV0_STATES,
0510 flags);
0511
0512
0513 c_set_hw_reg(hw, CARMINE_WB_REG + CARMINE_WB_REG_WBM,
0514 CARMINE_WB_REG_WBM_DEFAULT);
0515
0516
0517 c_set_hw_reg(hw, CARMINE_GRAPH_REG + CARMINE_GRAPH_REG_VRINTM, 0);
0518 c_set_hw_reg(hw, CARMINE_GRAPH_REG + CARMINE_GRAPH_REG_VRERRM, 0);
0519
0520
0521 c_set_hw_reg(hw, CARMINE_GRAPH_REG + CARMINE_GRAPH_REG_DC_OFFSET_PX, 0);
0522 c_set_hw_reg(hw, CARMINE_GRAPH_REG + CARMINE_GRAPH_REG_DC_OFFSET_PY, 0);
0523 c_set_hw_reg(hw, CARMINE_GRAPH_REG + CARMINE_GRAPH_REG_DC_OFFSET_LX, 0);
0524 c_set_hw_reg(hw, CARMINE_GRAPH_REG + CARMINE_GRAPH_REG_DC_OFFSET_LY, 0);
0525 c_set_hw_reg(hw, CARMINE_GRAPH_REG + CARMINE_GRAPH_REG_DC_OFFSET_TX, 0);
0526 c_set_hw_reg(hw, CARMINE_GRAPH_REG + CARMINE_GRAPH_REG_DC_OFFSET_TY, 0);
0527 return 0;
0528 }
0529
0530 static const struct fb_ops carminefb_ops = {
0531 .owner = THIS_MODULE,
0532 .fb_fillrect = cfb_fillrect,
0533 .fb_copyarea = cfb_copyarea,
0534 .fb_imageblit = cfb_imageblit,
0535
0536 .fb_check_var = carmine_check_var,
0537 .fb_set_par = carmine_set_par,
0538 .fb_setcolreg = carmine_setcolreg,
0539 };
0540
0541 static int alloc_carmine_fb(void __iomem *regs, void __iomem *smem_base,
0542 int smem_offset, struct device *device,
0543 struct fb_info **rinfo)
0544 {
0545 int ret;
0546 struct fb_info *info;
0547 struct carmine_fb *par;
0548
0549 info = framebuffer_alloc(sizeof *par, device);
0550 if (!info)
0551 return -ENOMEM;
0552
0553 par = info->par;
0554 par->display_reg = regs;
0555 par->smem_offset = smem_offset;
0556
0557 info->screen_base = smem_base + smem_offset;
0558 info->screen_size = CARMINE_DISPLAY_MEM;
0559 info->fbops = &carminefb_ops;
0560
0561 info->fix = carminefb_fix;
0562 info->pseudo_palette = par->pseudo_palette;
0563 info->flags = FBINFO_DEFAULT;
0564
0565 ret = fb_alloc_cmap(&info->cmap, 256, 1);
0566 if (ret < 0)
0567 goto err_free_fb;
0568
0569 if (fb_mode >= ARRAY_SIZE(carmine_modedb))
0570 fb_mode = CARMINEFB_DEFAULT_VIDEO_MODE;
0571
0572 par->cur_mode = par->new_mode = ~0;
0573
0574 ret = fb_find_mode(&info->var, info, fb_mode_str, carmine_modedb,
0575 ARRAY_SIZE(carmine_modedb),
0576 &carmine_modedb[fb_mode], 32);
0577 if (!ret || ret == 4) {
0578 ret = -EINVAL;
0579 goto err_dealloc_cmap;
0580 }
0581
0582 fb_videomode_to_modelist(carmine_modedb, ARRAY_SIZE(carmine_modedb),
0583 &info->modelist);
0584
0585 ret = register_framebuffer(info);
0586 if (ret < 0)
0587 goto err_dealloc_cmap;
0588
0589 fb_info(info, "%s frame buffer device\n", info->fix.id);
0590
0591 *rinfo = info;
0592 return 0;
0593
0594 err_dealloc_cmap:
0595 fb_dealloc_cmap(&info->cmap);
0596 err_free_fb:
0597 framebuffer_release(info);
0598 return ret;
0599 }
0600
0601 static void cleanup_fb_device(struct fb_info *info)
0602 {
0603 if (info) {
0604 unregister_framebuffer(info);
0605 fb_dealloc_cmap(&info->cmap);
0606 framebuffer_release(info);
0607 }
0608 }
0609
0610 static int carminefb_probe(struct pci_dev *dev, const struct pci_device_id *ent)
0611 {
0612 struct carmine_hw *hw;
0613 struct device *device = &dev->dev;
0614 struct fb_info *info;
0615 int ret;
0616
0617 ret = pci_enable_device(dev);
0618 if (ret)
0619 return ret;
0620
0621 ret = -ENOMEM;
0622 hw = kzalloc(sizeof *hw, GFP_KERNEL);
0623 if (!hw)
0624 goto err_enable_pci;
0625
0626 carminefb_fix.mmio_start = pci_resource_start(dev, CARMINE_CONFIG_BAR);
0627 carminefb_fix.mmio_len = pci_resource_len(dev, CARMINE_CONFIG_BAR);
0628
0629 if (!request_mem_region(carminefb_fix.mmio_start,
0630 carminefb_fix.mmio_len,
0631 "carminefb regbase")) {
0632 printk(KERN_ERR "carminefb: Can't reserve regbase.\n");
0633 ret = -EBUSY;
0634 goto err_free_hw;
0635 }
0636 hw->v_regs = ioremap(carminefb_fix.mmio_start,
0637 carminefb_fix.mmio_len);
0638 if (!hw->v_regs) {
0639 printk(KERN_ERR "carminefb: Can't remap %s register.\n",
0640 carminefb_fix.id);
0641 goto err_free_reg_mmio;
0642 }
0643
0644 carminefb_fix.smem_start = pci_resource_start(dev, CARMINE_MEMORY_BAR);
0645 carminefb_fix.smem_len = pci_resource_len(dev, CARMINE_MEMORY_BAR);
0646
0647
0648
0649
0650
0651 if (carminefb_fix.smem_len > CARMINE_TOTAL_DIPLAY_MEM)
0652 carminefb_fix.smem_len = CARMINE_TOTAL_DIPLAY_MEM;
0653
0654 else if (carminefb_fix.smem_len < CARMINE_TOTAL_DIPLAY_MEM) {
0655 printk(KERN_ERR "carminefb: Memory bar is only %d bytes, %d "
0656 "are required.", carminefb_fix.smem_len,
0657 CARMINE_TOTAL_DIPLAY_MEM);
0658 goto err_unmap_vregs;
0659 }
0660
0661 if (!request_mem_region(carminefb_fix.smem_start,
0662 carminefb_fix.smem_len, "carminefb smem")) {
0663 printk(KERN_ERR "carminefb: Can't reserve smem.\n");
0664 goto err_unmap_vregs;
0665 }
0666
0667 hw->screen_mem = ioremap(carminefb_fix.smem_start,
0668 carminefb_fix.smem_len);
0669 if (!hw->screen_mem) {
0670 printk(KERN_ERR "carmine: Can't ioremap smem area.\n");
0671 goto err_reg_smem;
0672 }
0673
0674 ret = init_hardware(hw);
0675 if (ret)
0676 goto err_unmap_screen;
0677
0678 info = NULL;
0679 if (fb_displays & CARMINE_USE_DISPLAY0) {
0680 ret = alloc_carmine_fb(hw->v_regs + CARMINE_DISP0_REG,
0681 hw->screen_mem, CARMINE_DISPLAY_MEM * 0,
0682 device, &info);
0683 if (ret)
0684 goto err_deinit_hw;
0685 }
0686
0687 hw->fb[0] = info;
0688
0689 info = NULL;
0690 if (fb_displays & CARMINE_USE_DISPLAY1) {
0691 ret = alloc_carmine_fb(hw->v_regs + CARMINE_DISP1_REG,
0692 hw->screen_mem, CARMINE_DISPLAY_MEM * 1,
0693 device, &info);
0694 if (ret)
0695 goto err_cleanup_fb0;
0696 }
0697
0698 hw->fb[1] = info;
0699 info = NULL;
0700
0701 pci_set_drvdata(dev, hw);
0702 return 0;
0703
0704 err_cleanup_fb0:
0705 cleanup_fb_device(hw->fb[0]);
0706 err_deinit_hw:
0707
0708 c_set_hw_reg(hw, CARMINE_CTL_REG + CARMINE_CTL_REG_CLOCK_ENABLE, 0);
0709 err_unmap_screen:
0710 iounmap(hw->screen_mem);
0711 err_reg_smem:
0712 release_mem_region(carminefb_fix.smem_start, carminefb_fix.smem_len);
0713 err_unmap_vregs:
0714 iounmap(hw->v_regs);
0715 err_free_reg_mmio:
0716 release_mem_region(carminefb_fix.mmio_start, carminefb_fix.mmio_len);
0717 err_free_hw:
0718 kfree(hw);
0719 err_enable_pci:
0720 pci_disable_device(dev);
0721 return ret;
0722 }
0723
0724 static void carminefb_remove(struct pci_dev *dev)
0725 {
0726 struct carmine_hw *hw = pci_get_drvdata(dev);
0727 struct fb_fix_screeninfo fix;
0728 int i;
0729
0730
0731 if (hw->fb[0])
0732 fix = hw->fb[0]->fix;
0733 else
0734 fix = hw->fb[1]->fix;
0735
0736
0737 c_set_hw_reg(hw, CARMINE_DISP0_REG + CARMINE_DISP_REG_DCM1, 0);
0738 c_set_hw_reg(hw, CARMINE_DISP1_REG + CARMINE_DISP_REG_DCM1, 0);
0739 c_set_hw_reg(hw, CARMINE_CTL_REG + CARMINE_CTL_REG_CLOCK_ENABLE, 0);
0740
0741 for (i = 0; i < MAX_DISPLAY; i++)
0742 cleanup_fb_device(hw->fb[i]);
0743
0744 iounmap(hw->screen_mem);
0745 release_mem_region(fix.smem_start, fix.smem_len);
0746 iounmap(hw->v_regs);
0747 release_mem_region(fix.mmio_start, fix.mmio_len);
0748
0749 pci_disable_device(dev);
0750 kfree(hw);
0751 }
0752
0753 #define PCI_VENDOR_ID_FUJITU_LIMITED 0x10cf
0754 static struct pci_device_id carmine_devices[] = {
0755 {
0756 PCI_DEVICE(PCI_VENDOR_ID_FUJITU_LIMITED, 0x202b)},
0757 {0, 0, 0, 0, 0, 0, 0}
0758 };
0759
0760 MODULE_DEVICE_TABLE(pci, carmine_devices);
0761
0762 static struct pci_driver carmine_pci_driver = {
0763 .name = "carminefb",
0764 .id_table = carmine_devices,
0765 .probe = carminefb_probe,
0766 .remove = carminefb_remove,
0767 };
0768
0769 static int __init carminefb_init(void)
0770 {
0771 if (!(fb_displays &
0772 (CARMINE_USE_DISPLAY0 | CARMINE_USE_DISPLAY1))) {
0773 printk(KERN_ERR "If you disable both displays than you don't "
0774 "need the driver at all\n");
0775 return -EINVAL;
0776 }
0777 return pci_register_driver(&carmine_pci_driver);
0778 }
0779 module_init(carminefb_init);
0780
0781 static void __exit carminefb_cleanup(void)
0782 {
0783 pci_unregister_driver(&carmine_pci_driver);
0784 }
0785 module_exit(carminefb_cleanup);
0786
0787 MODULE_AUTHOR("Sebastian Siewior <bigeasy@linutronix.de>");
0788 MODULE_DESCRIPTION("Framebuffer driver for Fujitsu Carmine based devices");
0789 MODULE_LICENSE("GPL v2");