diff options
| author | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-22 10:38:37 -0500 |
|---|---|---|
| committer | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-22 10:38:37 -0500 |
| commit | fcc9d2e5a6c89d22b8b773a64fb4ad21ac318446 (patch) | |
| tree | a57612d1888735a2ec7972891b68c1ac5ec8faea /drivers/video/pnx4008 | |
| parent | 8dea78da5cee153b8af9c07a2745f6c55057fe12 (diff) | |
Diffstat (limited to 'drivers/video/pnx4008')
| -rw-r--r-- | drivers/video/pnx4008/Makefile | 7 | ||||
| -rw-r--r-- | drivers/video/pnx4008/dum.h | 211 | ||||
| -rw-r--r-- | drivers/video/pnx4008/fbcommon.h | 43 | ||||
| -rw-r--r-- | drivers/video/pnx4008/pnxrgbfb.c | 209 | ||||
| -rw-r--r-- | drivers/video/pnx4008/sdum.c | 872 | ||||
| -rw-r--r-- | drivers/video/pnx4008/sdum.h | 136 |
6 files changed, 1478 insertions, 0 deletions
diff --git a/drivers/video/pnx4008/Makefile b/drivers/video/pnx4008/Makefile new file mode 100644 index 00000000000..636aaccf01f --- /dev/null +++ b/drivers/video/pnx4008/Makefile | |||
| @@ -0,0 +1,7 @@ | |||
| 1 | # | ||
| 2 | # Makefile for the new PNX4008 framebuffer device driver | ||
| 3 | # | ||
| 4 | |||
| 5 | obj-$(CONFIG_FB_PNX4008_DUM) += sdum.o | ||
| 6 | obj-$(CONFIG_FB_PNX4008_DUM_RGB) += pnxrgbfb.o | ||
| 7 | |||
diff --git a/drivers/video/pnx4008/dum.h b/drivers/video/pnx4008/dum.h new file mode 100644 index 00000000000..1234d4375d9 --- /dev/null +++ b/drivers/video/pnx4008/dum.h | |||
| @@ -0,0 +1,211 @@ | |||
| 1 | /* | ||
| 2 | * linux/drivers/video/pnx4008/dum.h | ||
| 3 | * | ||
| 4 | * Internal header for SDUM | ||
| 5 | * | ||
| 6 | * 2005 (c) Koninklijke Philips N.V. This file is licensed under | ||
| 7 | * the terms of the GNU General Public License version 2. This program | ||
| 8 | * is licensed "as is" without any warranty of any kind, whether express | ||
| 9 | * or implied. | ||
| 10 | */ | ||
| 11 | |||
| 12 | #ifndef __PNX008_DUM_H__ | ||
| 13 | #define __PNX008_DUM_H__ | ||
| 14 | |||
| 15 | #include <mach/platform.h> | ||
| 16 | |||
| 17 | #define PNX4008_DUMCONF_VA_BASE IO_ADDRESS(PNX4008_DUMCONF_BASE) | ||
| 18 | #define PNX4008_DUM_MAIN_VA_BASE IO_ADDRESS(PNX4008_DUM_MAINCFG_BASE) | ||
| 19 | |||
| 20 | /* DUM CFG ADDRESSES */ | ||
| 21 | #define DUM_CH_BASE_ADR (PNX4008_DUMCONF_VA_BASE + 0x00) | ||
| 22 | #define DUM_CH_MIN_ADR (PNX4008_DUMCONF_VA_BASE + 0x00) | ||
| 23 | #define DUM_CH_MAX_ADR (PNX4008_DUMCONF_VA_BASE + 0x04) | ||
| 24 | #define DUM_CH_CONF_ADR (PNX4008_DUMCONF_VA_BASE + 0x08) | ||
| 25 | #define DUM_CH_STAT_ADR (PNX4008_DUMCONF_VA_BASE + 0x0C) | ||
| 26 | #define DUM_CH_CTRL_ADR (PNX4008_DUMCONF_VA_BASE + 0x10) | ||
| 27 | |||
| 28 | #define CH_MARG (0x100 / sizeof(u32)) | ||
| 29 | #define DUM_CH_MIN(i) (*((volatile u32 *)DUM_CH_MIN_ADR + (i) * CH_MARG)) | ||
| 30 | #define DUM_CH_MAX(i) (*((volatile u32 *)DUM_CH_MAX_ADR + (i) * CH_MARG)) | ||
| 31 | #define DUM_CH_CONF(i) (*((volatile u32 *)DUM_CH_CONF_ADR + (i) * CH_MARG)) | ||
| 32 | #define DUM_CH_STAT(i) (*((volatile u32 *)DUM_CH_STAT_ADR + (i) * CH_MARG)) | ||
| 33 | #define DUM_CH_CTRL(i) (*((volatile u32 *)DUM_CH_CTRL_ADR + (i) * CH_MARG)) | ||
| 34 | |||
| 35 | #define DUM_CONF_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x00) | ||
| 36 | #define DUM_CTRL_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x04) | ||
| 37 | #define DUM_STAT_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x08) | ||
| 38 | #define DUM_DECODE_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x0C) | ||
| 39 | #define DUM_COM_BASE_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x10) | ||
| 40 | #define DUM_SYNC_C_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x14) | ||
| 41 | #define DUM_CLK_DIV_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x18) | ||
| 42 | #define DUM_DIRTY_LOW_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x20) | ||
| 43 | #define DUM_DIRTY_HIGH_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x24) | ||
| 44 | #define DUM_FORMAT_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x28) | ||
| 45 | #define DUM_WTCFG1_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x30) | ||
| 46 | #define DUM_RTCFG1_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x34) | ||
| 47 | #define DUM_WTCFG2_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x38) | ||
| 48 | #define DUM_RTCFG2_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x3C) | ||
| 49 | #define DUM_TCFG_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x40) | ||
| 50 | #define DUM_OUTP_FORMAT1_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x44) | ||
| 51 | #define DUM_OUTP_FORMAT2_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x48) | ||
| 52 | #define DUM_SYNC_MODE_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x4C) | ||
| 53 | #define DUM_SYNC_OUT_C_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x50) | ||
| 54 | |||
| 55 | #define DUM_CONF (*(volatile u32 *)(DUM_CONF_ADR)) | ||
| 56 | #define DUM_CTRL (*(volatile u32 *)(DUM_CTRL_ADR)) | ||
| 57 | #define DUM_STAT (*(volatile u32 *)(DUM_STAT_ADR)) | ||
| 58 | #define DUM_DECODE (*(volatile u32 *)(DUM_DECODE_ADR)) | ||
| 59 | #define DUM_COM_BASE (*(volatile u32 *)(DUM_COM_BASE_ADR)) | ||
| 60 | #define DUM_SYNC_C (*(volatile u32 *)(DUM_SYNC_C_ADR)) | ||
| 61 | #define DUM_CLK_DIV (*(volatile u32 *)(DUM_CLK_DIV_ADR)) | ||
| 62 | #define DUM_DIRTY_LOW (*(volatile u32 *)(DUM_DIRTY_LOW_ADR)) | ||
| 63 | #define DUM_DIRTY_HIGH (*(volatile u32 *)(DUM_DIRTY_HIGH_ADR)) | ||
| 64 | #define DUM_FORMAT (*(volatile u32 *)(DUM_FORMAT_ADR)) | ||
| 65 | #define DUM_WTCFG1 (*(volatile u32 *)(DUM_WTCFG1_ADR)) | ||
| 66 | #define DUM_RTCFG1 (*(volatile u32 *)(DUM_RTCFG1_ADR)) | ||
| 67 | #define DUM_WTCFG2 (*(volatile u32 *)(DUM_WTCFG2_ADR)) | ||
| 68 | #define DUM_RTCFG2 (*(volatile u32 *)(DUM_RTCFG2_ADR)) | ||
| 69 | #define DUM_TCFG (*(volatile u32 *)(DUM_TCFG_ADR)) | ||
| 70 | #define DUM_OUTP_FORMAT1 (*(volatile u32 *)(DUM_OUTP_FORMAT1_ADR)) | ||
| 71 | #define DUM_OUTP_FORMAT2 (*(volatile u32 *)(DUM_OUTP_FORMAT2_ADR)) | ||
| 72 | #define DUM_SYNC_MODE (*(volatile u32 *)(DUM_SYNC_MODE_ADR)) | ||
| 73 | #define DUM_SYNC_OUT_C (*(volatile u32 *)(DUM_SYNC_OUT_C_ADR)) | ||
| 74 | |||
| 75 | /* DUM SLAVE ADDRESSES */ | ||
| 76 | #define DUM_SLAVE_WRITE_ADR (PNX4008_DUM_MAINCFG_BASE + 0x0000000) | ||
| 77 | #define DUM_SLAVE_READ1_I_ADR (PNX4008_DUM_MAINCFG_BASE + 0x1000000) | ||
| 78 | #define DUM_SLAVE_READ1_R_ADR (PNX4008_DUM_MAINCFG_BASE + 0x1000004) | ||
| 79 | #define DUM_SLAVE_READ2_I_ADR (PNX4008_DUM_MAINCFG_BASE + 0x1000008) | ||
| 80 | #define DUM_SLAVE_READ2_R_ADR (PNX4008_DUM_MAINCFG_BASE + 0x100000C) | ||
| 81 | |||
| 82 | #define DUM_SLAVE_WRITE_W ((volatile u32 *)(DUM_SLAVE_WRITE_ADR)) | ||
| 83 | #define DUM_SLAVE_WRITE_HW ((volatile u16 *)(DUM_SLAVE_WRITE_ADR)) | ||
| 84 | #define DUM_SLAVE_READ1_I ((volatile u8 *)(DUM_SLAVE_READ1_I_ADR)) | ||
| 85 | #define DUM_SLAVE_READ1_R ((volatile u16 *)(DUM_SLAVE_READ1_R_ADR)) | ||
| 86 | #define DUM_SLAVE_READ2_I ((volatile u8 *)(DUM_SLAVE_READ2_I_ADR)) | ||
| 87 | #define DUM_SLAVE_READ2_R ((volatile u16 *)(DUM_SLAVE_READ2_R_ADR)) | ||
| 88 | |||
| 89 | /* Sony display register addresses */ | ||
| 90 | #define DISP_0_REG (0x00) | ||
| 91 | #define DISP_1_REG (0x01) | ||
| 92 | #define DISP_CAL_REG (0x20) | ||
| 93 | #define DISP_ID_REG (0x2A) | ||
| 94 | #define DISP_XMIN_L_REG (0x30) | ||
| 95 | #define DISP_XMIN_H_REG (0x31) | ||
| 96 | #define DISP_YMIN_REG (0x32) | ||
| 97 | #define DISP_XMAX_L_REG (0x34) | ||
| 98 | #define DISP_XMAX_H_REG (0x35) | ||
| 99 | #define DISP_YMAX_REG (0x36) | ||
| 100 | #define DISP_SYNC_EN_REG (0x38) | ||
| 101 | #define DISP_SYNC_RISE_L_REG (0x3C) | ||
| 102 | #define DISP_SYNC_RISE_H_REG (0x3D) | ||
| 103 | #define DISP_SYNC_FALL_L_REG (0x3E) | ||
| 104 | #define DISP_SYNC_FALL_H_REG (0x3F) | ||
| 105 | #define DISP_PIXEL_REG (0x0B) | ||
| 106 | #define DISP_DUMMY1_REG (0x28) | ||
| 107 | #define DISP_DUMMY2_REG (0x29) | ||
| 108 | #define DISP_TIMING_REG (0x98) | ||
| 109 | #define DISP_DUMP_REG (0x99) | ||
| 110 | |||
| 111 | /* Sony display constants */ | ||
| 112 | #define SONY_ID1 (0x22) | ||
| 113 | #define SONY_ID2 (0x23) | ||
| 114 | |||
| 115 | /* Philips display register addresses */ | ||
| 116 | #define PH_DISP_ORIENT_REG (0x003) | ||
| 117 | #define PH_DISP_YPOINT_REG (0x200) | ||
| 118 | #define PH_DISP_XPOINT_REG (0x201) | ||
| 119 | #define PH_DISP_PIXEL_REG (0x202) | ||
| 120 | #define PH_DISP_YMIN_REG (0x406) | ||
| 121 | #define PH_DISP_YMAX_REG (0x407) | ||
| 122 | #define PH_DISP_XMIN_REG (0x408) | ||
| 123 | #define PH_DISP_XMAX_REG (0x409) | ||
| 124 | |||
| 125 | /* Misc constants */ | ||
| 126 | #define NO_VALID_DISPLAY_FOUND (0) | ||
| 127 | #define DISPLAY2_IS_NOT_CONNECTED (0) | ||
| 128 | |||
| 129 | /* register values */ | ||
| 130 | #define V_BAC_ENABLE (BIT(0)) | ||
| 131 | #define V_BAC_DISABLE_IDLE (BIT(1)) | ||
| 132 | #define V_BAC_DISABLE_TRIG (BIT(2)) | ||
| 133 | #define V_DUM_RESET (BIT(3)) | ||
| 134 | #define V_MUX_RESET (BIT(4)) | ||
| 135 | #define BAC_ENABLED (BIT(0)) | ||
| 136 | #define BAC_DISABLED 0 | ||
| 137 | |||
| 138 | /* Sony LCD commands */ | ||
| 139 | #define V_LCD_STANDBY_OFF ((BIT(25)) | (0 << 16) | DISP_0_REG) | ||
| 140 | #define V_LCD_USE_9BIT_BUS ((BIT(25)) | (2 << 16) | DISP_1_REG) | ||
| 141 | #define V_LCD_SYNC_RISE_L ((BIT(25)) | (0 << 16) | DISP_SYNC_RISE_L_REG) | ||
| 142 | #define V_LCD_SYNC_RISE_H ((BIT(25)) | (0 << 16) | DISP_SYNC_RISE_H_REG) | ||
| 143 | #define V_LCD_SYNC_FALL_L ((BIT(25)) | (160 << 16) | DISP_SYNC_FALL_L_REG) | ||
| 144 | #define V_LCD_SYNC_FALL_H ((BIT(25)) | (0 << 16) | DISP_SYNC_FALL_H_REG) | ||
| 145 | #define V_LCD_SYNC_ENABLE ((BIT(25)) | (128 << 16) | DISP_SYNC_EN_REG) | ||
| 146 | #define V_LCD_DISPLAY_ON ((BIT(25)) | (64 << 16) | DISP_0_REG) | ||
| 147 | |||
| 148 | enum { | ||
| 149 | PAD_NONE, | ||
| 150 | PAD_512, | ||
| 151 | PAD_1024 | ||
| 152 | }; | ||
| 153 | |||
| 154 | enum { | ||
| 155 | RGB888, | ||
| 156 | RGB666, | ||
| 157 | RGB565, | ||
| 158 | BGR565, | ||
| 159 | ARGB1555, | ||
| 160 | ABGR1555, | ||
| 161 | ARGB4444, | ||
| 162 | ABGR4444 | ||
| 163 | }; | ||
| 164 | |||
| 165 | struct dum_setup { | ||
| 166 | int sync_neg_edge; | ||
| 167 | int round_robin; | ||
| 168 | int mux_int; | ||
| 169 | int synced_dirty_flag_int; | ||
| 170 | int dirty_flag_int; | ||
| 171 | int error_int; | ||
| 172 | int pf_empty_int; | ||
| 173 | int sf_empty_int; | ||
| 174 | int bac_dis_int; | ||
| 175 | u32 dirty_base_adr; | ||
| 176 | u32 command_base_adr; | ||
| 177 | u32 sync_clk_div; | ||
| 178 | int sync_output; | ||
| 179 | u32 sync_restart_val; | ||
| 180 | u32 set_sync_high; | ||
| 181 | u32 set_sync_low; | ||
| 182 | }; | ||
| 183 | |||
| 184 | struct dum_ch_setup { | ||
| 185 | int disp_no; | ||
| 186 | u32 xmin; | ||
| 187 | u32 ymin; | ||
| 188 | u32 xmax; | ||
| 189 | u32 ymax; | ||
| 190 | int xmirror; | ||
| 191 | int ymirror; | ||
| 192 | int rotate; | ||
| 193 | u32 minadr; | ||
| 194 | u32 maxadr; | ||
| 195 | u32 dirtybuffer; | ||
| 196 | int pad; | ||
| 197 | int format; | ||
| 198 | int hwdirty; | ||
| 199 | int slave_trans; | ||
| 200 | }; | ||
| 201 | |||
| 202 | struct disp_window { | ||
| 203 | u32 xmin_l; | ||
| 204 | u32 xmin_h; | ||
| 205 | u32 ymin; | ||
| 206 | u32 xmax_l; | ||
| 207 | u32 xmax_h; | ||
| 208 | u32 ymax; | ||
| 209 | }; | ||
| 210 | |||
| 211 | #endif /* #ifndef __PNX008_DUM_H__ */ | ||
diff --git a/drivers/video/pnx4008/fbcommon.h b/drivers/video/pnx4008/fbcommon.h new file mode 100644 index 00000000000..4ebc87dafaf --- /dev/null +++ b/drivers/video/pnx4008/fbcommon.h | |||
| @@ -0,0 +1,43 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2005 Philips Semiconductors | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License as published by | ||
| 6 | * the Free Software Foundation; either version 2, or (at your option) | ||
| 7 | * any later version. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope that it will be useful, | ||
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | * GNU General Public License for more details. | ||
| 13 | * | ||
| 14 | * You should have received a copy of the GNU General Public License | ||
| 15 | * along with this program; see the file COPYING. If not, write to | ||
| 16 | * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
| 17 | * Boston, MA 02111-1307, USA, or http://www.gnu.org/licenses/gpl.html | ||
| 18 | */ | ||
| 19 | |||
| 20 | #define QCIF_W (176) | ||
| 21 | #define QCIF_H (144) | ||
| 22 | |||
| 23 | #define CIF_W (352) | ||
| 24 | #define CIF_H (288) | ||
| 25 | |||
| 26 | #define LCD_X_RES 208 | ||
| 27 | #define LCD_Y_RES 320 | ||
| 28 | #define LCD_X_PAD 256 | ||
| 29 | #define LCD_BBP 4 /* Bytes Per Pixel */ | ||
| 30 | |||
| 31 | #define DISP_MAX_X_SIZE (320) | ||
| 32 | #define DISP_MAX_Y_SIZE (208) | ||
| 33 | |||
| 34 | #define RETURNVAL_BASE (0x400) | ||
| 35 | |||
| 36 | enum fb_ioctl_returntype { | ||
| 37 | ENORESOURCESLEFT = RETURNVAL_BASE, | ||
| 38 | ERESOURCESNOTFREED, | ||
| 39 | EPROCNOTOWNER, | ||
| 40 | EFBNOTOWNER, | ||
| 41 | ECOPYFAILED, | ||
| 42 | EIOREMAPFAILED, | ||
| 43 | }; | ||
diff --git a/drivers/video/pnx4008/pnxrgbfb.c b/drivers/video/pnx4008/pnxrgbfb.c new file mode 100644 index 00000000000..b2252fea285 --- /dev/null +++ b/drivers/video/pnx4008/pnxrgbfb.c | |||
| @@ -0,0 +1,209 @@ | |||
| 1 | /* | ||
| 2 | * drivers/video/pnx4008/pnxrgbfb.c | ||
| 3 | * | ||
| 4 | * PNX4008's framebuffer support | ||
| 5 | * | ||
| 6 | * Author: Grigory Tolstolytkin <gtolstolytkin@ru.mvista.com> | ||
| 7 | * Based on Philips Semiconductors's code | ||
| 8 | * | ||
| 9 | * Copyrght (c) 2005 MontaVista Software, Inc. | ||
| 10 | * Copyright (c) 2005 Philips Semiconductors | ||
| 11 | * This file is licensed under the terms of the GNU General Public License | ||
| 12 | * version 2. This program is licensed "as is" without any warranty of any | ||
| 13 | * kind, whether express or implied. | ||
| 14 | */ | ||
| 15 | |||
| 16 | #include <linux/module.h> | ||
| 17 | #include <linux/kernel.h> | ||
| 18 | #include <linux/errno.h> | ||
| 19 | #include <linux/string.h> | ||
| 20 | #include <linux/mm.h> | ||
| 21 | #include <linux/vmalloc.h> | ||
| 22 | #include <linux/delay.h> | ||
| 23 | #include <linux/interrupt.h> | ||
| 24 | #include <linux/fb.h> | ||
| 25 | #include <linux/init.h> | ||
| 26 | #include <linux/platform_device.h> | ||
| 27 | |||
| 28 | #include "sdum.h" | ||
| 29 | #include "fbcommon.h" | ||
| 30 | |||
| 31 | static u32 colreg[16]; | ||
| 32 | |||
| 33 | static struct fb_var_screeninfo rgbfb_var __initdata = { | ||
| 34 | .xres = LCD_X_RES, | ||
| 35 | .yres = LCD_Y_RES, | ||
| 36 | .xres_virtual = LCD_X_RES, | ||
| 37 | .yres_virtual = LCD_Y_RES, | ||
| 38 | .bits_per_pixel = 32, | ||
| 39 | .red.offset = 16, | ||
| 40 | .red.length = 8, | ||
| 41 | .green.offset = 8, | ||
| 42 | .green.length = 8, | ||
| 43 | .blue.offset = 0, | ||
| 44 | .blue.length = 8, | ||
| 45 | .left_margin = 0, | ||
| 46 | .right_margin = 0, | ||
| 47 | .upper_margin = 0, | ||
| 48 | .lower_margin = 0, | ||
| 49 | .vmode = FB_VMODE_NONINTERLACED, | ||
| 50 | }; | ||
| 51 | static struct fb_fix_screeninfo rgbfb_fix __initdata = { | ||
| 52 | .id = "RGBFB", | ||
| 53 | .line_length = LCD_X_RES * LCD_BBP, | ||
| 54 | .type = FB_TYPE_PACKED_PIXELS, | ||
| 55 | .visual = FB_VISUAL_TRUECOLOR, | ||
| 56 | .xpanstep = 0, | ||
| 57 | .ypanstep = 0, | ||
| 58 | .ywrapstep = 0, | ||
| 59 | .accel = FB_ACCEL_NONE, | ||
| 60 | }; | ||
| 61 | |||
| 62 | static int channel_owned; | ||
| 63 | |||
| 64 | static int no_cursor(struct fb_info *info, struct fb_cursor *cursor) | ||
| 65 | { | ||
| 66 | return 0; | ||
| 67 | } | ||
| 68 | |||
| 69 | static int rgbfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, | ||
| 70 | u_int transp, struct fb_info *info) | ||
| 71 | { | ||
| 72 | if (regno > 15) | ||
| 73 | return 1; | ||
| 74 | |||
| 75 | colreg[regno] = ((red & 0xff00) << 8) | (green & 0xff00) | | ||
| 76 | ((blue & 0xff00) >> 8); | ||
| 77 | return 0; | ||
| 78 | } | ||
| 79 | |||
| 80 | static int rgbfb_mmap(struct fb_info *info, struct vm_area_struct *vma) | ||
| 81 | { | ||
| 82 | return pnx4008_sdum_mmap(info, vma, NULL); | ||
| 83 | } | ||
| 84 | |||
| 85 | static struct fb_ops rgbfb_ops = { | ||
| 86 | .fb_mmap = rgbfb_mmap, | ||
| 87 | .fb_setcolreg = rgbfb_setcolreg, | ||
| 88 | .fb_fillrect = cfb_fillrect, | ||
| 89 | .fb_copyarea = cfb_copyarea, | ||
| 90 | .fb_imageblit = cfb_imageblit, | ||
| 91 | }; | ||
| 92 | |||
| 93 | static int rgbfb_remove(struct platform_device *pdev) | ||
| 94 | { | ||
| 95 | struct fb_info *info = platform_get_drvdata(pdev); | ||
| 96 | |||
| 97 | if (info) { | ||
| 98 | unregister_framebuffer(info); | ||
| 99 | fb_dealloc_cmap(&info->cmap); | ||
| 100 | framebuffer_release(info); | ||
| 101 | platform_set_drvdata(pdev, NULL); | ||
| 102 | } | ||
| 103 | |||
| 104 | pnx4008_free_dum_channel(channel_owned, pdev->id); | ||
| 105 | pnx4008_set_dum_exit_notification(pdev->id); | ||
| 106 | |||
| 107 | return 0; | ||
| 108 | } | ||
| 109 | |||
| 110 | static int __devinit rgbfb_probe(struct platform_device *pdev) | ||
| 111 | { | ||
| 112 | struct fb_info *info; | ||
| 113 | struct dumchannel_uf chan_uf; | ||
| 114 | int ret; | ||
| 115 | char *option; | ||
| 116 | |||
| 117 | info = framebuffer_alloc(sizeof(u32) * 16, &pdev->dev); | ||
| 118 | if (!info) { | ||
| 119 | ret = -ENOMEM; | ||
| 120 | goto err; | ||
| 121 | } | ||
| 122 | |||
| 123 | pnx4008_get_fb_addresses(FB_TYPE_RGB, (void **)&info->screen_base, | ||
| 124 | (dma_addr_t *) &rgbfb_fix.smem_start, | ||
| 125 | &rgbfb_fix.smem_len); | ||
| 126 | |||
| 127 | if ((ret = pnx4008_alloc_dum_channel(pdev->id)) < 0) | ||
| 128 | goto err0; | ||
| 129 | else { | ||
| 130 | channel_owned = ret; | ||
| 131 | chan_uf.channelnr = channel_owned; | ||
| 132 | chan_uf.dirty = (u32 *) NULL; | ||
| 133 | chan_uf.source = (u32 *) rgbfb_fix.smem_start; | ||
| 134 | chan_uf.x_offset = 0; | ||
| 135 | chan_uf.y_offset = 0; | ||
| 136 | chan_uf.width = LCD_X_RES; | ||
| 137 | chan_uf.height = LCD_Y_RES; | ||
| 138 | |||
| 139 | if ((ret = pnx4008_put_dum_channel_uf(chan_uf, pdev->id))< 0) | ||
| 140 | goto err1; | ||
| 141 | |||
| 142 | if ((ret = | ||
| 143 | pnx4008_set_dum_channel_sync(channel_owned, CONF_SYNC_ON, | ||
| 144 | pdev->id)) < 0) | ||
| 145 | goto err1; | ||
| 146 | |||
| 147 | if ((ret = | ||
| 148 | pnx4008_set_dum_channel_dirty_detect(channel_owned, | ||
| 149 | CONF_DIRTYDETECTION_ON, | ||
| 150 | pdev->id)) < 0) | ||
| 151 | goto err1; | ||
| 152 | } | ||
| 153 | |||
| 154 | if (!fb_get_options("pnxrgbfb", &option) && option && | ||
| 155 | !strcmp(option, "nocursor")) | ||
| 156 | rgbfb_ops.fb_cursor = no_cursor; | ||
| 157 | |||
| 158 | info->node = -1; | ||
| 159 | info->flags = FBINFO_FLAG_DEFAULT; | ||
| 160 | info->fbops = &rgbfb_ops; | ||
| 161 | info->fix = rgbfb_fix; | ||
| 162 | info->var = rgbfb_var; | ||
| 163 | info->screen_size = rgbfb_fix.smem_len; | ||
| 164 | info->pseudo_palette = info->par; | ||
| 165 | info->par = NULL; | ||
| 166 | |||
| 167 | ret = fb_alloc_cmap(&info->cmap, 256, 0); | ||
| 168 | if (ret < 0) | ||
| 169 | goto err1; | ||
| 170 | |||
| 171 | ret = register_framebuffer(info); | ||
| 172 | if (ret < 0) | ||
| 173 | goto err2; | ||
| 174 | platform_set_drvdata(pdev, info); | ||
| 175 | |||
| 176 | return 0; | ||
| 177 | |||
| 178 | err2: | ||
| 179 | fb_dealloc_cmap(&info->cmap); | ||
| 180 | err1: | ||
| 181 | pnx4008_free_dum_channel(channel_owned, pdev->id); | ||
| 182 | err0: | ||
| 183 | framebuffer_release(info); | ||
| 184 | err: | ||
| 185 | return ret; | ||
| 186 | } | ||
| 187 | |||
| 188 | static struct platform_driver rgbfb_driver = { | ||
| 189 | .driver = { | ||
| 190 | .name = "pnx4008-rgbfb", | ||
| 191 | }, | ||
| 192 | .probe = rgbfb_probe, | ||
| 193 | .remove = rgbfb_remove, | ||
| 194 | }; | ||
| 195 | |||
| 196 | static int __init rgbfb_init(void) | ||
| 197 | { | ||
| 198 | return platform_driver_register(&rgbfb_driver); | ||
| 199 | } | ||
| 200 | |||
| 201 | static void __exit rgbfb_exit(void) | ||
| 202 | { | ||
| 203 | platform_driver_unregister(&rgbfb_driver); | ||
| 204 | } | ||
| 205 | |||
| 206 | module_init(rgbfb_init); | ||
| 207 | module_exit(rgbfb_exit); | ||
| 208 | |||
| 209 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/video/pnx4008/sdum.c b/drivers/video/pnx4008/sdum.c new file mode 100644 index 00000000000..5ec4f2d439c --- /dev/null +++ b/drivers/video/pnx4008/sdum.c | |||
| @@ -0,0 +1,872 @@ | |||
| 1 | /* | ||
| 2 | * drivers/video/pnx4008/sdum.c | ||
| 3 | * | ||
| 4 | * Display Update Master support | ||
| 5 | * | ||
| 6 | * Authors: Grigory Tolstolytkin <gtolstolytkin@ru.mvista.com> | ||
| 7 | * Vitaly Wool <vitalywool@gmail.com> | ||
| 8 | * Based on Philips Semiconductors's code | ||
| 9 | * | ||
| 10 | * Copyrght (c) 2005-2006 MontaVista Software, Inc. | ||
| 11 | * Copyright (c) 2005 Philips Semiconductors | ||
| 12 | * This file is licensed under the terms of the GNU General Public License | ||
| 13 | * version 2. This program is licensed "as is" without any warranty of any | ||
| 14 | * kind, whether express or implied. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include <linux/module.h> | ||
| 18 | #include <linux/kernel.h> | ||
| 19 | #include <linux/errno.h> | ||
| 20 | #include <linux/string.h> | ||
| 21 | #include <linux/mm.h> | ||
| 22 | #include <linux/tty.h> | ||
| 23 | #include <linux/vmalloc.h> | ||
| 24 | #include <linux/delay.h> | ||
| 25 | #include <linux/interrupt.h> | ||
| 26 | #include <linux/platform_device.h> | ||
| 27 | #include <linux/fb.h> | ||
| 28 | #include <linux/init.h> | ||
| 29 | #include <linux/dma-mapping.h> | ||
| 30 | #include <linux/clk.h> | ||
| 31 | #include <linux/gfp.h> | ||
| 32 | #include <asm/uaccess.h> | ||
| 33 | #include <mach/gpio.h> | ||
| 34 | |||
| 35 | #include "sdum.h" | ||
| 36 | #include "fbcommon.h" | ||
| 37 | #include "dum.h" | ||
| 38 | |||
| 39 | /* Framebuffers we have */ | ||
| 40 | |||
| 41 | static struct pnx4008_fb_addr { | ||
| 42 | int fb_type; | ||
| 43 | long addr_offset; | ||
| 44 | long fb_length; | ||
| 45 | } fb_addr[] = { | ||
| 46 | [0] = { | ||
| 47 | FB_TYPE_YUV, 0, 0xB0000 | ||
| 48 | }, | ||
| 49 | [1] = { | ||
| 50 | FB_TYPE_RGB, 0xB0000, 0x50000 | ||
| 51 | }, | ||
| 52 | }; | ||
| 53 | |||
| 54 | static struct dum_data { | ||
| 55 | u32 lcd_phys_start; | ||
| 56 | u32 lcd_virt_start; | ||
| 57 | u32 slave_phys_base; | ||
| 58 | u32 *slave_virt_base; | ||
| 59 | int fb_owning_channel[MAX_DUM_CHANNELS]; | ||
| 60 | struct dumchannel_uf chan_uf_store[MAX_DUM_CHANNELS]; | ||
| 61 | } dum_data; | ||
| 62 | |||
| 63 | /* Different local helper functions */ | ||
| 64 | |||
| 65 | static u32 nof_pixels_dx(struct dum_ch_setup *ch_setup) | ||
| 66 | { | ||
| 67 | return (ch_setup->xmax - ch_setup->xmin + 1); | ||
| 68 | } | ||
| 69 | |||
| 70 | static u32 nof_pixels_dy(struct dum_ch_setup *ch_setup) | ||
| 71 | { | ||
| 72 | return (ch_setup->ymax - ch_setup->ymin + 1); | ||
| 73 | } | ||
| 74 | |||
| 75 | static u32 nof_pixels_dxy(struct dum_ch_setup *ch_setup) | ||
| 76 | { | ||
| 77 | return (nof_pixels_dx(ch_setup) * nof_pixels_dy(ch_setup)); | ||
| 78 | } | ||
| 79 | |||
| 80 | static u32 nof_bytes(struct dum_ch_setup *ch_setup) | ||
| 81 | { | ||
| 82 | u32 r = nof_pixels_dxy(ch_setup); | ||
| 83 | switch (ch_setup->format) { | ||
| 84 | case RGB888: | ||
| 85 | case RGB666: | ||
| 86 | r *= 4; | ||
| 87 | break; | ||
| 88 | |||
| 89 | default: | ||
| 90 | r *= 2; | ||
| 91 | break; | ||
| 92 | } | ||
| 93 | return r; | ||
| 94 | } | ||
| 95 | |||
| 96 | static u32 build_command(int disp_no, u32 reg, u32 val) | ||
| 97 | { | ||
| 98 | return ((disp_no << 26) | BIT(25) | (val << 16) | (disp_no << 10) | | ||
| 99 | (reg << 0)); | ||
| 100 | } | ||
| 101 | |||
| 102 | static u32 build_double_index(int disp_no, u32 val) | ||
| 103 | { | ||
| 104 | return ((disp_no << 26) | (val << 16) | (disp_no << 10) | (val << 0)); | ||
| 105 | } | ||
| 106 | |||
| 107 | static void build_disp_window(struct dum_ch_setup * ch_setup, struct disp_window * dw) | ||
| 108 | { | ||
| 109 | dw->ymin = ch_setup->ymin; | ||
| 110 | dw->ymax = ch_setup->ymax; | ||
| 111 | dw->xmin_l = ch_setup->xmin & 0xFF; | ||
| 112 | dw->xmin_h = (ch_setup->xmin & BIT(8)) >> 8; | ||
| 113 | dw->xmax_l = ch_setup->xmax & 0xFF; | ||
| 114 | dw->xmax_h = (ch_setup->xmax & BIT(8)) >> 8; | ||
| 115 | } | ||
| 116 | |||
| 117 | static int put_channel(struct dumchannel chan) | ||
| 118 | { | ||
| 119 | int i = chan.channelnr; | ||
| 120 | |||
| 121 | if (i < 0 || i > MAX_DUM_CHANNELS) | ||
| 122 | return -EINVAL; | ||
| 123 | else { | ||
| 124 | DUM_CH_MIN(i) = chan.dum_ch_min; | ||
| 125 | DUM_CH_MAX(i) = chan.dum_ch_max; | ||
| 126 | DUM_CH_CONF(i) = chan.dum_ch_conf; | ||
| 127 | DUM_CH_CTRL(i) = chan.dum_ch_ctrl; | ||
| 128 | } | ||
| 129 | |||
| 130 | return 0; | ||
| 131 | } | ||
| 132 | |||
| 133 | static void clear_channel(int channr) | ||
| 134 | { | ||
| 135 | struct dumchannel chan; | ||
| 136 | |||
| 137 | chan.channelnr = channr; | ||
| 138 | chan.dum_ch_min = 0; | ||
| 139 | chan.dum_ch_max = 0; | ||
| 140 | chan.dum_ch_conf = 0; | ||
| 141 | chan.dum_ch_ctrl = 0; | ||
| 142 | |||
| 143 | put_channel(chan); | ||
| 144 | } | ||
| 145 | |||
| 146 | static int put_cmd_string(struct cmdstring cmds) | ||
| 147 | { | ||
| 148 | u16 *cmd_str_virtaddr; | ||
| 149 | u32 *cmd_ptr0_virtaddr; | ||
| 150 | u32 cmd_str_physaddr; | ||
| 151 | |||
| 152 | int i = cmds.channelnr; | ||
| 153 | |||
| 154 | if (i < 0 || i > MAX_DUM_CHANNELS) | ||
| 155 | return -EINVAL; | ||
| 156 | else if ((cmd_ptr0_virtaddr = | ||
| 157 | (int *)ioremap_nocache(DUM_COM_BASE, | ||
| 158 | sizeof(int) * MAX_DUM_CHANNELS)) == | ||
| 159 | NULL) | ||
| 160 | return -EIOREMAPFAILED; | ||
| 161 | else { | ||
| 162 | cmd_str_physaddr = ioread32(&cmd_ptr0_virtaddr[cmds.channelnr]); | ||
| 163 | if ((cmd_str_virtaddr = | ||
| 164 | (u16 *) ioremap_nocache(cmd_str_physaddr, | ||
| 165 | sizeof(cmds))) == NULL) { | ||
| 166 | iounmap(cmd_ptr0_virtaddr); | ||
| 167 | return -EIOREMAPFAILED; | ||
| 168 | } else { | ||
| 169 | int t; | ||
| 170 | for (t = 0; t < 8; t++) | ||
| 171 | iowrite16(*((u16 *)&cmds.prestringlen + t), | ||
| 172 | cmd_str_virtaddr + t); | ||
| 173 | |||
| 174 | for (t = 0; t < cmds.prestringlen / 2; t++) | ||
| 175 | iowrite16(*((u16 *)&cmds.precmd + t), | ||
| 176 | cmd_str_virtaddr + t + 8); | ||
| 177 | |||
| 178 | for (t = 0; t < cmds.poststringlen / 2; t++) | ||
| 179 | iowrite16(*((u16 *)&cmds.postcmd + t), | ||
| 180 | cmd_str_virtaddr + t + 8 + | ||
| 181 | cmds.prestringlen / 2); | ||
| 182 | |||
| 183 | iounmap(cmd_ptr0_virtaddr); | ||
| 184 | iounmap(cmd_str_virtaddr); | ||
| 185 | } | ||
| 186 | } | ||
| 187 | |||
| 188 | return 0; | ||
| 189 | } | ||
| 190 | |||
| 191 | static u32 dum_ch_setup(int ch_no, struct dum_ch_setup * ch_setup) | ||
| 192 | { | ||
| 193 | struct cmdstring cmds_c; | ||
| 194 | struct cmdstring *cmds = &cmds_c; | ||
| 195 | struct disp_window dw; | ||
| 196 | int standard; | ||
| 197 | u32 orientation = 0; | ||
| 198 | struct dumchannel chan = { 0 }; | ||
| 199 | int ret; | ||
| 200 | |||
| 201 | if ((ch_setup->xmirror) || (ch_setup->ymirror) || (ch_setup->rotate)) { | ||
| 202 | standard = 0; | ||
| 203 | |||
| 204 | orientation = BIT(1); /* always set 9-bit-bus */ | ||
| 205 | if (ch_setup->xmirror) | ||
| 206 | orientation |= BIT(4); | ||
| 207 | if (ch_setup->ymirror) | ||
| 208 | orientation |= BIT(3); | ||
| 209 | if (ch_setup->rotate) | ||
| 210 | orientation |= BIT(0); | ||
| 211 | } else | ||
| 212 | standard = 1; | ||
| 213 | |||
| 214 | cmds->channelnr = ch_no; | ||
| 215 | |||
| 216 | /* build command string header */ | ||
| 217 | if (standard) { | ||
| 218 | cmds->prestringlen = 32; | ||
| 219 | cmds->poststringlen = 0; | ||
| 220 | } else { | ||
| 221 | cmds->prestringlen = 48; | ||
| 222 | cmds->poststringlen = 16; | ||
| 223 | } | ||
| 224 | |||
| 225 | cmds->format = | ||
| 226 | (u16) ((ch_setup->disp_no << 4) | (BIT(3)) | (ch_setup->format)); | ||
| 227 | cmds->reserved = 0x0; | ||
| 228 | cmds->startaddr_low = (ch_setup->minadr & 0xFFFF); | ||
| 229 | cmds->startaddr_high = (ch_setup->minadr >> 16); | ||
| 230 | |||
| 231 | if ((ch_setup->minadr == 0) && (ch_setup->maxadr == 0) | ||
| 232 | && (ch_setup->xmin == 0) | ||
| 233 | && (ch_setup->ymin == 0) && (ch_setup->xmax == 0) | ||
| 234 | && (ch_setup->ymax == 0)) { | ||
| 235 | cmds->pixdatlen_low = 0; | ||
| 236 | cmds->pixdatlen_high = 0; | ||
| 237 | } else { | ||
| 238 | u32 nbytes = nof_bytes(ch_setup); | ||
| 239 | cmds->pixdatlen_low = (nbytes & 0xFFFF); | ||
| 240 | cmds->pixdatlen_high = (nbytes >> 16); | ||
| 241 | } | ||
| 242 | |||
| 243 | if (ch_setup->slave_trans) | ||
| 244 | cmds->pixdatlen_high |= BIT(15); | ||
| 245 | |||
| 246 | /* build pre-string */ | ||
| 247 | build_disp_window(ch_setup, &dw); | ||
| 248 | |||
| 249 | if (standard) { | ||
| 250 | cmds->precmd[0] = | ||
| 251 | build_command(ch_setup->disp_no, DISP_XMIN_L_REG, 0x99); | ||
| 252 | cmds->precmd[1] = | ||
| 253 | build_command(ch_setup->disp_no, DISP_XMIN_L_REG, | ||
| 254 | dw.xmin_l); | ||
| 255 | cmds->precmd[2] = | ||
| 256 | build_command(ch_setup->disp_no, DISP_XMIN_H_REG, | ||
| 257 | dw.xmin_h); | ||
| 258 | cmds->precmd[3] = | ||
| 259 | build_command(ch_setup->disp_no, DISP_YMIN_REG, dw.ymin); | ||
| 260 | cmds->precmd[4] = | ||
| 261 | build_command(ch_setup->disp_no, DISP_XMAX_L_REG, | ||
| 262 | dw.xmax_l); | ||
| 263 | cmds->precmd[5] = | ||
| 264 | build_command(ch_setup->disp_no, DISP_XMAX_H_REG, | ||
| 265 | dw.xmax_h); | ||
| 266 | cmds->precmd[6] = | ||
| 267 | build_command(ch_setup->disp_no, DISP_YMAX_REG, dw.ymax); | ||
| 268 | cmds->precmd[7] = | ||
| 269 | build_double_index(ch_setup->disp_no, DISP_PIXEL_REG); | ||
| 270 | } else { | ||
| 271 | if (dw.xmin_l == ch_no) | ||
| 272 | cmds->precmd[0] = | ||
| 273 | build_command(ch_setup->disp_no, DISP_XMIN_L_REG, | ||
| 274 | 0x99); | ||
| 275 | else | ||
| 276 | cmds->precmd[0] = | ||
| 277 | build_command(ch_setup->disp_no, DISP_XMIN_L_REG, | ||
| 278 | ch_no); | ||
| 279 | |||
| 280 | cmds->precmd[1] = | ||
| 281 | build_command(ch_setup->disp_no, DISP_XMIN_L_REG, | ||
| 282 | dw.xmin_l); | ||
| 283 | cmds->precmd[2] = | ||
| 284 | build_command(ch_setup->disp_no, DISP_XMIN_H_REG, | ||
| 285 | dw.xmin_h); | ||
| 286 | cmds->precmd[3] = | ||
| 287 | build_command(ch_setup->disp_no, DISP_YMIN_REG, dw.ymin); | ||
| 288 | cmds->precmd[4] = | ||
| 289 | build_command(ch_setup->disp_no, DISP_XMAX_L_REG, | ||
| 290 | dw.xmax_l); | ||
| 291 | cmds->precmd[5] = | ||
| 292 | build_command(ch_setup->disp_no, DISP_XMAX_H_REG, | ||
| 293 | dw.xmax_h); | ||
| 294 | cmds->precmd[6] = | ||
| 295 | build_command(ch_setup->disp_no, DISP_YMAX_REG, dw.ymax); | ||
| 296 | cmds->precmd[7] = | ||
| 297 | build_command(ch_setup->disp_no, DISP_1_REG, orientation); | ||
| 298 | cmds->precmd[8] = | ||
| 299 | build_double_index(ch_setup->disp_no, DISP_PIXEL_REG); | ||
| 300 | cmds->precmd[9] = | ||
| 301 | build_double_index(ch_setup->disp_no, DISP_PIXEL_REG); | ||
| 302 | cmds->precmd[0xA] = | ||
| 303 | build_double_index(ch_setup->disp_no, DISP_PIXEL_REG); | ||
| 304 | cmds->precmd[0xB] = | ||
| 305 | build_double_index(ch_setup->disp_no, DISP_PIXEL_REG); | ||
| 306 | cmds->postcmd[0] = | ||
| 307 | build_command(ch_setup->disp_no, DISP_1_REG, BIT(1)); | ||
| 308 | cmds->postcmd[1] = | ||
| 309 | build_command(ch_setup->disp_no, DISP_DUMMY1_REG, 1); | ||
| 310 | cmds->postcmd[2] = | ||
| 311 | build_command(ch_setup->disp_no, DISP_DUMMY1_REG, 2); | ||
| 312 | cmds->postcmd[3] = | ||
| 313 | build_command(ch_setup->disp_no, DISP_DUMMY1_REG, 3); | ||
| 314 | } | ||
| 315 | |||
| 316 | if ((ret = put_cmd_string(cmds_c)) != 0) { | ||
| 317 | return ret; | ||
| 318 | } | ||
| 319 | |||
| 320 | chan.channelnr = cmds->channelnr; | ||
| 321 | chan.dum_ch_min = ch_setup->dirtybuffer + ch_setup->minadr; | ||
| 322 | chan.dum_ch_max = ch_setup->dirtybuffer + ch_setup->maxadr; | ||
| 323 | chan.dum_ch_conf = 0x002; | ||
| 324 | chan.dum_ch_ctrl = 0x04; | ||
| 325 | |||
| 326 | put_channel(chan); | ||
| 327 | |||
| 328 | return 0; | ||
| 329 | } | ||
| 330 | |||
| 331 | static u32 display_open(int ch_no, int auto_update, u32 * dirty_buffer, | ||
| 332 | u32 * frame_buffer, u32 xpos, u32 ypos, u32 w, u32 h) | ||
| 333 | { | ||
| 334 | |||
| 335 | struct dum_ch_setup k; | ||
| 336 | int ret; | ||
| 337 | |||
| 338 | /* keep width & height within display area */ | ||
| 339 | if ((xpos + w) > DISP_MAX_X_SIZE) | ||
| 340 | w = DISP_MAX_X_SIZE - xpos; | ||
| 341 | |||
| 342 | if ((ypos + h) > DISP_MAX_Y_SIZE) | ||
| 343 | h = DISP_MAX_Y_SIZE - ypos; | ||
| 344 | |||
| 345 | /* assume 1 display only */ | ||
| 346 | k.disp_no = 0; | ||
| 347 | k.xmin = xpos; | ||
| 348 | k.ymin = ypos; | ||
| 349 | k.xmax = xpos + (w - 1); | ||
| 350 | k.ymax = ypos + (h - 1); | ||
| 351 | |||
| 352 | /* adjust min and max values if necessary */ | ||
| 353 | if (k.xmin > DISP_MAX_X_SIZE - 1) | ||
| 354 | k.xmin = DISP_MAX_X_SIZE - 1; | ||
| 355 | if (k.ymin > DISP_MAX_Y_SIZE - 1) | ||
| 356 | k.ymin = DISP_MAX_Y_SIZE - 1; | ||
| 357 | |||
| 358 | if (k.xmax > DISP_MAX_X_SIZE - 1) | ||
| 359 | k.xmax = DISP_MAX_X_SIZE - 1; | ||
| 360 | if (k.ymax > DISP_MAX_Y_SIZE - 1) | ||
| 361 | k.ymax = DISP_MAX_Y_SIZE - 1; | ||
| 362 | |||
| 363 | k.xmirror = 0; | ||
| 364 | k.ymirror = 0; | ||
| 365 | k.rotate = 0; | ||
| 366 | k.minadr = (u32) frame_buffer; | ||
| 367 | k.maxadr = (u32) frame_buffer + (((w - 1) << 10) | ((h << 2) - 2)); | ||
| 368 | k.pad = PAD_1024; | ||
| 369 | k.dirtybuffer = (u32) dirty_buffer; | ||
| 370 | k.format = RGB888; | ||
| 371 | k.hwdirty = 0; | ||
| 372 | k.slave_trans = 0; | ||
| 373 | |||
| 374 | ret = dum_ch_setup(ch_no, &k); | ||
| 375 | |||
| 376 | return ret; | ||
| 377 | } | ||
| 378 | |||
| 379 | static void lcd_reset(void) | ||
| 380 | { | ||
| 381 | u32 *dum_pio_base = (u32 *)IO_ADDRESS(PNX4008_PIO_BASE); | ||
| 382 | |||
| 383 | udelay(1); | ||
| 384 | iowrite32(BIT(19), &dum_pio_base[2]); | ||
| 385 | udelay(1); | ||
| 386 | iowrite32(BIT(19), &dum_pio_base[1]); | ||
| 387 | udelay(1); | ||
| 388 | } | ||
| 389 | |||
| 390 | static int dum_init(struct platform_device *pdev) | ||
| 391 | { | ||
| 392 | struct clk *clk; | ||
| 393 | |||
| 394 | /* enable DUM clock */ | ||
| 395 | clk = clk_get(&pdev->dev, "dum_ck"); | ||
| 396 | if (IS_ERR(clk)) { | ||
| 397 | printk(KERN_ERR "pnx4008_dum: Unable to access DUM clock\n"); | ||
| 398 | return PTR_ERR(clk); | ||
| 399 | } | ||
| 400 | |||
| 401 | clk_set_rate(clk, 1); | ||
| 402 | clk_put(clk); | ||
| 403 | |||
| 404 | DUM_CTRL = V_DUM_RESET; | ||
| 405 | |||
| 406 | /* set priority to "round-robin". All other params to "false" */ | ||
| 407 | DUM_CONF = BIT(9); | ||
| 408 | |||
| 409 | /* Display 1 */ | ||
| 410 | DUM_WTCFG1 = PNX4008_DUM_WT_CFG; | ||
| 411 | DUM_RTCFG1 = PNX4008_DUM_RT_CFG; | ||
| 412 | DUM_TCFG = PNX4008_DUM_T_CFG; | ||
| 413 | |||
| 414 | return 0; | ||
| 415 | } | ||
| 416 | |||
| 417 | static void dum_chan_init(void) | ||
| 418 | { | ||
| 419 | int i = 0, ch = 0; | ||
| 420 | u32 *cmdptrs; | ||
| 421 | u32 *cmdstrings; | ||
| 422 | |||
| 423 | DUM_COM_BASE = | ||
| 424 | CMDSTRING_BASEADDR + BYTES_PER_CMDSTRING * NR_OF_CMDSTRINGS; | ||
| 425 | |||
| 426 | if ((cmdptrs = | ||
| 427 | (u32 *) ioremap_nocache(DUM_COM_BASE, | ||
| 428 | sizeof(u32) * NR_OF_CMDSTRINGS)) == NULL) | ||
| 429 | return; | ||
| 430 | |||
| 431 | for (ch = 0; ch < NR_OF_CMDSTRINGS; ch++) | ||
| 432 | iowrite32(CMDSTRING_BASEADDR + BYTES_PER_CMDSTRING * ch, | ||
| 433 | cmdptrs + ch); | ||
| 434 | |||
| 435 | for (ch = 0; ch < MAX_DUM_CHANNELS; ch++) | ||
| 436 | clear_channel(ch); | ||
| 437 | |||
| 438 | /* Clear the cmdstrings */ | ||
| 439 | cmdstrings = | ||
| 440 | (u32 *)ioremap_nocache(*cmdptrs, | ||
| 441 | BYTES_PER_CMDSTRING * NR_OF_CMDSTRINGS); | ||
| 442 | |||
| 443 | if (!cmdstrings) | ||
| 444 | goto out; | ||
| 445 | |||
| 446 | for (i = 0; i < NR_OF_CMDSTRINGS * BYTES_PER_CMDSTRING / sizeof(u32); | ||
| 447 | i++) | ||
| 448 | iowrite32(0, cmdstrings + i); | ||
| 449 | |||
| 450 | iounmap((u32 *)cmdstrings); | ||
| 451 | |||
| 452 | out: | ||
| 453 | iounmap((u32 *)cmdptrs); | ||
| 454 | } | ||
| 455 | |||
| 456 | static void lcd_init(void) | ||
| 457 | { | ||
| 458 | lcd_reset(); | ||
| 459 | |||
| 460 | DUM_OUTP_FORMAT1 = 0; /* RGB666 */ | ||
| 461 | |||
| 462 | udelay(1); | ||
| 463 | iowrite32(V_LCD_STANDBY_OFF, dum_data.slave_virt_base); | ||
| 464 | udelay(1); | ||
| 465 | iowrite32(V_LCD_USE_9BIT_BUS, dum_data.slave_virt_base); | ||
| 466 | udelay(1); | ||
| 467 | iowrite32(V_LCD_SYNC_RISE_L, dum_data.slave_virt_base); | ||
| 468 | udelay(1); | ||
| 469 | iowrite32(V_LCD_SYNC_RISE_H, dum_data.slave_virt_base); | ||
| 470 | udelay(1); | ||
| 471 | iowrite32(V_LCD_SYNC_FALL_L, dum_data.slave_virt_base); | ||
| 472 | udelay(1); | ||
| 473 | iowrite32(V_LCD_SYNC_FALL_H, dum_data.slave_virt_base); | ||
| 474 | udelay(1); | ||
| 475 | iowrite32(V_LCD_SYNC_ENABLE, dum_data.slave_virt_base); | ||
| 476 | udelay(1); | ||
| 477 | iowrite32(V_LCD_DISPLAY_ON, dum_data.slave_virt_base); | ||
| 478 | udelay(1); | ||
| 479 | } | ||
| 480 | |||
| 481 | /* Interface exported to framebuffer drivers */ | ||
| 482 | |||
| 483 | int pnx4008_get_fb_addresses(int fb_type, void **virt_addr, | ||
| 484 | dma_addr_t *phys_addr, int *fb_length) | ||
| 485 | { | ||
| 486 | int i; | ||
| 487 | int ret = -1; | ||
| 488 | for (i = 0; i < ARRAY_SIZE(fb_addr); i++) | ||
| 489 | if (fb_addr[i].fb_type == fb_type) { | ||
| 490 | *virt_addr = (void *)(dum_data.lcd_virt_start + | ||
| 491 | fb_addr[i].addr_offset); | ||
| 492 | *phys_addr = | ||
| 493 | dum_data.lcd_phys_start + fb_addr[i].addr_offset; | ||
| 494 | *fb_length = fb_addr[i].fb_length; | ||
| 495 | ret = 0; | ||
| 496 | break; | ||
| 497 | } | ||
| 498 | |||
| 499 | return ret; | ||
| 500 | } | ||
| 501 | |||
| 502 | EXPORT_SYMBOL(pnx4008_get_fb_addresses); | ||
| 503 | |||
| 504 | int pnx4008_alloc_dum_channel(int dev_id) | ||
| 505 | { | ||
| 506 | int i = 0; | ||
| 507 | |||
| 508 | while ((i < MAX_DUM_CHANNELS) && (dum_data.fb_owning_channel[i] != -1)) | ||
| 509 | i++; | ||
| 510 | |||
| 511 | if (i == MAX_DUM_CHANNELS) | ||
| 512 | return -ENORESOURCESLEFT; | ||
| 513 | else { | ||
| 514 | dum_data.fb_owning_channel[i] = dev_id; | ||
| 515 | return i; | ||
| 516 | } | ||
| 517 | } | ||
| 518 | |||
| 519 | EXPORT_SYMBOL(pnx4008_alloc_dum_channel); | ||
| 520 | |||
| 521 | int pnx4008_free_dum_channel(int channr, int dev_id) | ||
| 522 | { | ||
| 523 | if (channr < 0 || channr > MAX_DUM_CHANNELS) | ||
| 524 | return -EINVAL; | ||
| 525 | else if (dum_data.fb_owning_channel[channr] != dev_id) | ||
| 526 | return -EFBNOTOWNER; | ||
| 527 | else { | ||
| 528 | clear_channel(channr); | ||
| 529 | dum_data.fb_owning_channel[channr] = -1; | ||
| 530 | } | ||
| 531 | |||
| 532 | return 0; | ||
| 533 | } | ||
| 534 | |||
| 535 | EXPORT_SYMBOL(pnx4008_free_dum_channel); | ||
| 536 | |||
| 537 | int pnx4008_put_dum_channel_uf(struct dumchannel_uf chan_uf, int dev_id) | ||
| 538 | { | ||
| 539 | int i = chan_uf.channelnr; | ||
| 540 | int ret; | ||
| 541 | |||
| 542 | if (i < 0 || i > MAX_DUM_CHANNELS) | ||
| 543 | return -EINVAL; | ||
| 544 | else if (dum_data.fb_owning_channel[i] != dev_id) | ||
| 545 | return -EFBNOTOWNER; | ||
| 546 | else if ((ret = | ||
| 547 | display_open(chan_uf.channelnr, 0, chan_uf.dirty, | ||
| 548 | chan_uf.source, chan_uf.y_offset, | ||
| 549 | chan_uf.x_offset, chan_uf.height, | ||
| 550 | chan_uf.width)) != 0) | ||
| 551 | return ret; | ||
| 552 | else { | ||
| 553 | dum_data.chan_uf_store[i].dirty = chan_uf.dirty; | ||
| 554 | dum_data.chan_uf_store[i].source = chan_uf.source; | ||
| 555 | dum_data.chan_uf_store[i].x_offset = chan_uf.x_offset; | ||
| 556 | dum_data.chan_uf_store[i].y_offset = chan_uf.y_offset; | ||
| 557 | dum_data.chan_uf_store[i].width = chan_uf.width; | ||
| 558 | dum_data.chan_uf_store[i].height = chan_uf.height; | ||
| 559 | } | ||
| 560 | |||
| 561 | return 0; | ||
| 562 | } | ||
| 563 | |||
| 564 | EXPORT_SYMBOL(pnx4008_put_dum_channel_uf); | ||
| 565 | |||
| 566 | int pnx4008_set_dum_channel_sync(int channr, int val, int dev_id) | ||
| 567 | { | ||
| 568 | if (channr < 0 || channr > MAX_DUM_CHANNELS) | ||
| 569 | return -EINVAL; | ||
| 570 | else if (dum_data.fb_owning_channel[channr] != dev_id) | ||
| 571 | return -EFBNOTOWNER; | ||
| 572 | else { | ||
| 573 | if (val == CONF_SYNC_ON) { | ||
| 574 | DUM_CH_CONF(channr) |= CONF_SYNCENABLE; | ||
| 575 | DUM_CH_CONF(channr) |= DUM_CHANNEL_CFG_SYNC_MASK | | ||
| 576 | DUM_CHANNEL_CFG_SYNC_MASK_SET; | ||
| 577 | } else if (val == CONF_SYNC_OFF) | ||
| 578 | DUM_CH_CONF(channr) &= ~CONF_SYNCENABLE; | ||
| 579 | else | ||
| 580 | return -EINVAL; | ||
| 581 | } | ||
| 582 | |||
| 583 | return 0; | ||
| 584 | } | ||
| 585 | |||
| 586 | EXPORT_SYMBOL(pnx4008_set_dum_channel_sync); | ||
| 587 | |||
| 588 | int pnx4008_set_dum_channel_dirty_detect(int channr, int val, int dev_id) | ||
| 589 | { | ||
| 590 | if (channr < 0 || channr > MAX_DUM_CHANNELS) | ||
| 591 | return -EINVAL; | ||
| 592 | else if (dum_data.fb_owning_channel[channr] != dev_id) | ||
| 593 | return -EFBNOTOWNER; | ||
| 594 | else { | ||
| 595 | if (val == CONF_DIRTYDETECTION_ON) | ||
| 596 | DUM_CH_CONF(channr) |= CONF_DIRTYENABLE; | ||
| 597 | else if (val == CONF_DIRTYDETECTION_OFF) | ||
| 598 | DUM_CH_CONF(channr) &= ~CONF_DIRTYENABLE; | ||
| 599 | else | ||
| 600 | return -EINVAL; | ||
| 601 | } | ||
| 602 | |||
| 603 | return 0; | ||
| 604 | } | ||
| 605 | |||
| 606 | EXPORT_SYMBOL(pnx4008_set_dum_channel_dirty_detect); | ||
| 607 | |||
| 608 | #if 0 /* Functions not used currently, but likely to be used in future */ | ||
| 609 | |||
| 610 | static int get_channel(struct dumchannel *p_chan) | ||
| 611 | { | ||
| 612 | int i = p_chan->channelnr; | ||
| 613 | |||
| 614 | if (i < 0 || i > MAX_DUM_CHANNELS) | ||
| 615 | return -EINVAL; | ||
| 616 | else { | ||
| 617 | p_chan->dum_ch_min = DUM_CH_MIN(i); | ||
| 618 | p_chan->dum_ch_max = DUM_CH_MAX(i); | ||
| 619 | p_chan->dum_ch_conf = DUM_CH_CONF(i); | ||
| 620 | p_chan->dum_ch_stat = DUM_CH_STAT(i); | ||
| 621 | p_chan->dum_ch_ctrl = 0; /* WriteOnly control register */ | ||
| 622 | } | ||
| 623 | |||
| 624 | return 0; | ||
| 625 | } | ||
| 626 | |||
| 627 | int pnx4008_get_dum_channel_uf(struct dumchannel_uf *p_chan_uf, int dev_id) | ||
| 628 | { | ||
| 629 | int i = p_chan_uf->channelnr; | ||
| 630 | |||
| 631 | if (i < 0 || i > MAX_DUM_CHANNELS) | ||
| 632 | return -EINVAL; | ||
| 633 | else if (dum_data.fb_owning_channel[i] != dev_id) | ||
| 634 | return -EFBNOTOWNER; | ||
| 635 | else { | ||
| 636 | p_chan_uf->dirty = dum_data.chan_uf_store[i].dirty; | ||
| 637 | p_chan_uf->source = dum_data.chan_uf_store[i].source; | ||
| 638 | p_chan_uf->x_offset = dum_data.chan_uf_store[i].x_offset; | ||
| 639 | p_chan_uf->y_offset = dum_data.chan_uf_store[i].y_offset; | ||
| 640 | p_chan_uf->width = dum_data.chan_uf_store[i].width; | ||
| 641 | p_chan_uf->height = dum_data.chan_uf_store[i].height; | ||
| 642 | } | ||
| 643 | |||
| 644 | return 0; | ||
| 645 | } | ||
| 646 | |||
| 647 | EXPORT_SYMBOL(pnx4008_get_dum_channel_uf); | ||
| 648 | |||
| 649 | int pnx4008_get_dum_channel_config(int channr, int dev_id) | ||
| 650 | { | ||
| 651 | int ret; | ||
| 652 | struct dumchannel chan; | ||
| 653 | |||
| 654 | if (channr < 0 || channr > MAX_DUM_CHANNELS) | ||
| 655 | return -EINVAL; | ||
| 656 | else if (dum_data.fb_owning_channel[channr] != dev_id) | ||
| 657 | return -EFBNOTOWNER; | ||
| 658 | else { | ||
| 659 | chan.channelnr = channr; | ||
| 660 | if ((ret = get_channel(&chan)) != 0) | ||
| 661 | return ret; | ||
| 662 | } | ||
| 663 | |||
| 664 | return (chan.dum_ch_conf & DUM_CHANNEL_CFG_MASK); | ||
| 665 | } | ||
| 666 | |||
| 667 | EXPORT_SYMBOL(pnx4008_get_dum_channel_config); | ||
| 668 | |||
| 669 | int pnx4008_force_update_dum_channel(int channr, int dev_id) | ||
| 670 | { | ||
| 671 | if (channr < 0 || channr > MAX_DUM_CHANNELS) | ||
| 672 | return -EINVAL; | ||
| 673 | |||
| 674 | else if (dum_data.fb_owning_channel[channr] != dev_id) | ||
| 675 | return -EFBNOTOWNER; | ||
| 676 | else | ||
| 677 | DUM_CH_CTRL(channr) = CTRL_SETDIRTY; | ||
| 678 | |||
| 679 | return 0; | ||
| 680 | } | ||
| 681 | |||
| 682 | EXPORT_SYMBOL(pnx4008_force_update_dum_channel); | ||
| 683 | |||
| 684 | #endif | ||
| 685 | |||
| 686 | int pnx4008_sdum_mmap(struct fb_info *info, struct vm_area_struct *vma, | ||
| 687 | struct device *dev) | ||
| 688 | { | ||
| 689 | unsigned long off = vma->vm_pgoff << PAGE_SHIFT; | ||
| 690 | |||
| 691 | if (off < info->fix.smem_len) { | ||
| 692 | vma->vm_pgoff += 1; | ||
| 693 | return dma_mmap_writecombine(dev, vma, | ||
| 694 | (void *)dum_data.lcd_virt_start, | ||
| 695 | dum_data.lcd_phys_start, | ||
| 696 | FB_DMA_SIZE); | ||
| 697 | } | ||
| 698 | return -EINVAL; | ||
| 699 | } | ||
| 700 | |||
| 701 | EXPORT_SYMBOL(pnx4008_sdum_mmap); | ||
| 702 | |||
| 703 | int pnx4008_set_dum_exit_notification(int dev_id) | ||
| 704 | { | ||
| 705 | int i; | ||
| 706 | |||
| 707 | for (i = 0; i < MAX_DUM_CHANNELS; i++) | ||
| 708 | if (dum_data.fb_owning_channel[i] == dev_id) | ||
| 709 | return -ERESOURCESNOTFREED; | ||
| 710 | |||
| 711 | return 0; | ||
| 712 | } | ||
| 713 | |||
| 714 | EXPORT_SYMBOL(pnx4008_set_dum_exit_notification); | ||
| 715 | |||
| 716 | /* Platform device driver for DUM */ | ||
| 717 | |||
| 718 | static int sdum_suspend(struct platform_device *pdev, pm_message_t state) | ||
| 719 | { | ||
| 720 | int retval = 0; | ||
| 721 | struct clk *clk; | ||
| 722 | |||
| 723 | clk = clk_get(0, "dum_ck"); | ||
| 724 | if (!IS_ERR(clk)) { | ||
| 725 | clk_set_rate(clk, 0); | ||
| 726 | clk_put(clk); | ||
| 727 | } else | ||
| 728 | retval = PTR_ERR(clk); | ||
| 729 | |||
| 730 | /* disable BAC */ | ||
| 731 | DUM_CTRL = V_BAC_DISABLE_IDLE; | ||
| 732 | |||
| 733 | /* LCD standby & turn off display */ | ||
| 734 | lcd_reset(); | ||
| 735 | |||
| 736 | return retval; | ||
| 737 | } | ||
| 738 | |||
| 739 | static int sdum_resume(struct platform_device *pdev) | ||
| 740 | { | ||
| 741 | int retval = 0; | ||
| 742 | struct clk *clk; | ||
| 743 | |||
| 744 | clk = clk_get(0, "dum_ck"); | ||
| 745 | if (!IS_ERR(clk)) { | ||
| 746 | clk_set_rate(clk, 1); | ||
| 747 | clk_put(clk); | ||
| 748 | } else | ||
| 749 | retval = PTR_ERR(clk); | ||
| 750 | |||
| 751 | /* wait for BAC disable */ | ||
| 752 | DUM_CTRL = V_BAC_DISABLE_TRIG; | ||
| 753 | |||
| 754 | while (DUM_CTRL & BAC_ENABLED) | ||
| 755 | udelay(10); | ||
| 756 | |||
| 757 | /* re-init LCD */ | ||
| 758 | lcd_init(); | ||
| 759 | |||
| 760 | /* enable BAC and reset MUX */ | ||
| 761 | DUM_CTRL = V_BAC_ENABLE; | ||
| 762 | udelay(1); | ||
| 763 | DUM_CTRL = V_MUX_RESET; | ||
| 764 | return 0; | ||
| 765 | } | ||
| 766 | |||
| 767 | static int __devinit sdum_probe(struct platform_device *pdev) | ||
| 768 | { | ||
| 769 | int ret = 0, i = 0; | ||
| 770 | |||
| 771 | /* map frame buffer */ | ||
| 772 | dum_data.lcd_virt_start = (u32) dma_alloc_writecombine(&pdev->dev, | ||
| 773 | FB_DMA_SIZE, | ||
| 774 | &dum_data.lcd_phys_start, | ||
| 775 | GFP_KERNEL); | ||
| 776 | |||
| 777 | if (!dum_data.lcd_virt_start) { | ||
| 778 | ret = -ENOMEM; | ||
| 779 | goto out_3; | ||
| 780 | } | ||
| 781 | |||
| 782 | /* map slave registers */ | ||
| 783 | dum_data.slave_phys_base = PNX4008_DUM_SLAVE_BASE; | ||
| 784 | dum_data.slave_virt_base = | ||
| 785 | (u32 *) ioremap_nocache(dum_data.slave_phys_base, sizeof(u32)); | ||
| 786 | |||
| 787 | if (dum_data.slave_virt_base == NULL) { | ||
| 788 | ret = -ENOMEM; | ||
| 789 | goto out_2; | ||
| 790 | } | ||
| 791 | |||
| 792 | /* initialize DUM and LCD display */ | ||
| 793 | ret = dum_init(pdev); | ||
| 794 | if (ret) | ||
| 795 | goto out_1; | ||
| 796 | |||
| 797 | dum_chan_init(); | ||
| 798 | lcd_init(); | ||
| 799 | |||
| 800 | DUM_CTRL = V_BAC_ENABLE; | ||
| 801 | udelay(1); | ||
| 802 | DUM_CTRL = V_MUX_RESET; | ||
| 803 | |||
| 804 | /* set decode address and sync clock divider */ | ||
| 805 | DUM_DECODE = dum_data.lcd_phys_start & DUM_DECODE_MASK; | ||
| 806 | DUM_CLK_DIV = PNX4008_DUM_CLK_DIV; | ||
| 807 | |||
| 808 | for (i = 0; i < MAX_DUM_CHANNELS; i++) | ||
| 809 | dum_data.fb_owning_channel[i] = -1; | ||
| 810 | |||
| 811 | /*setup wakeup interrupt */ | ||
| 812 | start_int_set_rising_edge(SE_DISP_SYNC_INT); | ||
| 813 | start_int_ack(SE_DISP_SYNC_INT); | ||
| 814 | start_int_umask(SE_DISP_SYNC_INT); | ||
| 815 | |||
| 816 | return 0; | ||
| 817 | |||
| 818 | out_1: | ||
| 819 | iounmap((void *)dum_data.slave_virt_base); | ||
| 820 | out_2: | ||
| 821 | dma_free_writecombine(&pdev->dev, FB_DMA_SIZE, | ||
| 822 | (void *)dum_data.lcd_virt_start, | ||
| 823 | dum_data.lcd_phys_start); | ||
| 824 | out_3: | ||
| 825 | return ret; | ||
| 826 | } | ||
| 827 | |||
| 828 | static int sdum_remove(struct platform_device *pdev) | ||
| 829 | { | ||
| 830 | struct clk *clk; | ||
| 831 | |||
| 832 | start_int_mask(SE_DISP_SYNC_INT); | ||
| 833 | |||
| 834 | clk = clk_get(0, "dum_ck"); | ||
| 835 | if (!IS_ERR(clk)) { | ||
| 836 | clk_set_rate(clk, 0); | ||
| 837 | clk_put(clk); | ||
| 838 | } | ||
| 839 | |||
| 840 | iounmap((void *)dum_data.slave_virt_base); | ||
| 841 | |||
| 842 | dma_free_writecombine(&pdev->dev, FB_DMA_SIZE, | ||
| 843 | (void *)dum_data.lcd_virt_start, | ||
| 844 | dum_data.lcd_phys_start); | ||
| 845 | |||
| 846 | return 0; | ||
| 847 | } | ||
| 848 | |||
| 849 | static struct platform_driver sdum_driver = { | ||
| 850 | .driver = { | ||
| 851 | .name = "pnx4008-sdum", | ||
| 852 | }, | ||
| 853 | .probe = sdum_probe, | ||
| 854 | .remove = sdum_remove, | ||
| 855 | .suspend = sdum_suspend, | ||
| 856 | .resume = sdum_resume, | ||
| 857 | }; | ||
| 858 | |||
| 859 | int __init sdum_init(void) | ||
| 860 | { | ||
| 861 | return platform_driver_register(&sdum_driver); | ||
| 862 | } | ||
| 863 | |||
| 864 | static void __exit sdum_exit(void) | ||
| 865 | { | ||
| 866 | platform_driver_unregister(&sdum_driver); | ||
| 867 | }; | ||
| 868 | |||
| 869 | module_init(sdum_init); | ||
| 870 | module_exit(sdum_exit); | ||
| 871 | |||
| 872 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/video/pnx4008/sdum.h b/drivers/video/pnx4008/sdum.h new file mode 100644 index 00000000000..189c3d64138 --- /dev/null +++ b/drivers/video/pnx4008/sdum.h | |||
| @@ -0,0 +1,136 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2005 Philips Semiconductors | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License as published by | ||
| 6 | * the Free Software Foundation; either version 2, or (at your option) | ||
| 7 | * any later version. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope that it will be useful, | ||
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | * GNU General Public License for more details. | ||
| 13 | * | ||
| 14 | * You should have received a copy of the GNU General Public License | ||
| 15 | * along with this program; see the file COPYING. If not, write to | ||
| 16 | * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
| 17 | * Boston, MA 02111-1307, USA, or http://www.gnu.org/licenses/gpl.html | ||
| 18 | */ | ||
| 19 | |||
| 20 | #define MAX_DUM_CHANNELS 64 | ||
| 21 | |||
| 22 | #define RGB_MEM_WINDOW(x) (0x10000000 + (x)*0x00100000) | ||
| 23 | |||
| 24 | #define QCIF_OFFSET(x) (((x) == 0) ? 0x00000: ((x) == 1) ? 0x30000: -1) | ||
| 25 | #define CIF_OFFSET(x) (((x) == 0) ? 0x00000: ((x) == 1) ? 0x60000: -1) | ||
| 26 | |||
| 27 | #define CTRL_SETDIRTY (0x00000001) | ||
| 28 | #define CONF_DIRTYENABLE (0x00000020) | ||
| 29 | #define CONF_SYNCENABLE (0x00000004) | ||
| 30 | |||
| 31 | #define DIRTY_ENABLED(conf) ((conf) & 0x0020) | ||
| 32 | #define SYNC_ENABLED(conf) ((conf) & 0x0004) | ||
| 33 | |||
| 34 | /* Display 1 & 2 Write Timing Configuration */ | ||
| 35 | #define PNX4008_DUM_WT_CFG 0x00372000 | ||
| 36 | |||
| 37 | /* Display 1 & 2 Read Timing Configuration */ | ||
| 38 | #define PNX4008_DUM_RT_CFG 0x00003A47 | ||
| 39 | |||
| 40 | /* DUM Transit State Timing Configuration */ | ||
| 41 | #define PNX4008_DUM_T_CFG 0x1D /* 29 HCLK cycles */ | ||
| 42 | |||
| 43 | /* DUM Sync count clock divider */ | ||
| 44 | #define PNX4008_DUM_CLK_DIV 0x02DD | ||
| 45 | |||
| 46 | /* Memory size for framebuffer, allocated through dma_alloc_writecombine(). | ||
| 47 | * Must be PAGE aligned | ||
| 48 | */ | ||
| 49 | #define FB_DMA_SIZE (PAGE_ALIGN(SZ_1M + PAGE_SIZE)) | ||
| 50 | |||
| 51 | #define OFFSET_RGBBUFFER (0xB0000) | ||
| 52 | #define OFFSET_YUVBUFFER (0x00000) | ||
| 53 | |||
| 54 | #define YUVBUFFER (lcd_video_start + OFFSET_YUVBUFFER) | ||
| 55 | #define RGBBUFFER (lcd_video_start + OFFSET_RGBBUFFER) | ||
| 56 | |||
| 57 | #define CMDSTRING_BASEADDR (0x00C000) /* iram */ | ||
| 58 | #define BYTES_PER_CMDSTRING (0x80) | ||
| 59 | #define NR_OF_CMDSTRINGS (64) | ||
| 60 | |||
| 61 | #define MAX_NR_PRESTRINGS (0x40) | ||
| 62 | #define MAX_NR_POSTSTRINGS (0x40) | ||
| 63 | |||
| 64 | /* various mask definitions */ | ||
| 65 | #define DUM_CLK_ENABLE 0x01 | ||
| 66 | #define DUM_CLK_DISABLE 0 | ||
| 67 | #define DUM_DECODE_MASK 0x1FFFFFFF | ||
| 68 | #define DUM_CHANNEL_CFG_MASK 0x01FF | ||
| 69 | #define DUM_CHANNEL_CFG_SYNC_MASK 0xFFFE00FF | ||
| 70 | #define DUM_CHANNEL_CFG_SYNC_MASK_SET 0x0CA00 | ||
| 71 | |||
| 72 | #define SDUM_RETURNVAL_BASE (0x500) | ||
| 73 | |||
| 74 | #define CONF_SYNC_OFF (0x602) | ||
| 75 | #define CONF_SYNC_ON (0x603) | ||
| 76 | |||
| 77 | #define CONF_DIRTYDETECTION_OFF (0x600) | ||
| 78 | #define CONF_DIRTYDETECTION_ON (0x601) | ||
| 79 | |||
| 80 | struct dumchannel_uf { | ||
| 81 | int channelnr; | ||
| 82 | u32 *dirty; | ||
| 83 | u32 *source; | ||
| 84 | u32 x_offset; | ||
| 85 | u32 y_offset; | ||
| 86 | u32 width; | ||
| 87 | u32 height; | ||
| 88 | }; | ||
| 89 | |||
| 90 | enum { | ||
| 91 | FB_TYPE_YUV, | ||
| 92 | FB_TYPE_RGB | ||
| 93 | }; | ||
| 94 | |||
| 95 | struct cmdstring { | ||
| 96 | int channelnr; | ||
| 97 | uint16_t prestringlen; | ||
| 98 | uint16_t poststringlen; | ||
| 99 | uint16_t format; | ||
| 100 | uint16_t reserved; | ||
| 101 | uint16_t startaddr_low; | ||
| 102 | uint16_t startaddr_high; | ||
| 103 | uint16_t pixdatlen_low; | ||
| 104 | uint16_t pixdatlen_high; | ||
| 105 | u32 precmd[MAX_NR_PRESTRINGS]; | ||
| 106 | u32 postcmd[MAX_NR_POSTSTRINGS]; | ||
| 107 | |||
| 108 | }; | ||
| 109 | |||
| 110 | struct dumchannel { | ||
| 111 | int channelnr; | ||
| 112 | int dum_ch_min; | ||
| 113 | int dum_ch_max; | ||
| 114 | int dum_ch_conf; | ||
| 115 | int dum_ch_stat; | ||
| 116 | int dum_ch_ctrl; | ||
| 117 | }; | ||
| 118 | |||
| 119 | int pnx4008_alloc_dum_channel(int dev_id); | ||
| 120 | int pnx4008_free_dum_channel(int channr, int dev_id); | ||
| 121 | |||
| 122 | int pnx4008_get_dum_channel_uf(struct dumchannel_uf *pChan_uf, int dev_id); | ||
| 123 | int pnx4008_put_dum_channel_uf(struct dumchannel_uf chan_uf, int dev_id); | ||
| 124 | |||
| 125 | int pnx4008_set_dum_channel_sync(int channr, int val, int dev_id); | ||
| 126 | int pnx4008_set_dum_channel_dirty_detect(int channr, int val, int dev_id); | ||
| 127 | |||
| 128 | int pnx4008_force_dum_update_channel(int channr, int dev_id); | ||
| 129 | |||
| 130 | int pnx4008_get_dum_channel_config(int channr, int dev_id); | ||
| 131 | |||
| 132 | int pnx4008_sdum_mmap(struct fb_info *info, struct vm_area_struct *vma, struct device *dev); | ||
| 133 | int pnx4008_set_dum_exit_notification(int dev_id); | ||
| 134 | |||
| 135 | int pnx4008_get_fb_addresses(int fb_type, void **virt_addr, | ||
| 136 | dma_addr_t * phys_addr, int *fb_length); | ||
