20 #include <linux/module.h>
21 #include <linux/kernel.h>
22 #include <linux/errno.h>
23 #include <linux/string.h>
24 #include <linux/slab.h>
45 #define INT_VSYNC 0x01
46 #define INT_VSYNC_WB 0x02
47 #define INT_UNDRUN 0x04
48 #define INT_PARERR 0x08
49 #define INT_LS_BF_VS 0x10
313 static char *fb_mode;
314 static unsigned long default_bpp = 32;
315 static enum fsl_diu_monitor_port monitor_port;
316 static char *monitor_string;
318 #if defined(CONFIG_NOT_COHERENT_CACHE)
319 static u8 *coherence_data;
320 static size_t coherence_data_size;
321 static unsigned int d_cache_line_size;
384 #define DMA_ADDR(p, f) ((p)->dma_addr + offsetof(struct fsl_diu_data, f))
447 static enum fsl_diu_monitor_port fsl_diu_name_to_port(
const char *
s)
449 enum fsl_diu_monitor_port
port = FSL_DIU_PORT_DVI;
454 port = (
enum fsl_diu_monitor_port) val;
455 else if (
strncmp(s,
"lvds", 4) == 0)
456 port = FSL_DIU_PORT_LVDS;
457 else if (
strncmp(s,
"dlvds", 5) == 0)
458 port = FSL_DIU_PORT_DLVDS;
461 return diu_ops.valid_monitor_port(port);
475 static void fsl_diu_enable_panel(
struct fb_info *
info)
478 struct diu_ad *ad = mfbi->
ad;
482 switch (mfbi->
index) {
484 if (hw->desc[0] != ad->paddr)
488 cmfbi = &data->
mfb[2];
489 if (hw->desc[1] != ad->paddr) {
490 if (cmfbi->
count > 0)
499 cmfbi = &data->
mfb[4];
500 if (hw->desc[2] != ad->paddr) {
501 if (cmfbi->
count > 0)
510 pmfbi = &data->
mfb[1];
512 if (hw->desc[1] == data->dummy_ad.paddr)
518 pmfbi = &data->
mfb[3];
520 if (hw->desc[2] == data->dummy_ad.paddr)
528 static void fsl_diu_disable_panel(
struct fb_info *info)
531 struct diu_ad *ad = mfbi->
ad;
535 switch (mfbi->
index) {
537 if (hw->desc[0] != data->dummy_ad.paddr)
538 wr_reg_wa(&hw->desc[0], data->dummy_ad.paddr);
541 cmfbi = &data->
mfb[2];
542 if (cmfbi->
count > 0)
546 wr_reg_wa(&hw->desc[1], data->dummy_ad.paddr);
550 cmfbi = &data->
mfb[4];
551 if (cmfbi->
count > 0)
555 wr_reg_wa(&hw->desc[2], data->dummy_ad.paddr);
559 pmfbi = &data->
mfb[1];
560 if (hw->desc[1] != ad->paddr) {
562 if (pmfbi->
count > 0)
564 pmfbi->
ad->next_ad = 0;
566 wr_reg_wa(&hw->desc[1], data->dummy_ad.paddr);
570 pmfbi = &data->
mfb[3];
571 if (hw->desc[2] != ad->paddr) {
573 if (pmfbi->
count > 0)
575 pmfbi->
ad->next_ad = 0;
577 wr_reg_wa(&hw->desc[2], data->dummy_ad.paddr);
583 static void enable_lcdc(
struct fb_info *info)
592 static void disable_lcdc(
struct fb_info *info)
604 struct mfb_info *lower_aoi_mfbi, *upper_aoi_mfbi, *mfbi = info->
par;
606 int available_height, upper_aoi_bottom;
608 int lower_aoi_is_open, upper_aoi_is_open;
609 __u32 base_plane_width, base_plane_height, upper_aoi_height;
628 lower_aoi_is_open = lower_aoi_mfbi->
count > 0 ? 1 : 0;
629 if (var->
xres > base_plane_width)
630 var->
xres = base_plane_width;
631 if ((mfbi->
x_aoi_d + var->
xres) > base_plane_width)
634 if (lower_aoi_is_open)
635 available_height = lower_aoi_mfbi->
y_aoi_d;
637 available_height = base_plane_height;
638 if (var->
yres > available_height)
639 var->
yres = available_height;
640 if ((mfbi->
y_aoi_d + var->
yres) > available_height)
646 upper_aoi_height = data->
fsl_diu_info[index-1].var.yres;
647 upper_aoi_bottom = upper_aoi_mfbi->
y_aoi_d + upper_aoi_height;
648 upper_aoi_is_open = upper_aoi_mfbi->
count > 0 ? 1 : 0;
649 if (var->
xres > base_plane_width)
650 var->
xres = base_plane_width;
651 if ((mfbi->
x_aoi_d + var->
xres) > base_plane_width)
655 if (upper_aoi_is_open) {
656 if (mfbi->
y_aoi_d < upper_aoi_bottom)
657 mfbi->
y_aoi_d = upper_aoi_bottom;
658 available_height = base_plane_height
661 available_height = base_plane_height;
662 if (var->
yres > available_height)
663 var->
yres = available_height;
664 if ((mfbi->
y_aoi_d + var->
yres) > base_plane_height)
703 var->
red.offset = 11;
704 var->
red.msb_right = 0;
706 var->
green.length = 6;
707 var->
green.offset = 5;
708 var->
green.msb_right = 0;
710 var->
blue.length = 5;
711 var->
blue.offset = 0;
712 var->
blue.msb_right = 0;
716 var->
transp.msb_right = 0;
721 var->
red.msb_right = 0;
723 var->
green.length = 8;
724 var->
green.offset = 8;
725 var->
green.msb_right = 0;
727 var->
blue.length = 8;
728 var->
blue.offset = 16;
729 var->
blue.msb_right = 0;
733 var->
transp.msb_right = 0;
737 var->
red.offset = 16;
738 var->
red.msb_right = 0;
740 var->
green.length = 8;
741 var->
green.offset = 8;
742 var->
green.msb_right = 0;
744 var->
blue.length = 8;
745 var->
blue.offset = 0;
746 var->
blue.msb_right = 0;
750 var->
transp.msb_right = 0;
763 adjust_aoi_size_position(var, info);
767 static void set_fix(
struct fb_info *info)
782 static void update_lcdc(
struct fb_info *info)
789 u8 *gamma_table_base;
796 gamma_table_base = data->gamma;
800 for (i = 0; i <= 2; i++)
801 for (j = 0; j <= 255; j++)
802 *gamma_table_base++ = j;
804 if (diu_ops.set_gamma_table)
805 diu_ops.set_gamma_table(data->
monitor_port, data->gamma);
834 diu_ops.set_pixel_clock(var->
pixclock);
844 static int map_video_memory(
struct fb_info *info)
846 u32 smem_len = info->
fix.line_length * info->
var.yres_virtual;
851 dev_err(info->
dev,
"unable to allocate fb memory\n");
857 info->
fix.smem_len = smem_len;
864 static void unmap_video_memory(
struct fb_info *info)
867 size_t l = info->
fix.smem_len;
871 info->
fix.smem_start = 0;
872 info->
fix.smem_len = 0;
883 static int fsl_diu_set_aoi(
struct fb_info *info)
887 struct diu_ad *ad = mfbi->
ad;
904 #define PF_BYTE_F 0x10000000
905 #define PF_ALPHA_C_MASK 0x0E000000
906 #define PF_ALPHA_C_SHIFT 25
907 #define PF_BLUE_C_MASK 0x01800000
908 #define PF_BLUE_C_SHIFT 23
909 #define PF_GREEN_C_MASK 0x00600000
910 #define PF_GREEN_C_SHIFT 21
911 #define PF_RED_C_MASK 0x00180000
912 #define PF_RED_C_SHIFT 19
913 #define PF_PALETTE 0x00040000
914 #define PF_PIXEL_S_MASK 0x00030000
915 #define PF_PIXEL_S_SHIFT 16
916 #define PF_COMP_3_MASK 0x0000F000
917 #define PF_COMP_3_SHIFT 12
918 #define PF_COMP_2_MASK 0x00000F00
919 #define PF_COMP_2_SHIFT 8
920 #define PF_COMP_1_MASK 0x000000F0
921 #define PF_COMP_1_SHIFT 4
922 #define PF_COMP_0_MASK 0x0000000F
923 #define PF_COMP_0_SHIFT 0
925 #define MAKE_PF(alpha, red, blue, green, size, c0, c1, c2, c3) \
926 cpu_to_le32(PF_BYTE_F | (alpha << PF_ALPHA_C_SHIFT) | \
927 (blue << PF_BLUE_C_SHIFT) | (green << PF_GREEN_C_SHIFT) | \
928 (red << PF_RED_C_SHIFT) | (c3 << PF_COMP_3_SHIFT) | \
929 (c2 << PF_COMP_2_SHIFT) | (c1 << PF_COMP_1_SHIFT) | \
930 (c0 << PF_COMP_0_SHIFT) | (size << PF_PIXEL_S_SHIFT))
932 switch (bits_per_pixel) {
935 return MAKE_PF(3, 2, 0, 1, 3, 8, 8, 8, 8);
938 return MAKE_PF(4, 0, 1, 2, 2, 0, 8, 8, 8);
941 return MAKE_PF(4, 2, 1, 0, 1, 5, 6, 5, 0);
943 pr_err(
"fsl-diu: unsupported color depth %u\n", bits_per_pixel);
956 static int fsl_diu_set_par(
struct fb_info *info)
962 struct diu_ad *ad = mfbi->
ad;
970 len = info->
var.yres_virtual * info->
fix.line_length;
972 if (len != info->
fix.smem_len) {
973 if (info->
fix.smem_start)
974 unmap_video_memory(info);
977 if (map_video_memory(info)) {
978 dev_err(info->
dev,
"unable to allocate fb memory 1\n");
983 if (diu_ops.get_pixel_format)
984 ad->pix_fmt = diu_ops.get_pixel_format(data->
monitor_port,
1013 return ((val << width) + 0x7FFF - val) >> 16;
1025 static int fsl_diu_setcolreg(
unsigned int regno,
unsigned int red,
1035 if (info->
var.grayscale)
1036 red = green = blue = (19595 * red + 38470 * green +
1038 switch (info->
fix.visual) {
1053 v = (red << info->
var.red.offset) |
1054 (green << info->
var.green.offset) |
1055 (blue << info->
var.blue.offset) |
1056 (transp << info->
var.transp.offset);
1092 fsl_diu_set_aoi(info);
1097 static int fsl_diu_ioctl(
struct fb_info *info,
unsigned int cmd,
1101 struct diu_ad *ad = mfbi->
ad;
1103 unsigned char global_alpha;
1113 "MFB_SET_PIXFMT value of 0x%08x is deprecated.\n",
1118 ad->pix_fmt = pix_fmt;
1122 "MFB_GET_PIXFMT value of 0x%08x is deprecated.\n",
1125 pix_fmt = ad->pix_fmt;
1132 mfbi->
x_aoi_d = aoi_d.x_aoi_d;
1133 mfbi->
y_aoi_d = aoi_d.y_aoi_d;
1134 fsl_diu_check_var(&info->
var, info);
1135 fsl_diu_set_aoi(info);
1138 aoi_d.x_aoi_d = mfbi->
x_aoi_d;
1139 aoi_d.y_aoi_d = mfbi->
y_aoi_d;
1145 if (
copy_to_user(buf, &global_alpha,
sizeof(global_alpha)))
1152 ad->src_size_g_alpha = (ad->src_size_g_alpha & (~0xff)) |
1153 (global_alpha & 0xff);
1162 (ck.red_max < ck.red_min ||
1163 ck.green_max < ck.green_min ||
1164 ck.blue_max < ck.blue_min))
1175 ad->ckmax_r = ck.red_max;
1176 ad->ckmax_g = ck.green_max;
1177 ad->ckmax_b = ck.blue_max;
1178 ad->ckmin_r = ck.red_min;
1179 ad->ckmin_g = ck.green_min;
1180 ad->ckmin_b = ck.blue_min;
1184 dev_err(info->
dev,
"unknown ioctl command (0x%08X)\n", cmd);
1193 static int fsl_diu_open(
struct fb_info *info,
int user)
1199 if ((mfbi->
index ==
PLANE0) && diu_ops.release_bootmem)
1200 diu_ops.release_bootmem();
1202 spin_lock(&diu_lock);
1204 if (mfbi->
count == 1) {
1205 fsl_diu_check_var(&info->
var, info);
1206 res = fsl_diu_set_par(info);
1210 fsl_diu_enable_panel(info);
1213 spin_unlock(&diu_lock);
1219 static int fsl_diu_release(
struct fb_info *info,
int user)
1224 spin_lock(&diu_lock);
1226 if (mfbi->
count == 0)
1227 fsl_diu_disable_panel(info);
1229 spin_unlock(&diu_lock);
1233 static struct fb_ops fsl_diu_ops = {
1235 .fb_check_var = fsl_diu_check_var,
1236 .fb_set_par = fsl_diu_set_par,
1237 .fb_setcolreg = fsl_diu_setcolreg,
1238 .fb_pan_display = fsl_diu_pan_display,
1242 .fb_ioctl = fsl_diu_ioctl,
1243 .fb_open = fsl_diu_open,
1244 .fb_release = fsl_diu_release,
1251 const char *aoi_mode, *init_aoi_mode =
"320x240";
1253 unsigned int dbsize =
ARRAY_SIZE(fsl_diu_mode_db);
1254 int has_default_mode = 1;
1257 info->
fbops = &fsl_diu_ops;
1274 dbsize = info->
monspecs.modedb_len;
1278 aoi_mode = init_aoi_mode;
1288 has_default_mode = 0;
1293 if (!has_default_mode) {
1297 has_default_mode = 1;
1301 if (!has_default_mode && info->
monspecs.modedb) {
1320 info->
var.bits_per_pixel = default_bpp;
1324 if (fsl_diu_check_var(&info->
var, info)) {
1325 dev_err(info->
dev,
"fsl_diu_check_var failed\n");
1326 unmap_video_memory(info);
1332 dev_err(info->
dev,
"register_framebuffer failed\n");
1333 unmap_video_memory(info);
1339 dev_info(info->
dev,
"%s registered successfully\n", mfbi->
id);
1344 static void uninstall_fb(
struct fb_info *info)
1355 unmap_video_memory(info);
1374 #if defined(CONFIG_NOT_COHERENT_CACHE)
1378 for (i = 0; i < coherence_data_size;
1379 i += d_cache_line_size)
1382 ::[
input]
"r"(&coherence_data[i]));
1390 static int request_irq_local(
struct fsl_diu_data *data)
1402 #if !defined(CONFIG_NOT_COHERENT_CACHE)
1450 #define fsl_diu_suspend NULL
1451 #define fsl_diu_resume NULL
1457 enum fsl_diu_monitor_port old_monitor_port;
1483 case FSL_DIU_PORT_DVI:
1485 case FSL_DIU_PORT_LVDS:
1486 return sprintf(buf,
"Single-link LVDS\n");
1487 case FSL_DIU_PORT_DLVDS:
1488 return sprintf(buf,
"Dual-link LVDS\n");
1517 if ((
unsigned long)data & 31) {
1518 dev_err(&pdev->
dev,
"misaligned allocation");
1526 struct fb_info *info = &data->fsl_diu_info[
i];
1529 info->
par = &data->mfb[
i];
1535 data->ad[
i].paddr =
DMA_ADDR(data, ad[i]);
1537 info->
fix.smem_start = 0;
1543 mfbi->
ad = &data->ad[
i];
1558 if (!data->diu_reg) {
1559 dev_err(&pdev->
dev,
"cannot map DIU registers\n");
1564 diu_mode =
in_be32(&data->diu_reg->diu_mode);
1565 if (diu_mode == MFB_MODE0)
1566 out_be32(&data->diu_reg->diu_mode, 0);
1572 dev_err(&pdev->
dev,
"could not get DIU IRQ\n");
1576 data->monitor_port = monitor_port;
1580 data->dummy_ad.pix_fmt = 0x88882317;
1581 data->dummy_ad.src_size_g_alpha =
cpu_to_le32((4 << 12) | 4);
1582 data->dummy_ad.aoi_size =
cpu_to_le32((4 << 16) | 2);
1583 data->dummy_ad.offset_xyi = 0;
1584 data->dummy_ad.offset_xyd = 0;
1585 data->dummy_ad.next_ad = 0;
1586 data->dummy_ad.paddr =
DMA_ADDR(data, dummy_ad);
1592 if (diu_mode == MFB_MODE0)
1593 out_be32(&data->diu_reg->desc[0], data->dummy_ad.paddr);
1595 out_be32(&data->diu_reg->desc[1], data->dummy_ad.paddr);
1596 out_be32(&data->diu_reg->desc[2], data->dummy_ad.paddr);
1599 ret = install_fb(&data->fsl_diu_info[i]);
1601 dev_err(&pdev->
dev,
"could not register fb %d\n", i);
1606 if (request_irq_local(data)) {
1607 dev_err(&pdev->
dev,
"could not claim irq\n");
1612 data->dev_attr.attr.name =
"monitor";
1614 data->dev_attr.show = show_monitor;
1615 data->dev_attr.store = store_monitor;
1618 dev_err(&pdev->
dev,
"could not create sysfs file %s\n",
1619 data->dev_attr.attr.name);
1627 uninstall_fb(&data->fsl_diu_info[i]);
1641 free_irq_local(data);
1657 if (!options || !*options)
1660 while ((opt =
strsep(&options,
",")) !=
NULL) {
1663 if (!
strncmp(opt,
"monitor=", 8)) {
1665 }
else if (!
strncmp(opt,
"bpp=", 4)) {
1677 #ifdef CONFIG_PPC_MPC512x
1679 .compatible =
"fsl,mpc5121-diu",
1683 .compatible =
"fsl,diu",
1691 .name =
"fsl-diu-fb",
1693 .of_match_table = fsl_diu_match,
1695 .probe = fsl_diu_probe,
1696 .remove = fsl_diu_remove,
1701 static int __init fsl_diu_init(
void)
1703 #ifdef CONFIG_NOT_COHERENT_CACHE
1716 fsl_diu_setup(option);
1718 monitor_port = fsl_diu_name_to_port(monitor_string);
1720 pr_info(
"Freescale Display Interface Unit (DIU) framebuffer driver\n");
1722 #ifdef CONFIG_NOT_COHERENT_CACHE
1725 pr_err(
"fsl-diu-fb: can't find 'cpu' device node\n");
1731 pr_err(
"fsl-diu-fb: missing 'd-cache-size' property' "
1742 coherence_data_size /= 8;
1746 pr_err(
"fsl-diu-fb: missing 'd-cache-line-size' property' "
1754 coherence_data =
vmalloc(coherence_data_size);
1755 if (!coherence_data)
1761 pr_err(
"fsl-diu-fb: failed to register platform driver\n");
1762 #if defined(CONFIG_NOT_COHERENT_CACHE)
1763 vfree(coherence_data);
1769 static void __exit fsl_diu_exit(
void)
1772 #if defined(CONFIG_NOT_COHERENT_CACHE)
1773 vfree(coherence_data);
1786 "Specify resolution as \"<xres>x<yres>[-<bpp>][@<refresh>]\" ");
1791 "(\"dvi\", \"lvds\", or \"dlvds\") if supported by the platform");