21 #include <linux/module.h>
33 #define MODULE_NAME "omapfb-sossi"
35 #define OMAP_SOSSI_BASE 0xfffbac00
36 #define SOSSI_ID_REG 0x00
37 #define SOSSI_INIT1_REG 0x04
38 #define SOSSI_INIT2_REG 0x08
39 #define SOSSI_INIT3_REG 0x0c
40 #define SOSSI_FIFO_REG 0x10
41 #define SOSSI_REOTABLE_REG 0x14
42 #define SOSSI_TEARING_REG 0x18
43 #define SOSSI_INIT1B_REG 0x1c
44 #define SOSSI_FIFOB_REG 0x20
46 #define DMA_GSCR 0xfffedc04
47 #define DMA_LCD_CCR 0xfffee3c2
48 #define DMA_LCD_CTRL 0xfffee3c4
49 #define DMA_LCD_LCH_CTRL 0xfffee3ea
51 #define CONF_SOSSI_RESET_R (1 << 23)
56 #define SOSSI_MAX_XMIT_BYTES (512 * 1024)
83 static inline u32 sossi_read_reg(
int reg)
85 return readl(sossi.base + reg);
88 static inline u16 sossi_read_reg16(
int reg)
90 return readw(sossi.base + reg);
93 static inline u8 sossi_read_reg8(
int reg)
95 return readb(sossi.base + reg);
98 static inline void sossi_write_reg(
int reg,
u32 value)
100 writel(value, sossi.base + reg);
103 static inline void sossi_write_reg16(
int reg,
u16 value)
105 writew(value, sossi.base + reg);
108 static inline void sossi_write_reg8(
int reg,
u8 value)
110 writeb(value, sossi.base + reg);
115 sossi_write_reg(reg, sossi_read_reg(reg) | bits);
118 static void sossi_clear_bits(
int reg,
u32 bits)
120 sossi_write_reg(reg, sossi_read_reg(reg) & ~bits);
123 #define HZ_TO_PS(x) (1000000000 / (x / 1000))
128 return (clk_period + ps - 1) / clk_period;
134 int reon, reoff, recyc, actim;
173 if (actim - reoff > 1)
185 int weon, weoff, wecyc;
221 static void _set_timing(
int div,
int tw0,
int tw1)
226 dev_dbg(sossi.fbdev->dev,
"Using TW0 = %d, TW1 = %d, div = %d\n",
227 tw0 + 1, tw1 + 1, div);
233 l &= ~((0x0f << 20) | (0x3f << 24));
234 l |= (tw0 << 20) | (tw1 << 24);
245 l |= ((bus_pick_count - 1) << 5) | ((bus_pick_width - 1) & 0x1f);
249 static void _set_tearsync_mode(
int mode,
unsigned line)
254 l &= ~(((1 << 11) - 1) << 15);
265 static inline void set_timing(
int access)
267 if (access != sossi.last_access) {
268 sossi.last_access =
access;
269 _set_timing(sossi.clk_div,
270 sossi.clk_tw0[access], sossi.clk_tw1[access]);
274 static void sossi_start_transfer(
void)
282 static void sossi_stop_transfer(
void)
290 static void wait_end_of_write(
void)
296 static void send_data(
const void *
data,
unsigned int len)
315 static void set_cycles(
unsigned int len)
317 unsigned long nr_cycles = len / (sossi.bus_pick_width / 8);
319 BUG_ON((nr_cycles - 1) & ~0x3ffff);
332 if (div <= 0 || div > 8)
336 if ((r = calc_rd_timings(t)) < 0)
339 if ((r = calc_wr_timings(t)) < 0)
359 sossi.clk_div = t->
tim[4];
362 static void sossi_get_clk_info(
u32 *clk_period,
u32 *max_clk_div)
364 *clk_period =
HZ_TO_PS(sossi.fck_hz);
368 static void sossi_set_bits_per_cycle(
int bpc)
394 static int sossi_setup_tearsync(
unsigned pin_cnt,
395 unsigned hs_pulse_time,
unsigned vs_pulse_time,
396 int hs_pol_inv,
int vs_pol_inv,
int div)
401 if (pin_cnt != 1 || div < 1 || div > 8)
404 hs = ps_to_sossi_ticks(hs_pulse_time, div);
405 vs = ps_to_sossi_ticks(vs_pulse_time, div);
406 if (vs < 8 || vs <= hs || vs >= (1 << 12))
416 "setup_tearsync: hs %d vs %d hs_inv %d vs_inv %d\n",
417 hs, vs, hs_pol_inv, vs_pol_inv);
421 l &= ~((1 << 15) - 1);
438 static int sossi_enable_tearsync(
int enable,
unsigned line)
442 dev_dbg(sossi.fbdev->dev,
"tearsync %d line %d\n", enable, line);
452 sossi.tearsync_line = line;
453 sossi.tearsync_mode =
mode;
458 static void sossi_write_command(
const void *data,
unsigned int len)
462 _set_bits_per_cycle(sossi.bus_pick_count, sossi.bus_pick_width);
466 sossi_start_transfer();
467 send_data(data, len);
468 sossi_stop_transfer();
473 static void sossi_write_data(
const void *data,
unsigned int len)
477 _set_bits_per_cycle(sossi.bus_pick_count, sossi.bus_pick_width);
481 sossi_start_transfer();
482 send_data(data, len);
483 sossi_stop_transfer();
488 static void sossi_transfer_area(
int width,
int height,
489 void (
callback)(
void *data),
void *data)
494 sossi.lcdc_callback_data =
data;
498 _set_bits_per_cycle(sossi.bus_pick_count, sossi.bus_pick_width);
499 _set_tearsync_mode(sossi.tearsync_mode, sossi.tearsync_line);
502 set_cycles(width * height * sossi.bus_pick_width / 8);
504 sossi_start_transfer();
505 if (sossi.tearsync_mode) {
515 sossi.vsync_dma_pending++;
516 spin_unlock_irqrestore(&sossi.lock, flags);
522 static void sossi_dma_callback(
void *data)
525 sossi_stop_transfer();
527 sossi.lcdc_callback(sossi.lcdc_callback_data);
530 static void sossi_read_data(
void *data,
unsigned int len)
534 _set_bits_per_cycle(sossi.bus_pick_count, sossi.bus_pick_width);
538 sossi_start_transfer();
554 sossi_stop_transfer();
558 static irqreturn_t sossi_match_irq(
int irq,
void *data)
563 if (sossi.vsync_dma_pending) {
564 sossi.vsync_dma_pending--;
567 spin_unlock_irqrestore(&sossi.lock, flags);
575 struct clk *dpll1out_ck;
587 dpll1out_ck =
clk_get(fbdev->
dev,
"ck_dpll1out");
588 if (IS_ERR(dpll1out_ck)) {
589 dev_err(fbdev->
dev,
"can't get DPLL1OUT clock\n");
590 return PTR_ERR(dpll1out_ck);
602 dev_err(fbdev->
dev,
"can't get SoSSI functional clock\n");
621 l |= (1 << 0) | (1 << 1);
631 if (l != 0x55555555 || k != 0xaaaaaaaa) {
633 "invalid SoSSI sync pattern: %08x, %08x\n", l, k);
646 dev_info(fbdev->
dev,
"SoSSI version %d.%d initialized\n",
647 l >> 16, l & 0xffff);
656 "sossi_match", sossi.fbdev->dev)) < 0) {
657 dev_err(sossi.fbdev->dev,
"can't get SoSSI match IRQ\n");
670 static void sossi_cleanup(
void)
679 .cleanup = sossi_cleanup,
680 .get_clk_info = sossi_get_clk_info,
681 .convert_timings = sossi_convert_timings,
682 .set_timings = sossi_set_timings,
683 .set_bits_per_cycle = sossi_set_bits_per_cycle,
684 .setup_tearsync = sossi_setup_tearsync,
685 .enable_tearsync = sossi_enable_tearsync,
686 .write_command = sossi_write_command,
687 .read_data = sossi_read_data,
688 .write_data = sossi_write_data,
689 .transfer_area = sossi_transfer_area,