Lynx framebuffers multidomain implementation.
[linux/elbrus.git] / drivers / video / lynxfb / lynx_hw750.c
blob7e81288c516d7778c52ea148d231574245bfbe98
1 /*******************************************************************
2 *Copyright (c) 2012 by Silicon Motion, Inc. (SMI)
3 *Permission is hereby granted, free of charge, to any person obtaining a copy
4 *of this software and associated documentation files (the "Software"), to deal
5 *in the Software without restriction, including without limitation the rights to
6 *use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
7 *of the Software, and to permit persons to whom the Software is furnished to
8 *do so, subject to the following conditions:
10 *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
11 *EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
12 *OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
13 *NONINFRINGEMENT. IN NO EVENT SHALL Mill.Chen and Monk.Liu OR COPYRIGHT
14 *HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
15 *WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
16 *FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
17 *OTHER DEALINGS IN THE SOFTWARE.
18 *******************************************************************/
19 #include<linux/version.h>
20 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 10)
21 #include<linux/config.h>
22 #endif
23 #include <linux/version.h>
24 #include<linux/module.h>
25 #include<linux/kernel.h>
26 #include<linux/errno.h>
27 #include<linux/string.h>
28 #include<linux/mm.h>
29 #include<linux/slab.h>
30 #include<linux/delay.h>
31 #include<linux/fb.h>
32 #include<linux/ioport.h>
33 #include<linux/init.h>
34 #include<linux/pci.h>
35 #include<linux/vmalloc.h>
36 #include<linux/pagemap.h>
37 #include <linux/console.h>
38 #ifdef CONFIG_MTRR
39 #include <asm/mtrr.h>
40 #endif
42 #ifdef CONFIG_FB_LYNXFB_DOMAINS
43 #include <asm-l/iolinkmask.h>
44 #endif
46 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10)
47 /* no below two header files in 2.6.9 */
48 #include<linux/platform_device.h>
49 #include<linux/screen_info.h>
50 #else
51 /* nothing by far */
52 #endif
54 #include "lynx_drv.h"
55 #include "lynx_hw750.h"
56 #include "ddk750.h"
57 #include "lynx_accel.h"
59 int hw_sm750_map(struct lynx_share *share, struct pci_dev *pdev)
61 int ret;
62 struct sm750_share *spec_share;
64 #ifdef CONFIG_FB_LYNXFB_DOMAINS
65 int domain;
66 #endif /* CONFIG_FB_LYNXFB_DOMAINS */
68 ENTER();
70 spec_share = container_of(share, struct sm750_share, share);
71 ret = 0;
73 share->vidreg_start = pci_resource_start(pdev, 1);
74 share->vidreg_size = MB(2);
76 /* reserve the vidreg space of smi adaptor
77 * if you do this, u need to add release region code
78 * in lynxfb_remove, or memory will not be mapped again
79 * successfully
80 * */
83 /* now map mmio and vidmem */
84 share->pvReg =
85 ioremap_nocache(share->vidreg_start, share->vidreg_size);
86 if (!share->pvReg) {
87 err_msg("mmio failed\n");
88 ret = -EFAULT;
89 goto exit;
92 share->accel.dprBase = share->pvReg + DE_BASE_ADDR_TYPE1;
93 share->accel.dpPortBase = share->pvReg + DE_PORT_ADDR_TYPE1;
94 #ifdef CONFIG_FB_LYNXFB_DOMAINS
95 domain = pci_domain_nr(pdev->bus);
96 ddk750_set_mmio(share->pvReg, share->devid, share->revid, domain);
97 #else
98 ddk750_set_mmio(share->pvReg, share->devid, share->revid);
99 #endif /* CONFIG_FB_LYNXFB_DOMAINS */
101 share->vidmem_start = pci_resource_start(pdev, 0);
102 /* don't use pdev_resource[x].end - resource[x].start to
103 * calculate the resource size, its only the maximum available
104 * size but not the actual size, use
105 * @hw_sm750_getVMSize function can be safe.
106 * */
107 #ifdef CONFIG_FB_LYNXFB_DOMAINS
108 share->vidmem_size = hw_sm750_getVMSize(share, domain);
109 #else
110 share->vidmem_size = hw_sm750_getVMSize(share);
111 #endif /* CONFIG_FB_LYNXFB_DOMAINS */
112 inf_msg("video memory size = %lld mb\n", share->vidmem_size >> 20);
114 /* reserve the vidmem space of smi adaptor */
116 share->pvMem = ioremap(share->vidmem_start, share->vidmem_size);
118 if (!share->pvMem) {
119 err_msg("Map video memory failed\n");
120 ret = -EFAULT;
121 goto exit;
124 inf_msg("video memory vaddr = %p\n", share->pvMem);
125 exit:
126 LEAVE(ret);
129 #ifdef CONFIG_FB_LYNXFB_DOMAINS
131 int hw_sm750_inithw(struct lynx_share *share, struct pci_dev *pdev)
133 struct sm750_share *spec_share;
134 struct init_status *parm;
135 int domain;
137 ENTER();
139 domain = pci_domain_nr(pdev->bus);
141 spec_share = container_of(share, struct sm750_share, share);
142 parm = &spec_share->state.initParm;
143 if (parm->chip_clk == 0)
144 parm->chip_clk = (getChipType(domain) == SM750LE) ?
145 DEFAULT_SM750LE_CHIP_CLOCK : DEFAULT_SM750_CHIP_CLOCK;
147 if (parm->mem_clk == 0)
148 parm->mem_clk = parm->chip_clk;
149 if (parm->master_clk == 0)
150 parm->master_clk = parm->chip_clk / 3;
152 ddk750_initHw((initchip_param_t *) & spec_share->state.initParm,
153 domain);
154 /* for sm718, open pci burst */
155 if (share->devid == 0x718) {
156 POKE32(SYSTEM_CTRL,
157 PEEK32(SYSTEM_CTRL, domain) | (1 <<
158 SYSTEM_CTRL_PCI_BURST_LSB), domain);
161 /* sm750 use sii164, it can be setup with default value
162 * by on power, so initDVIDisp can be skipped */
164 if (getChipType(domain) != SM750LE) {
165 /* does user need CRT ? */
166 if (spec_share->state.nocrt) {
167 POKE32(MISC_CTRL,
168 PEEK32(MISC_CTRL, domain) |
169 (1 << MISC_CTRL_DAC_POWER_LSB), domain);
170 /* shut off dpms */
171 POKE32(SYSTEM_CTRL,
172 PEEK32(SYSTEM_CTRL, domain) |
173 (3 << SYSTEM_CTRL_DPMS_LSB), domain);
174 } else {
175 POKE32(MISC_CTRL,
176 PEEK32(MISC_CTRL, domain) &
177 (~(1 << MISC_CTRL_DAC_POWER_LSB)), domain);
178 /* turn on dpms */
179 POKE32(SYSTEM_CTRL,
180 PEEK32(SYSTEM_CTRL, domain) &
181 (~(3 << SYSTEM_CTRL_DPMS_LSB)), domain);
184 switch (spec_share->state.pnltype) {
185 case sm750_doubleTFT:
186 case sm750_24TFT:
187 case sm750_dualTFT:
188 POKE32(PANEL_DISPLAY_CTRL,
189 PEEK32(PANEL_DISPLAY_CTRL, domain) &
190 (~(3 << PANEL_DISPLAY_CTRL_TFT_DISP_LSB)),
191 domain);
192 POKE32(PANEL_DISPLAY_CTRL,
193 PEEK32(PANEL_DISPLAY_CTRL, domain) |
194 (spec_share->state.
195 pnltype <<
196 PANEL_DISPLAY_CTRL_TFT_DISP_LSB), domain);
197 break;
199 } else {
200 /* for 750LE , no DVI chip initilization makes Monitor no signal */
201 /* Set up GPIO for software I2C to program DVI chip in the
202 Xilinx SP605 board, in order to have video signal.
204 swI2CInit(0, 1, domain);
207 /* Customer may NOT use CH7301 DVI chip, which has to be
208 initialized differently.
210 if (swI2CReadReg(0xec, 0x4a, domain) == 0x95) {
211 /* The following register values for CH7301 are from
212 Chrontel app note and our experiment.
214 inf_msg("yes, CH7301 DVI chip found\n");
215 swI2CWriteReg(0xec, 0x1d, 0x16, domain);
216 swI2CWriteReg(0xec, 0x21, 0x9, domain);
217 swI2CWriteReg(0xec, 0x49, 0xC0, domain);
218 inf_msg("okay, CH7301 DVI chip setup done\n");
222 /* init 2d engine */
223 if (!share->accel_off) {
224 hw_sm750_initAccel(share, domain);
227 LEAVE(0);
230 resource_size_t hw_sm750_getVMSize(struct lynx_share *share, int domain)
232 resource_size_t ret;
233 ENTER();
234 ret = ddk750_getVMSize(domain);
235 LEAVE(ret);
240 int hw_sm750_output_checkMode(struct lynxfb_output *output,
241 struct fb_var_screeninfo *var, int domain)
243 ENTER();
244 LEAVE(0);
248 int hw_sm750_output_setMode(struct lynxfb_output *output,
249 struct fb_var_screeninfo *var,
250 struct fb_fix_screeninfo *fix,
251 int domain)
253 int ret;
254 disp_output_t dispSet;
255 int channel;
256 ENTER();
257 ret = 0;
258 dispSet = 0;
259 channel = *output->channel;
262 if (getChipType(domain) != SM750LE) {
263 if (channel == sm750_primary) {
264 inf_msg("primary channel\n");
265 if (output->paths & sm750_panel)
266 dispSet |= do_LCD1_PRI;
267 if (output->paths & sm750_crt)
268 dispSet |= do_CRT_PRI;
270 } else {
271 inf_msg("secondary channel\n");
272 if (output->paths & sm750_panel)
273 dispSet |= do_LCD1_SEC;
274 if (output->paths & sm750_crt)
275 dispSet |= do_CRT_SEC;
278 ddk750_setLogicalDispOut(dispSet, domain);
279 } else {
280 /* just open DISPLAY_CONTROL_750LE register bit 3:0 */
281 u32 reg;
282 reg = PEEK32(DISPLAY_CONTROL_750LE, domain);
283 reg |= 0xf;
284 POKE32(DISPLAY_CONTROL_750LE, reg, domain);
287 inf_msg("ddk setlogicdispout done \n");
288 LEAVE(ret);
291 void hw_sm750_output_clear(struct lynxfb_output *output, int domain)
293 ENTER();
294 LEAVE();
297 int hw_sm750_crtc_checkMode(struct lynxfb_crtc *crtc,
298 struct fb_var_screeninfo *var, int domain)
300 struct lynx_share *share;
301 ENTER();
303 share = container_of(crtc, struct lynxfb_par, crtc)->share;
305 switch (var->bits_per_pixel) {
306 case 8:
307 case 16:
308 break;
309 case 32:
310 if (share->revid == (unsigned char) SM750LE_REVISION_ID) {
311 dbg_msg("750le do not support 32bpp\n");
312 LEAVE(-EINVAL);
314 break;
315 default:
316 LEAVE(-EINVAL);
320 LEAVE(0);
325 set the controller's mode for @crtc charged with @var and @fix parameters
327 int hw_sm750_crtc_setMode(struct lynxfb_crtc *crtc,
328 struct fb_var_screeninfo *var,
329 struct fb_fix_screeninfo *fix, int domain)
331 int ret, fmt;
332 u32 reg;
333 mode_parameter_t modparm;
334 clock_type_t clock;
335 struct lynx_share *share;
336 struct lynxfb_par *par;
338 ENTER();
339 ret = 0;
340 par = container_of(crtc, struct lynxfb_par, crtc);
341 share = par->share;
343 if (!share->accel_off) {
344 /* set 2d engine pixel format according to mode bpp */
345 switch (var->bits_per_pixel) {
346 case 8:
347 fmt = 0;
348 break;
349 case 16:
350 fmt = 1;
351 break;
352 case 32:
353 default:
354 fmt = 2;
355 break;
357 hw_set2dformat(&share->accel, fmt);
361 /* set timing */
362 modparm.pixel_clock = ps_to_hz(var->pixclock);
363 modparm.vertical_sync_polarity =
364 (var->sync & FB_SYNC_HOR_HIGH_ACT) ? POS : NEG;
365 modparm.horizontal_sync_polarity =
366 (var->sync & FB_SYNC_VERT_HIGH_ACT) ? POS : NEG;
367 modparm.clock_phase_polarity =
368 (var->sync & FB_SYNC_COMP_HIGH_ACT) ? POS : NEG;
369 modparm.horizontal_display_end = var->xres;
370 modparm.horizontal_sync_width = var->hsync_len;
371 modparm.horizontal_sync_start = var->xres + var->right_margin;
372 modparm.horizontal_total =
373 var->xres + var->left_margin + var->right_margin +
374 var->hsync_len;
375 modparm.vertical_display_end = var->yres;
376 modparm.vertical_sync_height = var->vsync_len;
377 modparm.vertical_sync_start = var->yres + var->lower_margin;
378 modparm.vertical_total =
379 var->yres + var->upper_margin + var->lower_margin +
380 var->vsync_len;
382 /* choose pll */
383 if (crtc->channel != sm750_secondary)
384 clock = PRIMARY_PLL;
385 else
386 clock = SECONDARY_PLL;
388 dbg_msg("Request pixel clock = %lu\n", modparm.pixel_clock);
389 ret = ddk750_setModeTiming(&modparm, clock, domain);
390 if (ret) {
391 err_msg("Set mode timing failed\n");
392 goto exit;
395 if (crtc->channel != sm750_secondary) {
396 /* set pitch, offset , width, start address , etc... */
397 POKE32(PANEL_FB_ADDRESS,
398 crtc->oScreen << PANEL_FB_ADDRESS_ADDRESS_LSB, domain);
399 reg = var->xres * (var->bits_per_pixel >> 3);
400 /* crtc->channel is not equal to par->index on numeric, be aware of that */
401 reg = PADDING(crtc->line_pad, reg);
402 POKE32(PANEL_FB_WIDTH,
403 (reg << PANEL_FB_WIDTH_WIDTH_LSB) |
404 (fix->line_length << PANEL_FB_WIDTH_OFFSET_LSB),
405 domain);
407 POKE32(PANEL_WINDOW_WIDTH,
408 ((var->xres - 1) << PANEL_WINDOW_WIDTH_WIDTH_LSB) |
409 (var->xoffset << PANEL_WINDOW_WIDTH_X_LSB),
410 domain);
412 POKE32(PANEL_WINDOW_HEIGHT,
413 ((var->yres_virtual - 1) << PANEL_WINDOW_HEIGHT_HEIGHT_LSB) |
414 (var->yoffset << PANEL_WINDOW_HEIGHT_Y_LSB),
415 domain);
417 POKE32(PANEL_PLANE_TL, 0, domain);
419 POKE32(PANEL_PLANE_BR,
420 ((var->yres - 1) << PANEL_PLANE_BR_BOTTOM_LSB) |
421 ((var->xres - 1) << PANEL_PLANE_BR_RIGHT_LSB),
422 domain);
424 /* set pixel format */
425 reg = PEEK32(PANEL_DISPLAY_CTRL, domain);
426 POKE32(PANEL_DISPLAY_CTRL,
427 (reg & (~(3 << PANEL_DISPLAY_CTRL_FORMAT_LSB))) |
428 ((var->bits_per_pixel >> 4) <<
429 PANEL_DISPLAY_CTRL_FORMAT_LSB),
430 domain);
431 } else {
432 /* not implemented now */
433 POKE32(CRT_FB_ADDRESS, crtc->oScreen, domain);
434 reg = var->xres * (var->bits_per_pixel >> 3);
435 /* crtc->channel is not equal to par->index on numeric, be aware of that */
436 reg = PADDING(crtc->line_pad, reg);
437 POKE32(CRT_FB_WIDTH,
438 (reg << CRT_FB_WIDTH_WIDTH_LSB) |
439 (fix->line_length << CRT_FB_WIDTH_OFFSET_LSB), domain);
441 /* SET PIXEL FORMAT */
442 reg = PEEK32(CRT_DISPLAY_CTRL, domain);
443 reg |=
444 (var->
445 bits_per_pixel >> 4) << CRT_DISPLAY_CTRL_FORMAT_LSB;
446 POKE32(CRT_DISPLAY_CTRL, reg, domain);
450 exit:
451 LEAVE(ret);
454 void hw_sm750_crtc_clear(struct lynxfb_crtc *crtc, int domain)
456 ENTER();
457 LEAVE();
460 int hw_sm750_setColReg(struct lynxfb_crtc *crtc, ushort index,
461 ushort red, ushort green, ushort blue, int domain)
463 static unsigned int add[] = { PANEL_PALETTE_RAM, CRT_PALETTE_RAM };
464 POKE32(add[crtc->channel] + index * 4,
465 (red << 16) | (green << 8) | blue, domain);
466 return 0;
469 int hw_sm750le_setBLANK(struct lynxfb_output *output, int blank, int domain)
471 int dpms, crtdb;
472 ENTER();
473 switch (blank) {
474 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10)
475 case FB_BLANK_UNBLANK:
476 #else
477 case VESA_NO_BLANKING:
478 #endif
479 dpms = CRT_DISPLAY_CTRL_DPMS_0;
480 crtdb = CRT_DISPLAY_CTRL_BLANK_OFF;
481 break;
482 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10)
483 case FB_BLANK_NORMAL:
484 dpms = CRT_DISPLAY_CTRL_DPMS_0;
485 crtdb = CRT_DISPLAY_CTRL_BLANK_ON;
486 break;
487 #endif
488 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10)
489 case FB_BLANK_VSYNC_SUSPEND:
490 #else
491 case VESA_VSYNC_SUSPEND:
492 #endif
493 dpms = CRT_DISPLAY_CTRL_DPMS_2;
494 crtdb = CRT_DISPLAY_CTRL_BLANK_ON;
495 break;
496 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10)
497 case FB_BLANK_HSYNC_SUSPEND:
498 #else
499 case VESA_HSYNC_SUSPEND:
500 #endif
501 dpms = CRT_DISPLAY_CTRL_DPMS_1;
502 crtdb = CRT_DISPLAY_CTRL_BLANK_ON;
503 break;
504 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10)
505 case FB_BLANK_POWERDOWN:
506 #else
507 case VESA_POWERDOWN:
508 #endif
509 dpms = CRT_DISPLAY_CTRL_DPMS_3;
510 crtdb = CRT_DISPLAY_CTRL_BLANK_ON;
511 break;
512 default:
513 LEAVE(-1);
516 if (output->paths & sm750_crt) {
517 POKE32(CRT_DISPLAY_CTRL,
518 (PEEK32(CRT_DISPLAY_CTRL, domain) &
519 (~(3 << CRT_DISPLAY_CTRL_DPMS_LSB))) | (dpms <<
520 CRT_DISPLAY_CTRL_DPMS_LSB), domain);
521 POKE32(CRT_DISPLAY_CTRL,
522 (PEEK32(CRT_DISPLAY_CTRL, domain) &
523 (~(1 << CRT_DISPLAY_CTRL_BLANK_LSB))) | (crtdb <<
524 CRT_DISPLAY_CTRL_BLANK_LSB), domain);
526 LEAVE(0);
529 int hw_sm750_setBLANK(struct lynxfb_output *output, int blank, int domain)
531 unsigned int dpms, pps, crtdb;
532 ENTER();
533 dpms = pps = crtdb = 0;
535 switch (blank) {
536 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10)
537 case FB_BLANK_UNBLANK:
538 #else
539 case VESA_NO_BLANKING:
540 #endif
541 dbg_msg("flag = FB_BLANK_UNBLANK \n");
542 dpms = SYSTEM_CTRL_DPMS_VPHP;
543 pps = PANEL_DISPLAY_CTRL_DATA_ENABLE;
544 crtdb = CRT_DISPLAY_CTRL_BLANK_OFF;
545 break;
546 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10)
547 case FB_BLANK_NORMAL:
548 dbg_msg("flag = FB_BLANK_NORMAL \n");
549 dpms = SYSTEM_CTRL_DPMS_VPHP;
550 pps = PANEL_DISPLAY_CTRL_DATA_DISABLE;
551 crtdb = CRT_DISPLAY_CTRL_BLANK_ON;
552 break;
553 #endif
554 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10)
555 case FB_BLANK_VSYNC_SUSPEND:
556 #else
557 case VESA_VSYNC_SUSPEND:
558 #endif
559 dpms = SYSTEM_CTRL_DPMS_VNHP;
560 pps = PANEL_DISPLAY_CTRL_DATA_DISABLE;
561 crtdb = CRT_DISPLAY_CTRL_BLANK_ON;
562 break;
563 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10)
564 case FB_BLANK_HSYNC_SUSPEND:
565 #else
566 case VESA_HSYNC_SUSPEND:
567 #endif
568 dpms = SYSTEM_CTRL_DPMS_VPHN;
569 pps = PANEL_DISPLAY_CTRL_DATA_DISABLE;
570 crtdb = CRT_DISPLAY_CTRL_BLANK_ON;
571 break;
572 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10)
573 case FB_BLANK_POWERDOWN:
574 #else
575 case VESA_POWERDOWN:
576 #endif
577 dpms = SYSTEM_CTRL_DPMS_VNHN;
578 pps = PANEL_DISPLAY_CTRL_DATA_DISABLE;
579 crtdb = CRT_DISPLAY_CTRL_BLANK_ON;
580 break;
583 if (output->paths & sm750_crt) {
584 POKE32(SYSTEM_CTRL,
585 (PEEK32(SYSTEM_CTRL, domain) & (~(3 << SYSTEM_CTRL_DPMS_LSB)))
586 | (dpms << SYSTEM_CTRL_DPMS_LSB), domain);
587 POKE32(CRT_DISPLAY_CTRL,
588 (PEEK32(CRT_DISPLAY_CTRL, domain) &
589 (~(1 << CRT_DISPLAY_CTRL_BLANK_LSB)))
590 | (crtdb << CRT_DISPLAY_CTRL_BLANK_LSB), domain);
593 if (output->paths & sm750_panel) {
594 POKE32(PANEL_DISPLAY_CTRL,
595 (PEEK32(PANEL_DISPLAY_CTRL, domain) &
596 (~(1 << PANEL_DISPLAY_CTRL_DATA_LSB)))
597 | (pps << PANEL_DISPLAY_CTRL_DATA_LSB), domain);
600 LEAVE(0);
604 void hw_sm750_initAccel(struct lynx_share *share, int domain)
606 u32 reg;
607 enable2DEngine(1, domain);
609 if (getChipType(domain) == SM750LE) {
610 reg = PEEK32(DE_STATE1, domain);
611 reg |= 1 << DE_STATE1_DE_ABORT_LSB;
612 POKE32(DE_STATE1, reg, domain);
614 reg = PEEK32(DE_STATE1, domain);
615 reg &= ~(1 << DE_STATE1_DE_ABORT_LSB);
616 POKE32(DE_STATE1, reg, domain);
618 } else {
619 /* engine reset */
620 reg = PEEK32(SYSTEM_CTRL, domain);
621 reg |= 1 << SYSTEM_CTRL_DE_ABORT_LSB;
622 POKE32(SYSTEM_CTRL, reg, domain);
624 reg = PEEK32(SYSTEM_CTRL, domain);
625 reg &= ~(1 << SYSTEM_CTRL_DE_ABORT_LSB);
626 POKE32(SYSTEM_CTRL, reg, domain);
629 /* call 2d init */
630 share->accel.de_init(&share->accel);
633 int hw_sm750le_deWait(int domain)
635 int i = 0x10000000;
636 while (i--) {
637 unsigned int dwVal = PEEK32(DE_STATE2, domain);
638 if (((1 & (dwVal >> DE_STATE2_DE_STATUS_LSB)) ==
639 DE_STATE2_DE_STATUS_IDLE)
640 && ((1 & (dwVal >> DE_STATE2_DE_FIFO_LSB)) ==
641 DE_STATE2_DE_FIFO_EMPTY)
642 && ((1 & (dwVal >> DE_STATE2_DE_MEM_FIFO_LSB)) ==
643 DE_STATE2_DE_MEM_FIFO_EMPTY)) {
644 return 0;
647 /* timeout error */
648 return -1;
652 int hw_sm750_deWait(int domain)
654 int i = 0x10000000;
655 while (i--) {
656 unsigned int dwVal = PEEK32(SYSTEM_CTRL, domain);
657 if (((1 & (dwVal >> SYSTEM_CTRL_DE_STATUS_LSB)) ==
658 SYSTEM_CTRL_DE_STATUS_IDLE)
659 && ((1 & (dwVal >> SYSTEM_CTRL_DE_FIFO_LSB)) ==
660 SYSTEM_CTRL_DE_FIFO_EMPTY)
661 && ((1 & (dwVal >> SYSTEM_CTRL_DE_MEM_FIFO_LSB)) ==
662 SYSTEM_CTRL_DE_MEM_FIFO_EMPTY)) {
663 return 0;
666 /* timeout error */
667 return -1;
670 int hw_sm750_pan_display(struct lynxfb_crtc *crtc,
671 const struct fb_var_screeninfo *var,
672 const struct fb_info *info,
673 int domain)
675 uint32_t total;
676 if ((var->xoffset + var->xres > var->xres_virtual) ||
677 (var->yoffset + var->yres > var->yres_virtual)) {
678 return -EINVAL;
681 total = var->yoffset * info->fix.line_length +
682 ((var->xoffset * var->bits_per_pixel) >> 3);
683 total += crtc->oScreen;
684 if (crtc->channel == sm750_primary) {
685 POKE32(PANEL_FB_ADDRESS,
686 (PEEK32(PANEL_FB_ADDRESS, domain) &
687 (~(0x3ffffff << PANEL_FB_ADDRESS_ADDRESS_LSB))) |
688 (total << PANEL_FB_ADDRESS_ADDRESS_LSB), domain);
689 } else {
690 POKE32(CRT_FB_ADDRESS,
691 (PEEK32(CRT_FB_ADDRESS, domain) &
692 (~(0x3ffffff << CRT_FB_ADDRESS_ADDRESS_LSB))) |
693 (total << CRT_FB_ADDRESS_ADDRESS_LSB), domain);
695 return 0;
697 #else /* !CONFIG_FB_LYNXFB_DOMAINS: */
699 int hw_sm750_inithw(struct lynx_share *share, struct pci_dev *pdev)
701 struct sm750_share *spec_share;
702 struct init_status *parm;
704 ENTER();
706 spec_share = container_of(share, struct sm750_share, share);
707 parm = &spec_share->state.initParm;
708 if (parm->chip_clk == 0)
709 parm->chip_clk = (getChipType() == SM750LE) ?
710 DEFAULT_SM750LE_CHIP_CLOCK : DEFAULT_SM750_CHIP_CLOCK;
712 if (parm->mem_clk == 0)
713 parm->mem_clk = parm->chip_clk;
714 if (parm->master_clk == 0)
715 parm->master_clk = parm->chip_clk / 3;
717 ddk750_initHw((initchip_param_t *) & spec_share->state.initParm);
718 /* for sm718, open pci burst */
719 if (share->devid == 0x718) {
720 POKE32(SYSTEM_CTRL,
721 PEEK32(SYSTEM_CTRL) | (1 <<
722 SYSTEM_CTRL_PCI_BURST_LSB));
725 /* sm750 use sii164, it can be setup with default value
726 * by on power, so initDVIDisp can be skipped */
728 if (getChipType() != SM750LE) {
729 /* does user need CRT ? */
730 if (spec_share->state.nocrt) {
731 POKE32(MISC_CTRL,
732 PEEK32(MISC_CTRL) |
733 (1 << MISC_CTRL_DAC_POWER_LSB));
734 /* shut off dpms */
735 POKE32(SYSTEM_CTRL,
736 PEEK32(SYSTEM_CTRL) |
737 (3 << SYSTEM_CTRL_DPMS_LSB));
738 } else {
739 POKE32(MISC_CTRL,
740 PEEK32(MISC_CTRL) &
741 (~(1 << MISC_CTRL_DAC_POWER_LSB)));
742 /* turn on dpms */
743 POKE32(SYSTEM_CTRL,
744 PEEK32(SYSTEM_CTRL) &
745 (~(3 << SYSTEM_CTRL_DPMS_LSB)));
748 switch (spec_share->state.pnltype) {
749 case sm750_doubleTFT:
750 case sm750_24TFT:
751 case sm750_dualTFT:
752 POKE32(PANEL_DISPLAY_CTRL,
753 PEEK32(PANEL_DISPLAY_CTRL) &
754 (~(3 << PANEL_DISPLAY_CTRL_TFT_DISP_LSB)));
755 POKE32(PANEL_DISPLAY_CTRL,
756 PEEK32(PANEL_DISPLAY_CTRL) |
757 (spec_share->state.
758 pnltype <<
759 PANEL_DISPLAY_CTRL_TFT_DISP_LSB));
760 break;
762 } else {
763 /* for 750LE , no DVI chip initilization makes Monitor no signal */
764 /* Set up GPIO for software I2C to program DVI chip in the
765 Xilinx SP605 board, in order to have video signal.
767 swI2CInit(0, 1);
770 /* Customer may NOT use CH7301 DVI chip, which has to be
771 initialized differently.
773 if (swI2CReadReg(0xec, 0x4a) == 0x95) {
774 /* The following register values for CH7301 are from
775 Chrontel app note and our experiment.
777 inf_msg("yes, CH7301 DVI chip found\n");
778 swI2CWriteReg(0xec, 0x1d, 0x16);
779 swI2CWriteReg(0xec, 0x21, 0x9);
780 swI2CWriteReg(0xec, 0x49, 0xC0);
781 inf_msg("okay, CH7301 DVI chip setup done\n");
785 /* init 2d engine */
786 if (!share->accel_off) {
787 hw_sm750_initAccel(share);
790 LEAVE(0);
793 resource_size_t hw_sm750_getVMSize(struct lynx_share *share)
795 resource_size_t ret;
796 ENTER();
797 ret = ddk750_getVMSize();
798 LEAVE(ret);
803 int hw_sm750_output_checkMode(struct lynxfb_output *output,
804 struct fb_var_screeninfo *var)
806 ENTER();
807 LEAVE(0);
811 int hw_sm750_output_setMode(struct lynxfb_output *output,
812 struct fb_var_screeninfo *var,
813 struct fb_fix_screeninfo *fix)
815 int ret;
816 disp_output_t dispSet;
817 int channel;
818 ENTER();
819 ret = 0;
820 dispSet = 0;
821 channel = *output->channel;
824 if (getChipType() != SM750LE) {
825 if (channel == sm750_primary) {
826 inf_msg("primary channel\n");
827 if (output->paths & sm750_panel)
828 dispSet |= do_LCD1_PRI;
829 if (output->paths & sm750_crt)
830 dispSet |= do_CRT_PRI;
832 } else {
833 inf_msg("secondary channel\n");
834 if (output->paths & sm750_panel)
835 dispSet |= do_LCD1_SEC;
836 if (output->paths & sm750_crt)
837 dispSet |= do_CRT_SEC;
840 ddk750_setLogicalDispOut(dispSet);
841 } else {
842 /* just open DISPLAY_CONTROL_750LE register bit 3:0 */
843 u32 reg;
844 reg = PEEK32(DISPLAY_CONTROL_750LE);
845 reg |= 0xf;
846 POKE32(DISPLAY_CONTROL_750LE, reg);
849 inf_msg("ddk setlogicdispout done \n");
850 LEAVE(ret);
853 void hw_sm750_output_clear(struct lynxfb_output *output)
855 ENTER();
856 LEAVE();
859 int hw_sm750_crtc_checkMode(struct lynxfb_crtc *crtc,
860 struct fb_var_screeninfo *var)
862 struct lynx_share *share;
863 ENTER();
865 share = container_of(crtc, struct lynxfb_par, crtc)->share;
867 switch (var->bits_per_pixel) {
868 case 8:
869 case 16:
870 break;
871 case 32:
872 if (share->revid == (unsigned char) SM750LE_REVISION_ID) {
873 dbg_msg("750le do not support 32bpp\n");
874 LEAVE(-EINVAL);
876 break;
877 default:
878 LEAVE(-EINVAL);
882 LEAVE(0);
887 set the controller's mode for @crtc charged with @var and @fix parameters
889 int hw_sm750_crtc_setMode(struct lynxfb_crtc *crtc,
890 struct fb_var_screeninfo *var,
891 struct fb_fix_screeninfo *fix)
893 int ret, fmt;
894 u32 reg;
895 mode_parameter_t modparm;
896 clock_type_t clock;
897 struct lynx_share *share;
898 struct lynxfb_par *par;
900 ENTER();
901 ret = 0;
902 par = container_of(crtc, struct lynxfb_par, crtc);
903 share = par->share;
905 if (!share->accel_off) {
906 /* set 2d engine pixel format according to mode bpp */
907 switch (var->bits_per_pixel) {
908 case 8:
909 fmt = 0;
910 break;
911 case 16:
912 fmt = 1;
913 break;
914 case 32:
915 default:
916 fmt = 2;
917 break;
919 hw_set2dformat(&share->accel, fmt);
923 /* set timing */
924 modparm.pixel_clock = ps_to_hz(var->pixclock);
925 modparm.vertical_sync_polarity =
926 (var->sync & FB_SYNC_HOR_HIGH_ACT) ? POS : NEG;
927 modparm.horizontal_sync_polarity =
928 (var->sync & FB_SYNC_VERT_HIGH_ACT) ? POS : NEG;
929 modparm.clock_phase_polarity =
930 (var->sync & FB_SYNC_COMP_HIGH_ACT) ? POS : NEG;
931 modparm.horizontal_display_end = var->xres;
932 modparm.horizontal_sync_width = var->hsync_len;
933 modparm.horizontal_sync_start = var->xres + var->right_margin;
934 modparm.horizontal_total =
935 var->xres + var->left_margin + var->right_margin +
936 var->hsync_len;
937 modparm.vertical_display_end = var->yres;
938 modparm.vertical_sync_height = var->vsync_len;
939 modparm.vertical_sync_start = var->yres + var->lower_margin;
940 modparm.vertical_total =
941 var->yres + var->upper_margin + var->lower_margin +
942 var->vsync_len;
944 /* choose pll */
945 if (crtc->channel != sm750_secondary)
946 clock = PRIMARY_PLL;
947 else
948 clock = SECONDARY_PLL;
950 dbg_msg("Request pixel clock = %lu\n", modparm.pixel_clock);
951 ret = ddk750_setModeTiming(&modparm, clock);
952 if (ret) {
953 err_msg("Set mode timing failed\n");
954 goto exit;
957 if (crtc->channel != sm750_secondary) {
958 /* set pitch, offset , width, start address , etc... */
959 POKE32(PANEL_FB_ADDRESS,
960 crtc->oScreen << PANEL_FB_ADDRESS_ADDRESS_LSB);
961 reg = var->xres * (var->bits_per_pixel >> 3);
962 /* crtc->channel is not equal to par->index on numeric, be aware of that */
963 reg = PADDING(crtc->line_pad, reg);
964 POKE32(PANEL_FB_WIDTH,
965 (reg << PANEL_FB_WIDTH_WIDTH_LSB) |
966 (fix->line_length << PANEL_FB_WIDTH_OFFSET_LSB));
968 POKE32(PANEL_WINDOW_WIDTH,
969 ((var->xres - 1) << PANEL_WINDOW_WIDTH_WIDTH_LSB) |
970 (var->xoffset << PANEL_WINDOW_WIDTH_X_LSB));
972 POKE32(PANEL_WINDOW_HEIGHT,
973 ((var->yres_virtual - 1) << PANEL_WINDOW_HEIGHT_HEIGHT_LSB) |
974 (var->yoffset << PANEL_WINDOW_HEIGHT_Y_LSB));
976 POKE32(PANEL_PLANE_TL, 0);
978 POKE32(PANEL_PLANE_BR,
979 ((var->yres - 1) << PANEL_PLANE_BR_BOTTOM_LSB) |
980 ((var->xres - 1) << PANEL_PLANE_BR_RIGHT_LSB));
982 /* set pixel format */
983 reg = PEEK32(PANEL_DISPLAY_CTRL);
984 POKE32(PANEL_DISPLAY_CTRL,
985 (reg & (~(3 << PANEL_DISPLAY_CTRL_FORMAT_LSB))) |
986 ((var->bits_per_pixel >> 4) <<
987 PANEL_DISPLAY_CTRL_FORMAT_LSB));
988 } else {
989 /* not implemented now */
990 POKE32(CRT_FB_ADDRESS, crtc->oScreen);
991 reg = var->xres * (var->bits_per_pixel >> 3);
992 /* crtc->channel is not equal to par->index on numeric, be aware of that */
993 reg = PADDING(crtc->line_pad, reg);
994 POKE32(CRT_FB_WIDTH,
995 (reg << CRT_FB_WIDTH_WIDTH_LSB) |
996 (fix->line_length << CRT_FB_WIDTH_OFFSET_LSB));
998 /* SET PIXEL FORMAT */
999 reg = PEEK32(CRT_DISPLAY_CTRL);
1000 reg |=
1001 (var->
1002 bits_per_pixel >> 4) << CRT_DISPLAY_CTRL_FORMAT_LSB;
1003 POKE32(CRT_DISPLAY_CTRL, reg);
1007 exit:
1008 LEAVE(ret);
1011 void hw_sm750_crtc_clear(struct lynxfb_crtc *crtc)
1013 ENTER();
1014 LEAVE();
1017 int hw_sm750_setColReg(struct lynxfb_crtc *crtc, ushort index,
1018 ushort red, ushort green, ushort blue)
1020 static unsigned int add[] = { PANEL_PALETTE_RAM, CRT_PALETTE_RAM };
1021 POKE32(add[crtc->channel] + index * 4,
1022 (red << 16) | (green << 8) | blue);
1023 return 0;
1026 int hw_sm750le_setBLANK(struct lynxfb_output *output, int blank)
1028 int dpms, crtdb;
1029 ENTER();
1030 switch (blank) {
1031 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10)
1032 case FB_BLANK_UNBLANK:
1033 #else
1034 case VESA_NO_BLANKING:
1035 #endif
1036 dpms = CRT_DISPLAY_CTRL_DPMS_0;
1037 crtdb = CRT_DISPLAY_CTRL_BLANK_OFF;
1038 break;
1039 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10)
1040 case FB_BLANK_NORMAL:
1041 dpms = CRT_DISPLAY_CTRL_DPMS_0;
1042 crtdb = CRT_DISPLAY_CTRL_BLANK_ON;
1043 break;
1044 #endif
1045 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10)
1046 case FB_BLANK_VSYNC_SUSPEND:
1047 #else
1048 case VESA_VSYNC_SUSPEND:
1049 #endif
1050 dpms = CRT_DISPLAY_CTRL_DPMS_2;
1051 crtdb = CRT_DISPLAY_CTRL_BLANK_ON;
1052 break;
1053 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10)
1054 case FB_BLANK_HSYNC_SUSPEND:
1055 #else
1056 case VESA_HSYNC_SUSPEND:
1057 #endif
1058 dpms = CRT_DISPLAY_CTRL_DPMS_1;
1059 crtdb = CRT_DISPLAY_CTRL_BLANK_ON;
1060 break;
1061 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10)
1062 case FB_BLANK_POWERDOWN:
1063 #else
1064 case VESA_POWERDOWN:
1065 #endif
1066 dpms = CRT_DISPLAY_CTRL_DPMS_3;
1067 crtdb = CRT_DISPLAY_CTRL_BLANK_ON;
1068 break;
1069 default:
1070 LEAVE(-1);
1073 if (output->paths & sm750_crt) {
1074 POKE32(CRT_DISPLAY_CTRL,
1075 (PEEK32(CRT_DISPLAY_CTRL) &
1076 (~(3 << CRT_DISPLAY_CTRL_DPMS_LSB))) | (dpms <<
1077 CRT_DISPLAY_CTRL_DPMS_LSB));
1078 POKE32(CRT_DISPLAY_CTRL,
1079 (PEEK32(CRT_DISPLAY_CTRL) &
1080 (~(1 << CRT_DISPLAY_CTRL_BLANK_LSB))) | (crtdb <<
1081 CRT_DISPLAY_CTRL_BLANK_LSB));
1083 LEAVE(0);
1086 int hw_sm750_setBLANK(struct lynxfb_output *output, int blank)
1088 unsigned int dpms, pps, crtdb;
1089 ENTER();
1090 dpms = pps = crtdb = 0;
1092 switch (blank) {
1093 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10)
1094 case FB_BLANK_UNBLANK:
1095 #else
1096 case VESA_NO_BLANKING:
1097 #endif
1098 dbg_msg("flag = FB_BLANK_UNBLANK \n");
1099 dpms = SYSTEM_CTRL_DPMS_VPHP;
1100 pps = PANEL_DISPLAY_CTRL_DATA_ENABLE;
1101 crtdb = CRT_DISPLAY_CTRL_BLANK_OFF;
1102 break;
1103 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10)
1104 case FB_BLANK_NORMAL:
1105 dbg_msg("flag = FB_BLANK_NORMAL \n");
1106 dpms = SYSTEM_CTRL_DPMS_VPHP;
1107 pps = PANEL_DISPLAY_CTRL_DATA_DISABLE;
1108 crtdb = CRT_DISPLAY_CTRL_BLANK_ON;
1109 break;
1110 #endif
1111 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10)
1112 case FB_BLANK_VSYNC_SUSPEND:
1113 #else
1114 case VESA_VSYNC_SUSPEND:
1115 #endif
1116 dpms = SYSTEM_CTRL_DPMS_VNHP;
1117 pps = PANEL_DISPLAY_CTRL_DATA_DISABLE;
1118 crtdb = CRT_DISPLAY_CTRL_BLANK_ON;
1119 break;
1120 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10)
1121 case FB_BLANK_HSYNC_SUSPEND:
1122 #else
1123 case VESA_HSYNC_SUSPEND:
1124 #endif
1125 dpms = SYSTEM_CTRL_DPMS_VPHN;
1126 pps = PANEL_DISPLAY_CTRL_DATA_DISABLE;
1127 crtdb = CRT_DISPLAY_CTRL_BLANK_ON;
1128 break;
1129 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10)
1130 case FB_BLANK_POWERDOWN:
1131 #else
1132 case VESA_POWERDOWN:
1133 #endif
1134 dpms = SYSTEM_CTRL_DPMS_VNHN;
1135 pps = PANEL_DISPLAY_CTRL_DATA_DISABLE;
1136 crtdb = CRT_DISPLAY_CTRL_BLANK_ON;
1137 break;
1140 if (output->paths & sm750_crt) {
1141 POKE32(SYSTEM_CTRL,
1142 (PEEK32(SYSTEM_CTRL) & (~(3 << SYSTEM_CTRL_DPMS_LSB)))
1143 | (dpms << SYSTEM_CTRL_DPMS_LSB));
1144 POKE32(CRT_DISPLAY_CTRL,
1145 (PEEK32(CRT_DISPLAY_CTRL) &
1146 (~(1 << CRT_DISPLAY_CTRL_BLANK_LSB)))
1147 | (crtdb << CRT_DISPLAY_CTRL_BLANK_LSB));
1150 if (output->paths & sm750_panel) {
1151 POKE32(PANEL_DISPLAY_CTRL,
1152 (PEEK32(PANEL_DISPLAY_CTRL) &
1153 (~(1 << PANEL_DISPLAY_CTRL_DATA_LSB)))
1154 | (pps << PANEL_DISPLAY_CTRL_DATA_LSB));
1157 LEAVE(0);
1161 void hw_sm750_initAccel(struct lynx_share *share)
1163 u32 reg;
1164 enable2DEngine(1);
1166 if (getChipType() == SM750LE) {
1167 reg = PEEK32(DE_STATE1);
1168 reg |= 1 << DE_STATE1_DE_ABORT_LSB;
1169 POKE32(DE_STATE1, reg);
1171 reg = PEEK32(DE_STATE1);
1172 reg &= ~(1 << DE_STATE1_DE_ABORT_LSB);
1173 POKE32(DE_STATE1, reg);
1175 } else {
1176 /* engine reset */
1177 reg = PEEK32(SYSTEM_CTRL);
1178 reg |= 1 << SYSTEM_CTRL_DE_ABORT_LSB;
1179 POKE32(SYSTEM_CTRL, reg);
1181 reg = PEEK32(SYSTEM_CTRL);
1182 reg &= ~(1 << SYSTEM_CTRL_DE_ABORT_LSB);
1183 POKE32(SYSTEM_CTRL, reg);
1186 /* call 2d init */
1187 share->accel.de_init(&share->accel);
1190 int hw_sm750le_deWait()
1192 int i = 0x10000000;
1193 while (i--) {
1194 unsigned int dwVal = PEEK32(DE_STATE2);
1195 if (((1 & (dwVal >> DE_STATE2_DE_STATUS_LSB)) ==
1196 DE_STATE2_DE_STATUS_IDLE)
1197 && ((1 & (dwVal >> DE_STATE2_DE_FIFO_LSB)) ==
1198 DE_STATE2_DE_FIFO_EMPTY)
1199 && ((1 & (dwVal >> DE_STATE2_DE_MEM_FIFO_LSB)) ==
1200 DE_STATE2_DE_MEM_FIFO_EMPTY)) {
1201 return 0;
1204 /* timeout error */
1205 return -1;
1209 int hw_sm750_deWait()
1211 int i = 0x10000000;
1212 while (i--) {
1213 unsigned int dwVal = PEEK32(SYSTEM_CTRL);
1214 if (((1 & (dwVal >> SYSTEM_CTRL_DE_STATUS_LSB)) ==
1215 SYSTEM_CTRL_DE_STATUS_IDLE)
1216 && ((1 & (dwVal >> SYSTEM_CTRL_DE_FIFO_LSB)) ==
1217 SYSTEM_CTRL_DE_FIFO_EMPTY)
1218 && ((1 & (dwVal >> SYSTEM_CTRL_DE_MEM_FIFO_LSB)) ==
1219 SYSTEM_CTRL_DE_MEM_FIFO_EMPTY)) {
1220 return 0;
1223 /* timeout error */
1224 return -1;
1227 int hw_sm750_pan_display(struct lynxfb_crtc *crtc,
1228 const struct fb_var_screeninfo *var,
1229 const struct fb_info *info)
1231 uint32_t total;
1232 if ((var->xoffset + var->xres > var->xres_virtual) ||
1233 (var->yoffset + var->yres > var->yres_virtual)) {
1234 return -EINVAL;
1237 total = var->yoffset * info->fix.line_length +
1238 ((var->xoffset * var->bits_per_pixel) >> 3);
1239 total += crtc->oScreen;
1240 if (crtc->channel == sm750_primary) {
1241 POKE32(PANEL_FB_ADDRESS,
1242 (PEEK32(PANEL_FB_ADDRESS) &
1243 (~(0x3ffffff << PANEL_FB_ADDRESS_ADDRESS_LSB))) |
1244 (total << PANEL_FB_ADDRESS_ADDRESS_LSB));
1245 } else {
1246 POKE32(CRT_FB_ADDRESS,
1247 (PEEK32(CRT_FB_ADDRESS) &
1248 (~(0x3ffffff << CRT_FB_ADDRESS_ADDRESS_LSB))) |
1249 (total << CRT_FB_ADDRESS_ADDRESS_LSB));
1251 return 0;
1253 #endif /* !CONFIG_FB_LYNXFB_DOMAINS */