staticstruct { void __iomem *base; struct clk *fck; unsignedlong fck_hz;
spinlock_t lock; int bus_pick_count; int bus_pick_width; int tearsync_mode; int tearsync_line; void (*lcdc_callback)(void *data); void *lcdc_callback_data; int vsync_dma_pending; /* timing for read and write access */ int clk_div;
u8 clk_tw0[2];
u8 clk_tw1[2]; /* * if last_access is the same as current we don't have to change * the timings
*/ int last_access;
staticint calc_rd_timings(struct extif_timings *t)
{
u32 tw0, tw1; int reon, reoff, recyc, actim; int div = t->clk_div;
/* * Make sure that after conversion it still holds that: * reoff > reon, recyc >= reoff, actim > reon
*/
reon = ps_to_sossi_ticks(t->re_on_time, div); /* reon will be exactly one sossi tick */ if (reon > 1) return -1;
tw1 = recyc - tw0; /* values less then 3 result in the SOSSI block resetting itself */ if (tw1 < 3)
tw1 = 3; if (tw1 > 0x40) return -1;
actim = ps_to_sossi_ticks(t->access_time, div); if (actim < reoff)
actim++; /* * access time (data hold time) will be exactly one sossi * tick
*/ if (actim - reoff > 1) return -1;
t->tim[0] = tw0 - 1;
t->tim[1] = tw1 - 1;
return 0;
}
staticint calc_wr_timings(struct extif_timings *t)
{
u32 tw0, tw1; int weon, weoff, wecyc; int div = t->clk_div;
/* * Make sure that after conversion it still holds that: * weoff > weon, wecyc >= weoff
*/
weon = ps_to_sossi_ticks(t->we_on_time, div); /* weon will be exactly one sossi tick */ if (weon > 1) return -1;
staticvoid sossi_start_transfer(void)
{ /* WE */
sossi_clear_bits(SOSSI_INIT2_REG, 1 << 4); /* CS active low */
sossi_clear_bits(SOSSI_INIT1_REG, 1 << 30);
}
staticvoid sossi_stop_transfer(void)
{ /* WE */
sossi_set_bits(SOSSI_INIT2_REG, 1 << 4); /* CS active low */
sossi_set_bits(SOSSI_INIT1_REG, 1 << 30);
}
staticvoid wait_end_of_write(void)
{ /* Before reading we must check if some writings are going on */ while (!(sossi_read_reg(SOSSI_INIT2_REG) & (1 << 3)));
}
staticvoid send_data(constvoid *data, unsignedint len)
{ while (len >= 4) {
sossi_write_reg(SOSSI_FIFO_REG, *(const u32 *) data);
len -= 4;
data += 4;
} while (len >= 2) {
sossi_write_reg16(SOSSI_FIFO_REG, *(const u16 *) data);
len -= 2;
data += 2;
} while (len) {
sossi_write_reg8(SOSSI_FIFO_REG, *(const u8 *) data);
len--;
data++;
}
}
staticvoid sossi_set_bits_per_cycle(int bpc)
{ int bus_pick_count, bus_pick_width;
/* * We set explicitly the bus_pick_count as well, although * with remapping/reordering disabled it will be calculated by HW * as (32 / bus_pick_width).
*/ switch (bpc) { case 8:
bus_pick_count = 4;
bus_pick_width = 8; break; case 16:
bus_pick_count = 2;
bus_pick_width = 16; break; default:
BUG(); return;
}
sossi.bus_pick_width = bus_pick_width;
sossi.bus_pick_count = bus_pick_count;
}
staticint sossi_setup_tearsync(unsigned pin_cnt, unsigned hs_pulse_time, unsigned vs_pulse_time, int hs_pol_inv, int vs_pol_inv, int div)
{ int hs, vs;
u32 l;
if (pin_cnt != 1 || div < 1 || div > 8) return -EINVAL;
hs = ps_to_sossi_ticks(hs_pulse_time, div);
vs = ps_to_sossi_ticks(vs_pulse_time, div); if (vs < 8 || vs <= hs || vs >= (1 << 12)) return -EDOM;
vs /= 8;
vs--; if (hs > 8)
hs = 8; if (hs)
hs--;
clk_enable(sossi.fck);
l = sossi_read_reg(SOSSI_TEARING_REG);
l &= ~((1 << 15) - 1);
l |= vs << 3;
l |= hs; if (hs_pol_inv)
l |= 1 << 29; else
l &= ~(1 << 29); if (vs_pol_inv)
l |= 1 << 28; else
l &= ~(1 << 28);
sossi_write_reg(SOSSI_TEARING_REG, l);
clk_disable(sossi.fck);
return 0;
}
staticint sossi_enable_tearsync(int enable, unsigned line)
{ int mode;
dev_dbg(sossi.fbdev->dev, "tearsync %d line %d\n", enable, line); if (line >= 1 << 11) return -EINVAL; if (enable) { if (line)
mode = 2; /* HS or VS */ else
mode = 3; /* VS only */
} else
mode = 0;
sossi.tearsync_line = line;
sossi.tearsync_mode = mode;
sossi_start_transfer(); if (sossi.tearsync_mode) { /* * Wait for the sync signal and start the transfer only * then. We can't seem to be able to use HW sync DMA for * this since LCD DMA shows huge latencies, as if it * would ignore some of the DMA requests from SoSSI.
*/ unsignedlong flags;
spin_lock_irqsave(&sossi.lock, flags);
sossi.vsync_dma_pending++;
spin_unlock_irqrestore(&sossi.lock, flags);
} else /* Just start the transfer right away. */
omap_enable_lcd_dma();
}
dpll1out_ck = clk_get(fbdev->dev, "ck_dpll1out"); if (IS_ERR(dpll1out_ck)) {
dev_err(fbdev->dev, "can't get DPLL1OUT clock\n"); return PTR_ERR(dpll1out_ck);
} /* * We need the parent clock rate, which we might divide further * depending on the timing requirements of the controller. See * _set_timings.
*/
sossi.fck_hz = clk_get_rate(dpll1out_ck);
clk_put(dpll1out_ck);
fck = clk_get(fbdev->dev, "ck_sossi"); if (IS_ERR(fck)) {
dev_err(fbdev->dev, "can't get SoSSI functional clock\n"); return PTR_ERR(fck);
}
sossi.fck = fck;
/* Reset and enable the SoSSI module */
l = omap_readl(MOD_CONF_CTRL_1);
l |= CONF_SOSSI_RESET_R;
omap_writel(l, MOD_CONF_CTRL_1);
l &= ~CONF_SOSSI_RESET_R;
omap_writel(l, MOD_CONF_CTRL_1);
clk_prepare_enable(sossi.fck);
l = omap_readl(ARM_IDLECT2);
l &= ~(1 << 8); /* DMACK_REQ */
omap_writel(l, ARM_IDLECT2);
l = sossi_read_reg(SOSSI_INIT2_REG); /* Enable and reset the SoSSI block */
l |= (1 << 0) | (1 << 1);
sossi_write_reg(SOSSI_INIT2_REG, l); /* Take SoSSI out of reset */
l &= ~(1 << 1);
sossi_write_reg(SOSSI_INIT2_REG, l);
sossi_write_reg(SOSSI_ID_REG, 0);
l = sossi_read_reg(SOSSI_ID_REG);
k = sossi_read_reg(SOSSI_ID_REG);
if (l != 0x55555555 || k != 0xaaaaaaaa) {
dev_err(fbdev->dev, "invalid SoSSI sync pattern: %08x, %08x\n", l, k);
r = -ENODEV; goto err;
}
if ((r = omap_lcdc_set_dma_callback(sossi_dma_callback, NULL)) < 0) {
dev_err(fbdev->dev, "can't get LCDC IRQ\n");
r = -ENODEV; goto err;
}
l = sossi_read_reg(SOSSI_ID_REG); /* Component code */
l = sossi_read_reg(SOSSI_ID_REG);
dev_info(fbdev->dev, "SoSSI version %d.%d initialized\n",
l >> 16, l & 0xffff);
l = sossi_read_reg(SOSSI_INIT1_REG);
l |= (1 << 19); /* DMA_MODE */
l &= ~(1 << 31); /* REORDERING */
sossi_write_reg(SOSSI_INIT1_REG, l);
if ((r = request_irq(fbdev->ext_irq, sossi_match_irq,
IRQ_TYPE_EDGE_FALLING, "sossi_match", sossi.fbdev->dev)) < 0) {
dev_err(sossi.fbdev->dev, "can't get SoSSI match IRQ\n"); goto err;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.