diff -Naur -X kernel-source-2.6.16-2.6.16.rel/Documentation/dontdiff kernel-source-2.6.16-2.6.16.rel/arch/arm/mach-omap1/board-nokia770.c kernel-source-2.6.16-2.6.16.my/arch/arm/mach-omap1/board-nokia770.c --- kernel-source-2.6.16-2.6.16.rel/arch/arm/mach-omap1/board-nokia770.c 2006-11-28 14:16:52.000000000 +0100 +++ kernel-source-2.6.16-2.6.16.my/arch/arm/mach-omap1/board-nokia770.c 2008-04-06 21:46:43.000000000 +0200 @@ -257,6 +257,47 @@ platform_device_register(&retu_headset_device); } +/* + We do our own pin muxing here, + CONFIG_OMAP_MUX is disabled for 770 kernel as all pin muxing is done in NOLO bootloader, + we cannot enable it since random pieces of kernel would then change muxing of other pins. +*/ + +static void __init nokia770_mux_pin(char *cfg_name, char *mux_reg_name, unsigned int mux_reg, + unsigned char value, unsigned char offset) +{ + static DEFINE_SPINLOCK(nokia770_mux_spin_lock); + unsigned long flags; + unsigned int reg_orig = 0, reg = 0; + unsigned int tmp1, tmp2; + unsigned int mask, warn = 0; + spin_lock_irqsave(&nokia770_mux_spin_lock, flags); + reg_orig = omap_readl(mux_reg); + /* The mux registers always seem to be 3 bits long */ + mask = (0x7 << offset); + tmp1 = reg_orig & mask; + reg = reg_orig & ~mask; + tmp2 = (value << offset); + reg |= tmp2; + if (tmp1 != tmp2) + warn = 1; + omap_writel(reg, mux_reg); + spin_unlock_irqrestore(&nokia770_mux_spin_lock, flags); + if (warn) { + printk("MUX: Setting %s\n", cfg_name); + printk(" %s (0x%08x) = 0x%08x -> 0x%08x\n", + mux_reg_name, mux_reg, reg_orig, reg); + } +} + +static void __init nokia770_mux_init(void) +{ + // TE pin of S1D13742 is connected to ball G20 + // set correct muxing for TE (tearing enabled) SOSSI pin on ball G20 + //omap_cfg_reg(G20_SOSSI_TE); + nokia770_mux_pin("G20_SOSSI_TE","FUNC_MUX_CTRL_4",FUNC_MUX_CTRL_4,6,6); +} + static void __init nokia770_init(void) { nokia770_config[0].data = &nokia770_usb_config; @@ -267,6 +308,7 @@ omap_board_config = nokia770_config; omap_board_config_size = ARRAY_SIZE(nokia770_config); omap_gpio_init(); + nokia770_mux_init(); omap_serial_init(); omap_dsp_audio_pwr_up_request = nokia770_audio_pwr_up_request; omap_dsp_audio_pwr_down_request = nokia770_audio_pwr_down_request; diff -Naur -X kernel-source-2.6.16-2.6.16.rel/Documentation/dontdiff kernel-source-2.6.16-2.6.16.rel/arch/arm/mach-omap1/clock.c kernel-source-2.6.16-2.6.16.my/arch/arm/mach-omap1/clock.c --- kernel-source-2.6.16-2.6.16.rel/arch/arm/mach-omap1/clock.c 2008-04-07 09:52:44.000000000 +0200 +++ kernel-source-2.6.16-2.6.16.my/arch/arm/mach-omap1/clock.c 2007-05-06 21:04:45.000000000 +0200 @@ -46,6 +46,15 @@ clk->rate = 12000000; } +static void omap1_sossi_recalc(struct clk *clk) +{ + u32 div = omap_readl(MOD_CONF_CTRL_1); + + div = (div >> 17) & 0x7; + div++; + clk->rate = clk->parent->rate / div; +} + static int omap1_clk_enable_dsp_domain(struct clk *clk) { int retval; @@ -389,6 +398,31 @@ return 0; } +static int omap1_set_sossi_rate(struct clk *clk, unsigned long rate) +{ + u32 l; + int div; + unsigned long p_rate; + + p_rate = clk->parent->rate; + /* Round towards slower frequency */ + div = (p_rate + rate - 1) / rate; + div--; + if (div < 0 || div > 7) + return -EINVAL; + + l = omap_readl(MOD_CONF_CTRL_1); + l &= ~(7 << 17); + l |= div << 17; + omap_writel(l, MOD_CONF_CTRL_1); + + clk->rate = p_rate / (div + 1); + if (unlikely(clk->flags & RATE_PROPAGATES)) + propagate_rate(clk); + + return 0; +} + static long omap1_round_ext_clk_rate(struct clk * clk, unsigned long rate) { return 96000000 / calc_ext_dsor(rate); diff -Naur -X kernel-source-2.6.16-2.6.16.rel/Documentation/dontdiff kernel-source-2.6.16-2.6.16.rel/arch/arm/mach-omap1/clock.h kernel-source-2.6.16-2.6.16.my/arch/arm/mach-omap1/clock.h --- kernel-source-2.6.16-2.6.16.rel/arch/arm/mach-omap1/clock.h 2008-04-07 09:52:44.000000000 +0200 +++ kernel-source-2.6.16-2.6.16.my/arch/arm/mach-omap1/clock.h 2007-05-06 21:04:45.000000000 +0200 @@ -17,6 +17,8 @@ static void omap1_clk_disable_generic(struct clk * clk); static void omap1_ckctl_recalc(struct clk * clk); static void omap1_watchdog_recalc(struct clk * clk); +static int omap1_set_sossi_rate(struct clk *clk, unsigned long rate); +static void omap1_sossi_recalc(struct clk *clk); static void omap1_ckctl_recalc_dsp_domain(struct clk * clk); static int omap1_clk_enable_dsp_domain(struct clk * clk); static int omap1_clk_set_rate_dsp_domain(struct clk * clk, unsigned long rate); @@ -167,9 +169,10 @@ static struct arm_idlect1_clk ck_dpll1out = { .clk = { - .name = "ck_dpll1out", + .name = "ck_dpll1out", .parent = &ck_dpll1, - .flags = CLOCK_IN_OMAP16XX | CLOCK_IDLE_CONTROL, + .flags = CLOCK_IN_OMAP16XX | CLOCK_IDLE_CONTROL | + ENABLE_REG_32BIT | RATE_PROPAGATES, .enable_reg = (void __iomem *)ARM_IDLECT2, .enable_bit = EN_CKOUT_ARM, .recalc = &followparent_recalc, @@ -179,6 +182,19 @@ .idlect_shift = 12, }; +static struct clk sossi_ck = { + .name = "ck_sossi", + .parent = &ck_dpll1out.clk, + .flags = CLOCK_IN_OMAP16XX | CLOCK_NO_IDLE_PARENT | + ENABLE_REG_32BIT, + .enable_reg = (void __iomem *)MOD_CONF_CTRL_1, + .enable_bit = 16, + .recalc = &omap1_sossi_recalc, + .set_rate = &omap1_set_sossi_rate, + .enable = &omap1_clk_enable_generic, + .disable = &omap1_clk_disable_generic, +}; + static struct clk arm_ck = { .name = "arm_ck", .parent = &ck_dpll1, @@ -759,6 +775,7 @@ &ck_dpll1, /* CK_GEN1 clocks */ &ck_dpll1out.clk, + &sossi_ck, &arm_ck, &armper_ck.clk, &arm_gpio_ck, diff -Naur -X kernel-source-2.6.16-2.6.16.rel/Documentation/dontdiff kernel-source-2.6.16-2.6.16.rel/arch/arm/mach-omap1/mux.c kernel-source-2.6.16-2.6.16.my/arch/arm/mach-omap1/mux.c --- kernel-source-2.6.16-2.6.16.rel/arch/arm/mach-omap1/mux.c 2006-11-28 14:16:52.000000000 +0100 +++ kernel-source-2.6.16-2.6.16.my/arch/arm/mach-omap1/mux.c 2008-04-05 22:32:36.000000000 +0200 @@ -273,6 +273,12 @@ MUX_CFG("V10_1610_CF_IREQ", A, 24, 3, 2, 14, 0, 2, 0, 1) MUX_CFG("W10_1610_CF_RESET", A, 18, 3, 2, 12, 1, 2, 1, 1) MUX_CFG("W11_1610_CF_CD1", 10, 15, 3, 3, 8, 1, 3, 1, 1) + +/* + * description mux mode mux pull pull pull pu_pd pu dbg + * reg offset mode reg bit ena reg + */ +MUX_CFG("G20_SOSSI_TE", 4, 6, 6, NA, 0, 0, NA , 0, 1) }; #endif /* CONFIG_ARCH_OMAP15XX || CONFIG_ARCH_OMAP16XX */ diff -Naur -X kernel-source-2.6.16-2.6.16.rel/Documentation/dontdiff kernel-source-2.6.16-2.6.16.rel/drivers/video/omap/hwa742.c kernel-source-2.6.16-2.6.16.my/drivers/video/omap/hwa742.c --- kernel-source-2.6.16-2.6.16.rel/drivers/video/omap/hwa742.c 2008-04-07 09:52:45.000000000 +0200 +++ kernel-source-2.6.16-2.6.16.my/drivers/video/omap/hwa742.c 2007-05-29 12:36:53.000000000 +0200 @@ -86,17 +86,17 @@ #define REQ_POOL_SIZE 24 #define IRQ_REQ_POOL_SIZE 4 +#define REQ_FROM_IRQ_POOL 0x01 + +#define REQ_COMPLETE 0 +#define REQ_PENDING 1 + struct update_param { int x, y, width, height; int color_mode; int flags; }; -#define REQ_FROM_IRQ_POOL 0x01 - -#define REQ_COMPLETE 0 -#define REQ_PENDING 1 - struct hwa742_request { struct list_head entry; unsigned int flags; @@ -118,6 +118,8 @@ struct timer_list auto_update_timer; int stop_auto_update; struct omapfb_update_window auto_update_window; + unsigned te_connected:1; + unsigned vsync_only:1; struct hwa742_request req_pool[REQ_POOL_SIZE]; struct list_head pending_req_list; @@ -134,6 +136,9 @@ u32 max_transmit_size; u32 extif_clk_period; + unsigned long pix_tx_time; + unsigned long line_upd_time; + struct omapfb_device *fbdev; struct lcd_ctrl_extif *extif; @@ -197,6 +202,45 @@ hwa742_write_reg(HWA742_WINDOW_TYPE, hwa742.window_type); } +static void enable_tearsync(int y, int width, int height, int screen_height, + int force_vsync) +{ + u8 b; + + b = hwa742_read_reg(HWA742_NDP_CTRL); + b |= 1 << 2; + hwa742_write_reg(HWA742_NDP_CTRL, b); + + if (likely(hwa742.vsync_only || force_vsync)) { + hwa742.extif->enable_tearsync(1, 0); + return; + } + + if (width * hwa742.pix_tx_time < hwa742.line_upd_time) { + hwa742.extif->enable_tearsync(1, 0); + return; + } + + if ((width * hwa742.pix_tx_time / 1000) * height < + (y + height) * (hwa742.line_upd_time / 1000)) { + hwa742.extif->enable_tearsync(1, 0); + return; + } + + hwa742.extif->enable_tearsync(1, y + 1); +} + +static void disable_tearsync(void) +{ + u8 b; + + hwa742.extif->enable_tearsync(0, 0); + + b = hwa742_read_reg(HWA742_NDP_CTRL); + b &= ~(1 << 2); + hwa742_write_reg(HWA742_NDP_CTRL, b); +} + static inline struct hwa742_request *alloc_req(void) { unsigned long flags; @@ -306,6 +350,20 @@ process_pending_requests(); } +/* Wait until the YYC color space converter is idle. */ +static void hwa742_wait_yyc(void) +{ + unsigned long tmo = jiffies + msecs_to_jiffies(30); + + while (hwa742_read_reg(HWA742_NDP_CTRL) & (1 << 4)) { + if (time_after(jiffies, tmo)) { + if (printk_ratelimit()) + dev_err(hwa742.fbdev->dev,"hwa742: YYC not ready\n"); + break; + } + } +} + static int send_frame_handler(struct hwa742_request *req) { struct update_param *par = &req->par.update; @@ -313,29 +371,38 @@ int y = par->y; int w = par->width; int h = par->height; - int bpp; int conv, transl; unsigned long offset; int color_mode = par->color_mode; + int prev_color_mode; int flags = par->flags; - int scr_width = 800; + int scr_width = hwa742.fbdev->panel->x_res; + int scr_height = hwa742.fbdev->panel->y_res; + int scr_bpp = hwa742.fbdev->panel->bpp; DBGPRINT(2, "x %d y %d w %d h %d scr_width %d color_mode %d flags %d\n", x, y, w, h, scr_width, color_mode, flags); switch (color_mode) { case OMAPFB_COLOR_YUV422: - bpp = 16; conv = 0x08; transl = 0x25; + /* X, Y, height must be aligned at 2, width at 4 pixels */ + x &= ~1; + y &= ~1; + h &= ~1; + w &= ~3; break; case OMAPFB_COLOR_YUV420: - bpp = 12; conv = 0x09; transl = 0x25; + /* X, Y, height must be aligned at 2, width at 4 pixels */ + x &= ~1; + y &= ~1; + h &= ~1; + w &= ~3; break; case OMAPFB_COLOR_RGB565: - bpp = 16; conv = 0x01; transl = 0x05; break; @@ -343,21 +410,39 @@ return -EINVAL; } + prev_color_mode = hwa742.prev_color_mode; // remember for YYC check below if (hwa742.prev_flags != flags || hwa742.prev_color_mode != color_mode) { set_format_regs(conv, transl, flags); hwa742.prev_color_mode = color_mode; hwa742.prev_flags = flags; } + flags = req->par.update.flags; + if (flags & OMAPFB_FORMAT_FLAG_TEARSYNC) + enable_tearsync(y, scr_width, h, scr_height, + flags & OMAPFB_FORMAT_FLAG_FORCE_VSYNC); + else + disable_tearsync(); + if (prev_color_mode==OMAPFB_COLOR_YUV420) { // wait for YYC converter for YUV420 mode + hwa742_wait_yyc(); + } + set_window_regs(x, y, x + w, y + h); - offset = (scr_width * y + x) * bpp / 8; + offset = (scr_width * y + x) * scr_bpp / 8; hwa742.int_ctrl->setup_plane(OMAPFB_PLANE_GFX, OMAPFB_CHANNEL_OUT_LCD, offset, scr_width, 0, 0, w, h, color_mode); + if (color_mode==OMAPFB_COLOR_YUV420){ + /* Currently only the 16 bits/pixel cycle format is + * supported on the external interface. Adjust the number + * of transfer elements per line for 12bpp format. + */ + w = (w + 1) * 3 / 4; + } hwa742.extif->set_bits_per_cycle(16); hwa742.int_ctrl->enable_plane(OMAPFB_PLANE_GFX, 1); @@ -395,13 +480,14 @@ int color_mode; int flags; - flags = win->format & OMAPFB_FORMAT_FLAG_DOUBLE; + flags = win->format & ~OMAPFB_FORMAT_MASK; color_mode = win->format & OMAPFB_FORMAT_MASK; if (x & 1) { ADD_PREQ(x, y, 1, height); width--; x++; + flags &= ~OMAPFB_FORMAT_FLAG_TEARSYNC; } if (width & ~1) { unsigned int xspan = width & ~1; @@ -413,11 +499,13 @@ ADD_PREQ(x, ystart, xspan, yspan); ystart += yspan; yspan = height - yspan; + flags &= ~OMAPFB_FORMAT_FLAG_TEARSYNC; } ADD_PREQ(x, ystart, xspan, yspan); x += xspan; width -= xspan; + flags &= ~OMAPFB_FORMAT_FLAG_TEARSYNC; } if (width) ADD_PREQ(x, y, 1, height); @@ -467,8 +555,10 @@ r = -EINVAL; goto out; } - if (unlikely(win->format & ~(0x03 | OMAPFB_FORMAT_FLAG_DOUBLE))) { - DBGPRINT(1, "invalid window flag"); + if (unlikely(win->format & + ~(0x03 | OMAPFB_FORMAT_FLAG_DOUBLE | + OMAPFB_FORMAT_FLAG_TEARSYNC | OMAPFB_FORMAT_FLAG_FORCE_VSYNC))) { + DBGPRINT(1,"invalid window flag"); r = -EINVAL; goto out; } @@ -705,7 +795,7 @@ return hwa742.extif->convert_timings(t); } -static int calc_extif_timings(unsigned long sysclk) +static int calc_extif_timings(unsigned long sysclk, int *extif_mem_div) { int max_clk_div; int div; @@ -715,25 +805,161 @@ if (calc_reg_timing(sysclk, div) == 0) break; } - if (div == max_clk_div) + if (div > max_clk_div) goto err; + *extif_mem_div = div; + for (div = 1; div < max_clk_div; div++) { if (calc_lut_timing(sysclk, div) == 0) break; } - if (div < max_clk_div) - return 0; + if (div > max_clk_div) + goto err; + + return 0; err: pr_err("can't setup timings\n"); return -1; } +static void calc_hwa742_clk_rates(unsigned long ext_clk, + unsigned long *sys_clk, unsigned long *pix_clk) +{ + int pix_clk_src; + int sys_div = 0, sys_mul = 0; + int pix_div; + + pix_clk_src = hwa742_read_reg(HWA742_CLK_SRC_REG); + pix_div = ((pix_clk_src >> 3) & 0x1f) + 1; + if ((pix_clk_src & (0x3 << 1)) == 0) { + /* Source is the PLL */ + sys_div = (hwa742_read_reg(HWA742_PLL_DIV_REG) & 0x3f) + 1; + sys_mul = (hwa742_read_reg(HWA742_PLL_4_REG) & 0x7f) + 1; + *sys_clk = ext_clk * sys_mul / sys_div; + } else /* else source is ext clk, or oscillator */ + *sys_clk = ext_clk; + + *pix_clk = *sys_clk / pix_div; /* HZ */ + DBGPRINT(1, + "ext_clk %ld pix_src %d pix_div %d sys_div %d sys_mul %d\n", + ext_clk, pix_clk_src & (0x3 << 1), pix_div, sys_div, sys_mul); + DBGPRINT(1, "sys_clk %ld pix_clk %ld\n", + *sys_clk, *pix_clk); +} + + +static int setup_tearsync(unsigned long pix_clk, int extif_div) +{ + int hdisp, vdisp; + int hndp, vndp; + int hsw, vsw; + int hs, vs; + int hs_pol_inv, vs_pol_inv; + int use_hsvs, use_ndp; + u8 b; + + hsw = hwa742_read_reg(HWA742_HS_W_REG); + vsw = hwa742_read_reg(HWA742_VS_W_REG); + hs_pol_inv = !(hsw & 0x80); + vs_pol_inv = !(vsw & 0x80); + hsw = hsw & 0x7f; + vsw = vsw & 0x3f; + + hdisp = (hwa742_read_reg(HWA742_H_DISP_REG) & 0x7f) * 8; + vdisp = hwa742_read_reg(HWA742_V_DISP_1_REG) + + ((hwa742_read_reg(HWA742_V_DISP_2_REG) & 0x3) << 8); + + hndp = hwa742_read_reg(HWA742_H_NDP_REG) & 0x7f; + vndp = hwa742_read_reg(HWA742_V_NDP_REG); + + /* time to transfer one pixel (16bpp) in ps */ + hwa742.pix_tx_time = hwa742.reg_timings.we_cycle_time; + if (hwa742.extif->get_max_tx_rate != NULL) { + /* The external interface might have a rate limitation, + * if so, we have to maximize our transfer rate. + */ + unsigned long min_tx_time; + unsigned long max_tx_rate = hwa742.extif->get_max_tx_rate(); + + DBGPRINT(1, "max_tx_rate %ld HZ\n", + max_tx_rate); + min_tx_time = 1000000000 / (max_tx_rate / 1000); /* ps */ + if (hwa742.pix_tx_time < min_tx_time) + hwa742.pix_tx_time = min_tx_time; + } + + /* time to update one line in ps */ + hwa742.line_upd_time = (hdisp + hndp) * 1000000 / (pix_clk / 1000); + hwa742.line_upd_time *= 1000; + if (hdisp * hwa742.pix_tx_time > hwa742.line_upd_time) + /* transfer speed too low, we might have to use both + * HS and VS */ + use_hsvs = 1; + else + /* decent transfer speed, we'll always use only VS */ + use_hsvs = 0; + + if (use_hsvs && (hs_pol_inv || vs_pol_inv)) { + /* HS or'ed with VS doesn't work, use the active high + * TE signal based on HNDP / VNDP */ + use_ndp = 1; + hs_pol_inv = 0; + vs_pol_inv = 0; + hs = hndp; + vs = vndp; + } else { + /* Use HS or'ed with VS as a TE signal if both are needed + * or VNDP if only vsync is needed. */ + use_ndp = 0; + hs = hsw; + vs = vsw; + if (!use_hsvs) { + hs_pol_inv = 0; + vs_pol_inv = 0; + } + } + + hs = hs * 1000000 / (pix_clk / 1000); /* ps */ + hs *= 1000; + + vs = vs * (hdisp + hndp) * 1000000 / (pix_clk / 1000); /* ps */ + vs *= 1000; + + if (vs <= hs) + return -EDOM; + /* set VS to 120% of HS to minimize VS detection time */ + vs = hs * 12 / 10; + /* minimize HS too */ + hs = 10000; + + b = hwa742_read_reg(HWA742_NDP_CTRL); + b &= ~0x3; + b |= use_hsvs ? 1 : 0; + b |= (use_ndp && use_hsvs) ? 0 : 2; + hwa742_write_reg(HWA742_NDP_CTRL, b); + + hwa742.vsync_only = !use_hsvs; + + DBGPRINT(1,"pix_clk %ld HZ pix_tx_time %ld ps line_upd_time %ld ps\n", + pix_clk, hwa742.pix_tx_time, hwa742.line_upd_time); + DBGPRINT(1,"hs %d ps vs %d ps mode %d vsync_only %d\n", + hs, vs, (b & 0x3), !use_hsvs); + + return hwa742.extif->setup_tearsync(1, hs, vs, + hs_pol_inv, vs_pol_inv, extif_div); +} + static unsigned long hwa742_get_caps(void) { - return OMAPFB_CAPS_MANUAL_UPDATE; + unsigned long caps; + + caps = OMAPFB_CAPS_MANUAL_UPDATE; + if (hwa742.te_connected) + caps |= OMAPFB_CAPS_TEARSYNC; + return caps; } static void hwa742_suspend(void) @@ -840,21 +1066,15 @@ int r = 0, i; u8 rev, conf; unsigned long sysfreq; - int div, nd; + //int div, nd; - DBGENTER(1); + unsigned long sys_clk, pix_clk; + int extif_mem_div; - hwa742.sys_ck = clk_get(0, "bclk"); - if (IS_ERR(hwa742.sys_ck)) { - pr_err("can't get SYS clock\n"); - return PTR_ERR(hwa742.sys_ck); - } + struct omapfb_platform_data *omapfb_conf; + struct hwa742_platform_data *ctrl_conf; - if ((r = clk_enable(hwa742.sys_ck)) != 0) { - pr_err("can't enable SYS clock\n"); - clk_put(hwa742.sys_ck); - return r; - } + DBGENTER(1); BUG_ON(!fbdev->ext_if || !fbdev->int_ctrl); @@ -862,27 +1082,51 @@ hwa742.extif = fbdev->ext_if; hwa742.int_ctrl = fbdev->int_ctrl; + omapfb_conf = fbdev->dev->platform_data; +#if 0 + ctrl_conf = omapfb_conf->ctrl_platform_data; + if (ctrl_conf == NULL || ctrl_conf->get_clock_rate == NULL) { + pr_err( "HWA742: missing platform data\n"); + r = -ENOENT; + goto err1; + } +#endif spin_lock_init(&hwa742.req_lock); if ((r = hwa742.int_ctrl->init(fbdev, 1, req_vram_size)) < 0) goto err1; - if ((r = hwa742.extif->init()) < 0) + if ((r = hwa742.extif->init(fbdev)) < 0) goto err2; hwa742_ctrl.get_vram_layout = hwa742.int_ctrl->get_vram_layout; hwa742_ctrl.mmap = hwa742.int_ctrl->mmap; + hwa742.sys_ck = clk_get(0, "bclk"); + if (IS_ERR(hwa742.sys_ck)) { + pr_err("can't get SYS clock\n"); + //return PTR_ERR(hwa742.sys_ck); + goto err2; + } + sysfreq = clk_get_rate(hwa742.sys_ck); - if ((r = calc_extif_timings(sysfreq)) < 0) + if ((r = calc_extif_timings(sysfreq, &extif_mem_div)) < 0) goto err3; hwa742.extif->set_timings(&hwa742.reg_timings); + + if ((r = clk_enable(hwa742.sys_ck)) != 0) { + pr_err("can't enable SYS clock\n"); + goto err3; + } + + calc_hwa742_clk_rates(sysfreq, &sys_clk, &pix_clk); +#if 0 div = (hwa742_read_reg(HWA742_PLL_DIV_REG) & 0x3f) + 1; nd = (hwa742_read_reg(HWA742_PLL_4_REG) & 0x7f) + 1; - - if ((r = calc_extif_timings(sysfreq / div * nd)) < 0) +#endif + if ((r = calc_extif_timings(sys_clk, &extif_mem_div)) < 0) goto err3; hwa742.extif->set_timings(&hwa742.reg_timings); @@ -893,15 +1137,19 @@ goto err3; } - conf = hwa742_read_reg(HWA742_CONFIG_REG); - pr_info(MODULE_NAME ": Epson HWA742 LCD controller rev. %d " - "initialized (CNF pins %x)\n", rev, conf & 0x03); if (!(hwa742_read_reg(HWA742_PLL_DIV_REG) & 0x80)) { pr_err("controller not initialized by the bootloader\n"); r = -ENODEV; goto err2; } +// if (ctrl_conf->te_connected) { + if ((r = setup_tearsync(pix_clk, extif_mem_div)) < 0) { + pr_err("HWA742: can't setup tearing synchronization\n"); + goto err3; + } else + hwa742.te_connected = 1; +// } hwa742.max_transmit_size = hwa742.extif->max_transmit_size; @@ -929,6 +1177,10 @@ BUG_ON(i <= IRQ_REQ_POOL_SIZE); sema_init(&hwa742.req_sema, i - IRQ_REQ_POOL_SIZE); + conf = hwa742_read_reg(HWA742_CONFIG_REG); + pr_info(MODULE_NAME ": Epson HWA742 LCD controller rev. %d " + "initialized (CNF pins %x)\n", rev, conf & 0x03); + return 0; err3: hwa742.extif->cleanup(); diff -Naur -X kernel-source-2.6.16-2.6.16.rel/Documentation/dontdiff kernel-source-2.6.16-2.6.16.rel/drivers/video/omap/omapfb_main.c kernel-source-2.6.16-2.6.16.my/drivers/video/omap/omapfb_main.c --- kernel-source-2.6.16-2.6.16.rel/drivers/video/omap/omapfb_main.c 2007-05-30 21:38:59.000000000 +0200 +++ kernel-source-2.6.16-2.6.16.my/drivers/video/omap/omapfb_main.c 2007-05-01 14:19:47.000000000 +0200 @@ -76,6 +76,7 @@ const char *name; } omapfb_caps_table[] = { { OMAPFB_CAPS_MANUAL_UPDATE, "manual update" }, + { OMAPFB_CAPS_TEARSYNC, "tearing synchronization" }, { OMAPFB_CAPS_SET_BACKLIGHT, "backlight setting" }, }; diff -Naur -X kernel-source-2.6.16-2.6.16.rel/Documentation/dontdiff kernel-source-2.6.16-2.6.16.rel/drivers/video/omap/sossi.c kernel-source-2.6.16-2.6.16.my/drivers/video/omap/sossi.c --- kernel-source-2.6.16-2.6.16.rel/drivers/video/omap/sossi.c 2008-04-07 09:52:45.000000000 +0200 +++ kernel-source-2.6.16-2.6.16.my/drivers/video/omap/sossi.c 2007-05-06 20:43:48.000000000 +0200 @@ -20,11 +20,11 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - #include #include #include #include +#include #include @@ -33,10 +33,6 @@ #include "lcdc.h" -/* #define OMAPFB_DBG 1 */ - -#include "debug.h" - #define MODULE_NAME "omapfb-sossi" #define OMAP_SOSSI_BASE 0xfffbac00 @@ -55,19 +51,25 @@ #define DMA_LCD_CTRL 0xfffee3c4 #define DMA_LCD_LCH_CTRL 0xfffee3ea +#define CONF_SOSSI_RESET_R (1 << 23) + #define RD_ACCESS 0 #define WR_ACCESS 1 #define SOSSI_MAX_XMIT_BYTES (512 * 1024) -#define pr_err(fmt, args...) printk(KERN_ERR MODULE_NAME ": " fmt, ## args) - -static struct sossi { - int base; - unsigned long dpll_khz; +static struct { + void __iomem *base; + struct clk *fck; + unsigned long 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]; @@ -76,9 +78,9 @@ * the timings */ int last_access; -} sossi; -struct lcd_ctrl_extif sossi_extif; + struct omapfb_device *fbdev; +} sossi; static inline u32 sossi_read_reg(int reg) { @@ -120,95 +122,11 @@ sossi_write_reg(reg, sossi_read_reg(reg) & ~bits); } -#define MOD_CONF_CTRL_1 0xfffe1110 -#define CONF_SOSSI_RESET_R (1 << 23) -#define CONF_MOD_SOSSI_CLK_EN_R (1 << 16) - -static void sossi_dma_callback(void *data); - -static int sossi_init(void) -{ - u32 l, k; - struct clk *dpll_clk; - int r; - - sossi.base = IO_ADDRESS(OMAP_SOSSI_BASE); - - dpll_clk = clk_get(NULL, "ck_dpll1"); - if (IS_ERR(dpll_clk)) { - pr_err("can't get dpll1 clock\n"); - return PTR_ERR(dpll_clk); - } - - sossi.dpll_khz = clk_get_rate(dpll_clk) / 1000; - clk_put(dpll_clk); - - sossi_extif.max_transmit_size = SOSSI_MAX_XMIT_BYTES; - - /* 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); - - l |= CONF_MOD_SOSSI_CLK_EN_R; - omap_writel(l, MOD_CONF_CTRL_1); - - omap_writel(omap_readl(ARM_IDLECT2) | (1 << 11), ARM_IDLECT2); - omap_writel(omap_readl(ARM_IDLECT1) | (1 << 6), ARM_IDLECT1); - - 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) { - pr_err("Invalid SoSSI sync pattern: %08x, %08x\n", l, k); - return -ENODEV; - } - - if ((r = omap_lcdc_set_dma_callback(sossi_dma_callback, NULL)) < 0) { - pr_err("can't get LCDC IRQ\n"); - return r; - } - - l = sossi_read_reg(SOSSI_ID_REG); /* Component code */ - l = sossi_read_reg(SOSSI_ID_REG); - pr_info(MODULE_NAME ": 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); - - return 0; -} - -static void sossi_cleanup(void) -{ - omap_lcdc_free_dma_callback(); -} - -#define KHZ_TO_PS(x) (1000000000 / (x)) - -static void sossi_get_clk_info(u32 *clk_period, u32 *max_clk_div) -{ - *clk_period = KHZ_TO_PS(sossi.dpll_khz); - *max_clk_div = 8; -} +#define HZ_TO_PS(x) (1000000000 / (x / 1000)) static u32 ps_to_sossi_ticks(u32 ps, int div) { - u32 clk_period = KHZ_TO_PS(sossi.dpll_khz) * div; + u32 clk_period = HZ_TO_PS(sossi.fck_hz) * div; return (clk_period + ps - 1) / clk_period; } @@ -299,59 +217,48 @@ return 0; } -static int sossi_convert_timings(struct extif_timings *t) +static void _set_timing(int div, int tw0, int tw1) { - int r = 0; - int div = t->clk_div; - - t->converted = 0; - - if (div <= 0 || div > 8) - return -1; - - /* no CS on SOSSI, so ignore cson, csoff, cs_pulsewidth */ - if ((r = calc_rd_timings(t)) < 0) - return r; - - if ((r = calc_wr_timings(t)) < 0) - return r; - - t->tim[4] = div - 1; + u32 l; - t->converted = 1; +#ifdef VERBOSE + dev_dbg(sossi.fbdev->dev, "Using TW0 = %d, TW1 = %d, div = %d\n", + tw0 + 1, tw1 + 1, div); +#endif - return 0; + clk_set_rate(sossi.fck, sossi.fck_hz / div); + clk_enable(sossi.fck); + l = sossi_read_reg(SOSSI_INIT1_REG); + l &= ~((0x0f << 20) | (0x3f << 24)); + l |= (tw0 << 20) | (tw1 << 24); + sossi_write_reg(SOSSI_INIT1_REG, l); + clk_disable(sossi.fck); } -static void sossi_set_timings(const struct extif_timings *t) +static void _set_bits_per_cycle(int bus_pick_count, int bus_pick_width) { - BUG_ON(!t->converted); - - sossi.clk_tw0[RD_ACCESS] = t->tim[0]; - sossi.clk_tw1[RD_ACCESS] = t->tim[1]; - - sossi.clk_tw0[WR_ACCESS] = t->tim[2]; - sossi.clk_tw1[WR_ACCESS] = t->tim[3]; + u32 l; - sossi.clk_div = t->tim[4]; + l = sossi_read_reg(SOSSI_INIT3_REG); + l &= ~0x3ff; + l |= ((bus_pick_count - 1) << 5) | ((bus_pick_width - 1) & 0x1f); + sossi_write_reg(SOSSI_INIT3_REG, l); } -static void _set_timing(int div, int tw0, int tw1) +static void _set_tearsync_mode(int mode, unsigned line) { u32 l; - DBGPRINT(2, "Using TW0 = %d, TW1 = %d, div = %d\n", - tw0 + 1, tw1 + 1, div + 1); - - l = omap_readl(MOD_CONF_CTRL_1); - l &= ~(7 << 17); - l |= div << 17; - omap_writel(l, MOD_CONF_CTRL_1); - - l = sossi_read_reg(SOSSI_INIT1_REG); - l &= ~((0x0f << 20) | (0x3f << 24)); - l |= (tw0 << 20) | (tw1 << 24); - sossi_write_reg(SOSSI_INIT1_REG, l); + l = sossi_read_reg(SOSSI_TEARING_REG); + l &= ~(((1 << 11) - 1) << 15); + l |= line << 15; + l &= ~(0x3 << 26); + l |= mode << 26; + sossi_write_reg(SOSSI_TEARING_REG, l); + if (mode) + sossi_set_bits(SOSSI_INIT2_REG, 1 << 6); /* TE logic */ + else + sossi_clear_bits(SOSSI_INIT2_REG, 1 << 6); } static inline void set_timing(int access) @@ -363,43 +270,12 @@ } } -static void sossi_set_bits_per_cycle(int bpc) -{ - u32 l; - int bus_pick_count, bus_pick_width; - - DBGPRINT(2, "bits_per_cycle %d\n", bpc); - /* We set explicitly the 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; - } - l = sossi_read_reg(SOSSI_INIT3_REG); - sossi.bus_pick_width = bus_pick_width; - l &= ~0x3ff; - l |= ((bus_pick_count - 1) << 5) | ((bus_pick_width - 1) & 0x1f); - sossi_write_reg(SOSSI_INIT3_REG, l); -} - static void sossi_start_transfer(void) { /* WE */ sossi_clear_bits(SOSSI_INIT2_REG, 1 << 4); /* CS active low */ sossi_clear_bits(SOSSI_INIT1_REG, 1 << 30); - /* FIXME: locking? */ } static void sossi_stop_transfer(void) @@ -408,7 +284,6 @@ sossi_set_bits(SOSSI_INIT2_REG, 1 << 4); /* CS active low */ sossi_set_bits(SOSSI_INIT1_REG, 1 << 30); - /* FIXME: locking? */ } static void wait_end_of_write(void) @@ -446,9 +321,143 @@ sossi_set_bits(SOSSI_INIT1_REG, (nr_cycles - 1) & 0x3ffff); } +static int sossi_convert_timings(struct extif_timings *t) +{ + int r = 0; + int div = t->clk_div; + + t->converted = 0; + + if (div <= 0 || div > 8) + return -1; + + /* no CS on SOSSI, so ignore cson, csoff, cs_pulsewidth */ + if ((r = calc_rd_timings(t)) < 0) + return r; + + if ((r = calc_wr_timings(t)) < 0) + return r; + + t->tim[4] = div; + + t->converted = 1; + + return 0; +} + +static void sossi_set_timings(const struct extif_timings *t) +{ + BUG_ON(!t->converted); + + sossi.clk_tw0[RD_ACCESS] = t->tim[0]; + sossi.clk_tw1[RD_ACCESS] = t->tim[1]; + + sossi.clk_tw0[WR_ACCESS] = t->tim[2]; + sossi.clk_tw1[WR_ACCESS] = t->tim[3]; + + sossi.clk_div = t->tim[4]; +} + +static void sossi_get_clk_info(u32 *clk_period, u32 *max_clk_div) +{ + *clk_period = HZ_TO_PS(sossi.fck_hz); + *max_clk_div = 8; +} + +static void sossi_set_bits_per_cycle(int bpc) +{ + int bus_pick_count, bus_pick_width; + + /* We set explicitly the 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; +} + +static int 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--; + + dev_dbg(sossi.fbdev->dev, + "setup_tearsync: hs %d vs %d hs_inv %d vs_inv %d\n", + hs, vs, hs_pol_inv, vs_pol_inv); + + 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; +} + +static int 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; + + return 0; +} + static void sossi_write_command(const void *data, unsigned int len) { + clk_enable(sossi.fck); set_timing(WR_ACCESS); + _set_bits_per_cycle(sossi.bus_pick_count, sossi.bus_pick_width); /* CMD#/DATA */ sossi_clear_bits(SOSSI_INIT1_REG, 1 << 18); set_cycles(len); @@ -456,11 +465,14 @@ send_data(data, len); sossi_stop_transfer(); wait_end_of_write(); + clk_disable(sossi.fck); } static void sossi_write_data(const void *data, unsigned int len) { + clk_enable(sossi.fck); set_timing(WR_ACCESS); + _set_bits_per_cycle(sossi.bus_pick_count, sossi.bus_pick_width); /* CMD#/DATA */ sossi_set_bits(SOSSI_INIT1_REG, 1 << 18); set_cycles(len); @@ -468,6 +480,7 @@ send_data(data, len); sossi_stop_transfer(); wait_end_of_write(); + clk_disable(sossi.fck); } static void sossi_transfer_area(int width, int height, @@ -478,27 +491,44 @@ sossi.lcdc_callback = callback; sossi.lcdc_callback_data = data; + clk_enable(sossi.fck); set_timing(WR_ACCESS); + _set_bits_per_cycle(sossi.bus_pick_count, sossi.bus_pick_width); + _set_tearsync_mode(sossi.tearsync_mode, sossi.tearsync_line); /* CMD#/DATA */ sossi_set_bits(SOSSI_INIT1_REG, 1 << 18); set_cycles(width * height * sossi.bus_pick_width / 8); - DBGPRINT(2, "SOSSI_INIT1_REG %08x\n", sossi_read_reg(SOSSI_INIT1_REG)); - sossi_start_transfer(); - omap_enable_lcd_dma(); + 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. + */ + unsigned long 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(); } static void sossi_dma_callback(void *data) { omap_stop_lcd_dma(); sossi_stop_transfer(); + clk_disable(sossi.fck); sossi.lcdc_callback(sossi.lcdc_callback_data); } static void sossi_read_data(void *data, unsigned int len) { + clk_enable(sossi.fck); set_timing(RD_ACCESS); + _set_bits_per_cycle(sossi.bus_pick_count, sossi.bus_pick_width); /* CMD#/DATA */ sossi_set_bits(SOSSI_INIT1_REG, 1 << 18); set_cycles(len); @@ -519,6 +549,118 @@ data++; } sossi_stop_transfer(); + clk_disable(sossi.fck); +} + +static irqreturn_t sossi_match_irq(int irq, void *data, struct pt_regs *r) +{ + unsigned long flags; + + spin_lock_irqsave(&sossi.lock, flags); + if (sossi.vsync_dma_pending) { + sossi.vsync_dma_pending--; + omap_enable_lcd_dma(); + } + spin_unlock_irqrestore(&sossi.lock, flags); + return IRQ_HANDLED; +} + +static int sossi_init(struct omapfb_device *fbdev) +{ + u32 l, k; + struct clk *fck; + struct clk *dpll1out_ck; + int r; + + sossi.base = (void __iomem *)IO_ADDRESS(OMAP_SOSSI_BASE); + sossi.fbdev = fbdev; + spin_lock_init(&sossi.lock); + + 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_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(INT_SOSSI_MATCH, sossi_match_irq, IRQT_FALLING, + "sossi_match", sossi.fbdev->dev)) < 0) { + dev_err(sossi.fbdev->dev, "can't get SoSSI match IRQ\n"); + goto err; + } + + clk_disable(sossi.fck); + return 0; + +err: + clk_disable(sossi.fck); + clk_put(sossi.fck); + return r; +} + +static void sossi_cleanup(void) +{ + omap_lcdc_free_dma_callback(); + clk_put(sossi.fck); } struct lcd_ctrl_extif sossi_extif = { @@ -528,8 +670,13 @@ .convert_timings = sossi_convert_timings, .set_timings = sossi_set_timings, .set_bits_per_cycle = sossi_set_bits_per_cycle, + .setup_tearsync = sossi_setup_tearsync, + .enable_tearsync = sossi_enable_tearsync, .write_command = sossi_write_command, .read_data = sossi_read_data, .write_data = sossi_write_data, .transfer_area = sossi_transfer_area, + + .max_transmit_size = SOSSI_MAX_XMIT_BYTES, }; + diff -Naur -X kernel-source-2.6.16-2.6.16.rel/Documentation/dontdiff kernel-source-2.6.16-2.6.16.rel/include/asm-arm/arch-omap/irqs.h kernel-source-2.6.16-2.6.16.my/include/asm-arm/arch-omap/irqs.h --- kernel-source-2.6.16-2.6.16.rel/include/asm-arm/arch-omap/irqs.h 2008-04-07 09:52:45.000000000 +0200 +++ kernel-source-2.6.16-2.6.16.my/include/asm-arm/arch-omap/irqs.h 2007-04-29 21:36:06.000000000 +0200 @@ -123,6 +123,7 @@ #define INT_UART2 (15 + IH2_BASE) #define INT_BT_MCSI1TX (16 + IH2_BASE) #define INT_BT_MCSI1RX (17 + IH2_BASE) +#define INT_SOSSI_MATCH (19 + IH2_BASE) #define INT_USB_W2FC (20 + IH2_BASE) #define INT_1WIRE (21 + IH2_BASE) #define INT_OS_TIMER (22 + IH2_BASE) diff -Naur -X kernel-source-2.6.16-2.6.16.rel/Documentation/dontdiff kernel-source-2.6.16-2.6.16.rel/include/asm-arm/arch-omap/mux.h kernel-source-2.6.16-2.6.16.my/include/asm-arm/arch-omap/mux.h --- kernel-source-2.6.16-2.6.16.rel/include/asm-arm/arch-omap/mux.h 2006-11-28 14:17:04.000000000 +0100 +++ kernel-source-2.6.16-2.6.16.my/include/asm-arm/arch-omap/mux.h 2008-04-05 21:04:15.000000000 +0200 @@ -395,6 +395,9 @@ V10_1610_CF_IREQ, W10_1610_CF_RESET, W11_1610_CF_CD1, + + /* SOSSI tearing enabled*/ + G20_SOSSI_TE, }; enum omap24xx_index { diff -Naur -X kernel-source-2.6.16-2.6.16.rel/Documentation/dontdiff kernel-source-2.6.16-2.6.16.rel/include/asm-arm/arch-omap/omapfb.h kernel-source-2.6.16-2.6.16.my/include/asm-arm/arch-omap/omapfb.h --- kernel-source-2.6.16-2.6.16.rel/include/asm-arm/arch-omap/omapfb.h 2008-04-07 09:52:45.000000000 +0200 +++ kernel-source-2.6.16-2.6.16.my/include/asm-arm/arch-omap/omapfb.h 2007-05-01 13:48:41.000000000 +0200 @@ -50,11 +50,14 @@ #define OMAPFB_CAPS_PANEL_MASK 0xff000000 #define OMAPFB_CAPS_MANUAL_UPDATE 0x00001000 +#define OMAPFB_CAPS_TEARSYNC 0x00002000 #define OMAPFB_CAPS_SET_BACKLIGHT 0x01000000 /* Values from DSP must map to lower 16-bits */ #define OMAPFB_FORMAT_MASK 0x00ff #define OMAPFB_FORMAT_FLAG_DOUBLE 0x0100 +#define OMAPFB_FORMAT_FLAG_TEARSYNC 0x0200 +#define OMAPFB_FORMAT_FLAG_FORCE_VSYNC 0x0400 enum omapfb_color_format { OMAPFB_COLOR_RGB565 = 0, @@ -205,9 +208,10 @@ }; struct lcd_ctrl_extif { - int (*init) (void); + int (*init) (struct omapfb_device *fbdev); void (*cleanup) (void); void (*get_clk_info) (u32 *clk_period, u32 *max_clk_div); + unsigned long (*get_max_tx_rate)(void); int (*convert_timings) (struct extif_timings *timings); void (*set_timings) (const struct extif_timings *timings); void (*set_bits_per_cycle)(int bpc); @@ -217,6 +221,12 @@ void (*transfer_area) (int width, int height, void (callback)(void * data), void *data); unsigned long max_transmit_size; + int (*setup_tearsync) (unsigned pin_cnt, + unsigned hs_pulse_time, unsigned vs_pulse_time, + int hs_pol_inv, int vs_pol_inv, int div); + int (*enable_tearsync) (int enable, unsigned line); + + }; struct omapfb_notifier_block {