2 * File: drivers/video/omap_new/omapfb_main.c
4 * Special optimiSed Screen Interface driver for TI OMAP boards
6 * Copyright (C) 2004 Nokia Corporation
7 * Author: Juha Yrjölä <juha.yrjola@nokia.com>
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by the
11 * Free Software Foundation; either version 2 of the License, or (at your
12 * option) any later version.
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 #include <linux/config.h>
25 #include <linux/module.h>
31 #define OMAP_SOSSI_BASE 0xfffbac00
32 #define SOSSI_ID_REG 0x00
33 #define SOSSI_INIT1_REG 0x04
34 #define SOSSI_INIT2_REG 0x08
35 #define SOSSI_INIT3_REG 0x0c
36 #define SOSSI_FIFO_REG 0x10
37 #define SOSSI_REOTABLE_REG 0x14
38 #define SOSSI_TEARING_REG 0x18
39 #define SOSSI_INIT1B_REG 0x1c
40 #define SOSSI_FIFOB_REG 0x20
42 #define DMA_GSCR 0xfffedc04
43 #define DMA_LCD_CCR 0xfffee3c2
44 #define DMA_LCD_CTRL 0xfffee3c4
45 #define DMA_LCD_LCH_CTRL 0xfffee3ea
47 static int sossi_base = IO_ADDRESS(OMAP_SOSSI_BASE);
49 static inline u32 sossi_read_reg(int reg)
51 return readl(sossi_base + reg);
54 static inline u16 sossi_read_reg16(int reg)
56 return readw(sossi_base + reg);
59 static inline u8 sossi_read_reg8(int reg)
61 return readb(sossi_base + reg);
64 static inline void sossi_write_reg(int reg, u32 value)
66 writel(value, sossi_base + reg);
69 static inline void sossi_write_reg16(int reg, u16 value)
71 writew(value, sossi_base + reg);
74 static inline void sossi_write_reg8(int reg, u8 value)
76 writeb(value, sossi_base + reg);
79 static void sossi_set_bits(int reg, u32 bits)
81 sossi_write_reg(reg, sossi_read_reg(reg) | bits);
84 static void sossi_clear_bits(int reg, u32 bits)
86 sossi_write_reg(reg, sossi_read_reg(reg) & ~bits);
92 printk(" INIT1: 0x%08x\n", sossi_read_reg(SOSSI_INIT1_REG));
93 printk(" INIT2: 0x%08x\n", sossi_read_reg(SOSSI_INIT2_REG));
94 printk(" INIT3: 0x%08x\n", sossi_read_reg(SOSSI_INIT3_REG));
95 printk(" TEARING: 0x%08x\n", sossi_read_reg(SOSSI_TEARING_REG));
96 printk(" INIT1B: 0x%08x\n", sossi_read_reg(SOSSI_INIT1B_REG));
100 static void sossi_dma_init(void)
102 /* OMAP3.1 mapping disable */
103 omap_writel(omap_readl(DMA_GSCR) | (1 << 3), DMA_GSCR);
104 /* Logical channel type to b0100 */
105 omap_writew(omap_readw(DMA_LCD_LCH_CTRL) | (1 << 2), DMA_LCD_LCH_CTRL);
106 /* LCD_DMA dest port to 1 */
107 omap_writew(omap_readw(DMA_LCD_CTRL) | (1 << 8), DMA_LCD_CTRL);
108 /* LCD_CCR OMAP31 comp mode */
109 omap_writew(omap_readw(DMA_LCD_CCR) | (1 << 10), DMA_LCD_CCR);
112 #define MOD_CONF_CTRL_1 0xfffe1110
113 #define CONF_SOSSI_RESET_R (1 << 23)
114 #define CONF_MOD_SOSSI_CLK_EN_R (1 << 16)
120 /* Reset and enable the SoSSI module */
121 l = omap_readl(MOD_CONF_CTRL_1);
122 l |= CONF_SOSSI_RESET_R;
123 omap_writel(l, MOD_CONF_CTRL_1);
124 l &= ~CONF_SOSSI_RESET_R;
125 omap_writel(l, MOD_CONF_CTRL_1);
127 l |= CONF_MOD_SOSSI_CLK_EN_R;
128 /* FIXME: Hardcode divide ratio 3 */
130 omap_writel(l, MOD_CONF_CTRL_1);
132 omap_writel(omap_readl(ARM_IDLECT2) | (1 << 11), ARM_IDLECT2);
133 omap_writel(omap_readl(ARM_IDLECT1) | (1 << 6), ARM_IDLECT1);
137 l = sossi_read_reg(SOSSI_INIT2_REG);
138 /* Enable and reset the SoSSI block */
139 l |= (1 << 0) | (1 << 1);
140 sossi_write_reg(SOSSI_INIT2_REG, l);
141 /* Take SoSSI out of reset */
143 sossi_write_reg(SOSSI_INIT2_REG, l);
145 sossi_write_reg(SOSSI_ID_REG, 0);
146 l = sossi_read_reg(SOSSI_ID_REG);
147 k = sossi_read_reg(SOSSI_ID_REG);
149 if (l != 0x55555555 || k != 0xaaaaaaaa) {
150 printk(KERN_ERR "Invalid SoSSI sync pattern: %08x, %08x\n", l, k);
153 l = sossi_read_reg(SOSSI_ID_REG); /* Component code */
154 l = sossi_read_reg(SOSSI_ID_REG);
155 printk(KERN_INFO "SoSSI rev. %d.%d initialized\n", l >> 16, l & 0xffff);
157 l = sossi_read_reg(SOSSI_INIT1_REG);
158 l |= (1 << 19); /* DMA_MODE */
159 l &= ~(1 << 31); /* REORDERING */
160 sossi_write_reg(SOSSI_INIT1_REG, l);
165 static void set_timings(int tw0, int tw1)
169 l = sossi_read_reg(SOSSI_INIT1_REG);
170 l &= ~((0x0f << 20) | (0x3f << 24));
171 l |= ((tw0 & 0x0f) << 20) | ((tw1 & 0x3f) << 24);
172 sossi_write_reg(SOSSI_INIT1_REG, l);
175 static struct sossi {
179 void sossi_set_xfer_params(int tw0, int tw1, int bus_pick_count, int bus_pick_width)
183 set_timings(tw0, tw1);
184 sossi.bus_pick_width = bus_pick_width;
185 l = ((bus_pick_count - 1) << 5) | ((bus_pick_width - 1) & 0x1f);
186 sossi_write_reg(SOSSI_INIT3_REG, l);
189 void sossi_start_transfer(void)
192 sossi_clear_bits(SOSSI_INIT2_REG, 1 << 4);
194 sossi_clear_bits(SOSSI_INIT1_REG, 1 << 30);
195 /* FIXME: locking? */
198 void sossi_stop_transfer(void)
201 sossi_set_bits(SOSSI_INIT2_REG, 1 << 4);
203 sossi_set_bits(SOSSI_INIT1_REG, 1 << 30);
204 /* FIXME: locking? */
207 static void send_data(const void *data, unsigned int len)
210 sossi_write_reg(SOSSI_FIFO_REG, *(const u32 *) data);
215 sossi_write_reg16(SOSSI_FIFO_REG, *(const u16 *) data);
220 sossi_write_reg8(SOSSI_FIFO_REG, *(const u8 *) data);
226 static void set_cycles(unsigned int len)
228 int nr_cycles = len / (sossi.bus_pick_width / 8);
230 sossi_clear_bits(SOSSI_INIT1_REG, 0x3ffff);
231 sossi_set_bits(SOSSI_INIT1_REG, (nr_cycles - 1) & 0x3ffff);
234 void sossi_send_cmd(const void *data, unsigned int len)
236 sossi_clear_bits(SOSSI_INIT1_REG, 1 << 18);
238 send_data(data, len);
241 void sossi_send_data(const void *data, unsigned int len)
243 sossi_set_bits(SOSSI_INIT1_REG, 1 << 18);
245 send_data(data, len);
248 void sossi_prepare_dma_transfer(unsigned int count)
250 sossi_set_bits(SOSSI_INIT1_REG, 1 << 18);
254 void sossi_send_data_const32(u32 data, unsigned int count)
256 sossi_set_bits(SOSSI_INIT1_REG, 1 << 18);
257 set_cycles(count * 4);
259 sossi_write_reg(SOSSI_FIFO_REG, data);
264 void sossi_set_tearing(int mode, int hs_counter, int detect_limit,
265 int vs_counter, int vs_detect_limit, int flags)
269 l |= vs_counter << 30;
270 if (flags & SOSSI_FLAG_HS_INVERTED)
272 if (flags & SOSSI_FLAG_VS_INVERTED)
275 l |= hs_counter << 15;
276 l |= vs_detect_limit << 3;
278 sossi_write_reg(SOSSI_TEARING_REG, l);
281 void sossi_read_data(void *data, unsigned int len)
283 /* Before reading we must check if some writings are going on */
284 while (!(sossi_read_reg(SOSSI_INIT2_REG) & (1 << 3)));
285 sossi_set_bits(SOSSI_INIT1_REG, 1 << 18);
288 *(u32 *) data = sossi_read_reg(SOSSI_FIFO_REG);
293 *(u16 *) data = sossi_read_reg16(SOSSI_FIFO_REG);
298 *(u8 *) data = sossi_read_reg8(SOSSI_FIFO_REG);