/* For S1D13745 */
#define BLIZZARD_SRC_WRITE_LCD_BACKGROUND 0x00
#define BLIZZARD_SRC_WRITE_LCD_DESTRUCTIVE 0x01
+#define BLIZZARD_SRC_WRITE_OVERLAY_ENABLE 0x04
+#define BLIZZARD_SRC_DISABLE_OVERLAY 0x05
/* For S1D13744 */
#define BLIZZARD_SRC_WRITE_LCD 0x00
#define BLIZZARD_SRC_BLT_LCD 0x06
+#define BLIZZARD_COLOR_RGB565 0x01
+#define BLIZZARD_COLOR_YUV420 0x09
+
#define BLIZZARD_VERSION_S1D13745 0x01 /* Hailstorm */
#define BLIZZARD_VERSION_S1D13744 0x02 /* Blizzard */
#define REQ_COMPLETE 0
#define REQ_PENDING 1
+struct blizzard_reg_list {
+ int start;
+ int end;
+};
+
+/* These need to be saved / restored separately from the rest. */
+static struct blizzard_reg_list blizzard_pll_regs[] = {
+ {
+ .start = 0x04, /* Don't save PLL ctrl (0x0C) */
+ .end = 0x0a,
+ },
+ {
+ .start = 0x0e, /* Clock configuration */
+ .end = 0x0e,
+ },
+};
+
+static struct blizzard_reg_list blizzard_gen_regs[] = {
+ {
+ .start = 0x18, /* SDRAM control */
+ .end = 0x20,
+ },
+ {
+ .start = 0x28, /* LCD Panel configuration */
+ .end = 0x5a, /* HSSI interface, TV configuration */
+ },
+};
+
+static u8 blizzard_reg_cache[0x5a / 2];
+
struct update_param {
int plane;
int x, y, width, height;
+ int out_x, out_y;
+ int out_width, out_height;
int color_mode;
+ int bpp;
int flags;
};
int enabled_planes;
int vid_nonstd_color;
int vid_scaled;
+ int last_color_mode;
+ int zoom_on;
int screen_width;
int screen_height;
unsigned te_connected:1;
}
}
-static void set_window_regs(int x_start, int y_start, int x_end, int y_end)
+/* Wait until the YYC color space converter is idle. */
+static void blizzard_wait_yyc(void)
{
- u8 tmp[8];
+ unsigned long tmo = jiffies + msecs_to_jiffies(30);
+
+ while (blizzard_read_reg(BLIZZARD_NDISP_CTRL_STATUS) & (1 << 4)) {
+ if (time_after(jiffies, tmo)) {
+ if (printk_ratelimit())
+ dev_err(blizzard.fbdev->dev,
+ "s1d1374x: YYC not ready\n");
+ break;
+ }
+ }
+}
+
+static void disable_overlay(void)
+{
+ blizzard_write_reg(BLIZZARD_DATA_SOURCE_SELECT,
+ BLIZZARD_SRC_DISABLE_OVERLAY);
+}
+
+static void set_window_regs(int x_start, int y_start, int x_end, int y_end,
+ int x_out_start, int y_out_start,
+ int x_out_end, int y_out_end, int color_mode,
+ int zoom_off, int flags)
+{
+ u8 tmp[18];
u8 cmd;
x_end--;
tmp[6] = y_end;
tmp[7] = y_end >> 8;
+ x_out_end--;
+ y_out_end--;
+ tmp[8] = x_out_start;
+ tmp[9] = x_out_start >> 8;
+ tmp[10] = y_out_start;
+ tmp[11] = y_out_start >> 8;
+ tmp[12] = x_out_end;
+ tmp[13] = x_out_end >> 8;
+ tmp[14] = y_out_end;
+ tmp[15] = y_out_end >> 8;
+
+ tmp[16] = color_mode;
+ if (zoom_off && blizzard.version == BLIZZARD_VERSION_S1D13745)
+ tmp[17] = BLIZZARD_SRC_WRITE_LCD_BACKGROUND;
+ else if (flags & OMAPFB_FORMAT_FLAG_ENABLE_OVERLAY)
+ tmp[17] = BLIZZARD_SRC_WRITE_OVERLAY_ENABLE;
+ else
+ tmp[17] = blizzard.version == BLIZZARD_VERSION_S1D13744 ?
+ BLIZZARD_SRC_WRITE_LCD :
+ BLIZZARD_SRC_WRITE_LCD_DESTRUCTIVE;
+
blizzard.extif->set_bits_per_cycle(8);
cmd = BLIZZARD_INPUT_WIN_X_START_0;
blizzard.extif->write_command(&cmd, 1);
- blizzard.extif->write_data(tmp, 8);
- blizzard.extif->write_data(tmp, 8);
-
- tmp[0] = 0x01;
- tmp[1] = blizzard.version == BLIZZARD_VERSION_S1D13744 ?
- BLIZZARD_SRC_WRITE_LCD :
- BLIZZARD_SRC_WRITE_LCD_DESTRUCTIVE;
- blizzard.extif->write_data(tmp, 2);
+ blizzard.extif->write_data(tmp, 18);
}
static void enable_tearsync(int y, int width, int height, int screen_height,
- int force_vsync)
+ int out_height, int force_vsync)
{
u8 b;
}
if ((width * blizzard.pix_tx_time / 1000) * height <
- (y + height) * (blizzard.line_upd_time / 1000)) {
+ (y + out_height) * (blizzard.line_upd_time / 1000)) {
blizzard.extif->enable_tearsync(1, 0);
return;
}
flags = req->par.update.flags;
if (flags & OMAPFB_FORMAT_FLAG_TEARSYNC)
enable_tearsync(0, blizzard.screen_width,
+ blizzard.screen_height,
blizzard.screen_height,
blizzard.screen_height,
flags & OMAPFB_FORMAT_FLAG_FORCE_VSYNC);
else
disable_tearsync();
- set_window_regs(0, 0, blizzard.screen_width, blizzard.screen_height);
+ set_window_regs(0, 0, blizzard.screen_width, blizzard.screen_height,
+ 0, 0, blizzard.screen_width, blizzard.screen_height,
+ BLIZZARD_COLOR_RGB565, blizzard.zoom_on, flags);
+ blizzard.zoom_on = 0;
blizzard.extif->set_bits_per_cycle(16);
/* set_window_regs has left the register index at the right
/* Setup all planes with an overlapping area with the update window. */
static int do_partial_update(struct blizzard_request *req, int plane,
- int x, int y, int w, int h)
+ int x, int y, int w, int h,
+ int x_out, int y_out, int w_out, int h_out,
+ int wnd_color_mode, int bpp)
{
int i;
int gx1, gy1, gx2, gy2;
+ int gx1_out, gy1_out, gx2_out, gy2_out;
+ int color_mode;
int flags;
+ int zoom_off;
/* Global coordinates, relative to pixel 0,0 of the LCD */
gx1 = x + blizzard.plane[plane].pos_x;
gx2 = gx1 + w;
gy2 = gy1 + h;
+ flags = req->par.update.flags;
+ if (flags & OMAPFB_FORMAT_FLAG_DOUBLE) {
+ gx1_out = gx1;
+ gy1_out = gy1;
+ gx2_out = gx1 + w * 2;
+ gy2_out = gy1 + h * 2;
+ } else {
+ gx1_out = x_out + blizzard.plane[plane].pos_x;
+ gy1_out = y_out + blizzard.plane[plane].pos_y;
+ gx2_out = gx1_out + w_out;
+ gy2_out = gy1_out + h_out;
+ }
+ zoom_off = blizzard.zoom_on && gx1 == 0 && gy1 == 0 &&
+ w == blizzard.screen_width && h == blizzard.screen_height;
+ blizzard.zoom_on = (!zoom_off && blizzard.zoom_on) ||
+ (w < w_out || h < h_out);
+
for (i = 0; i < OMAPFB_PLANE_NUM; i++) {
struct plane_info *p = &blizzard.plane[i];
int px1, py1;
int pposx, pposy;
unsigned long offset;
- if (!(blizzard.enabled_planes & (1 << i))) {
+ if (!(blizzard.enabled_planes & (1 << i)) ||
+ (wnd_color_mode && i != plane)) {
blizzard.int_ctrl->enable_plane(i, 0);
continue;
}
pw = px2 - px1;
ph = py2 - py1;
offset = p->offset + (p->scr_width * py1 + px1) * p->bpp / 8;
+ if (wnd_color_mode)
+ /* Window embedded in the plane with a differing
+ * color mode / bpp. Calculate the number of DMA
+ * transfer elements in terms of the plane's bpp.
+ */
+ pw = (pw + 1) * bpp / p->bpp;
#ifdef VERBOSE
dev_dbg(blizzard.fbdev->dev,
"plane %d offset %#08lx pposx %d pposy %d "
blizzard.int_ctrl->enable_plane(i, 1);
}
+ switch (wnd_color_mode) {
+ case OMAPFB_COLOR_YUV420:
+ color_mode = BLIZZARD_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;
+ break;
+ default:
+ color_mode = BLIZZARD_COLOR_RGB565;
+ break;
+ }
+
blizzard_wait_line_buffer();
- flags = req->par.update.flags;
+ if (blizzard.last_color_mode == BLIZZARD_COLOR_YUV420)
+ blizzard_wait_yyc();
+ blizzard.last_color_mode = color_mode;
if (flags & OMAPFB_FORMAT_FLAG_TEARSYNC)
- enable_tearsync(gy1, gx2 - gx1, gy2 - gy1,
+ enable_tearsync(gy1, w, h,
blizzard.screen_height,
+ h_out,
flags & OMAPFB_FORMAT_FLAG_FORCE_VSYNC);
else
disable_tearsync();
- set_window_regs(gx1, gy1, gx2, gy2);
+ set_window_regs(gx1, gy1, gx2, gy2, gx1_out, gy1_out, gx2_out, gy2_out,
+ color_mode, zoom_off, flags);
blizzard.extif->set_bits_per_cycle(16);
/* set_window_regs has left the register index at the right
#ifdef VERBOSE
dev_dbg(blizzard.fbdev->dev,
- "send_frame: x %d y %d w %d h %d color_mode %04x flags %04x "
- "planes %01x\n",
+ "send_frame: x %d y %d w %d h %d "
+ "x_out %d y_out %d w_out %d h_out %d "
+ "color_mode %04x flags %04x planes %01x\n",
par->x, par->y, par->width, par->height,
+ par->out_x, par->out_y, par->out_width, par->out_height,
par->color_mode, par->flags, blizzard.enabled_planes);
#endif
+ if (par->flags & OMAPFB_FORMAT_FLAG_DISABLE_OVERLAY)
+ disable_overlay();
if ((blizzard.enabled_planes & blizzard.vid_nonstd_color) ||
(blizzard.enabled_planes & blizzard.vid_scaled))
return do_full_screen_update(req);
return do_partial_update(req, plane, par->x, par->y,
- par->width, par->height);
+ par->width, par->height,
+ par->out_x, par->out_y,
+ par->out_width, par->out_height,
+ par->color_mode, par->bpp);
}
static void send_frame_complete(void *data)
{
}
-#define ADD_PREQ(_x, _y, _w, _h) do { \
+#define ADD_PREQ(_x, _y, _w, _h, _x_out, _y_out, _w_out, _h_out) do { \
req = alloc_req(); \
req->handler = send_frame_handler; \
req->complete = send_frame_complete; \
- req->par.update.plane = plane; \
+ req->par.update.plane = plane_idx; \
req->par.update.x = _x; \
req->par.update.y = _y; \
req->par.update.width = _w; \
req->par.update.height = _h; \
+ req->par.update.out_x = _x_out; \
+ req->par.update.out_y = _y_out; \
+ req->par.update.out_width = _w_out; \
+ req->par.update.out_height = _h_out; \
+ req->par.update.bpp = bpp; \
req->par.update.color_mode = color_mode;\
req->par.update.flags = flags; \
list_add_tail(&req->entry, req_head); \
} while(0)
-static void create_req_list(int plane,
+static void create_req_list(int plane_idx,
struct omapfb_update_window *win,
struct list_head *req_head)
{
struct blizzard_request *req;
- int x = (win->x & ~0x07);
- int y = (win->y & ~0x07);
- int width = ((win->x + win->width + 7) & ~0x07) - x;
- int height = ((win->y + win->height + 7) & ~0x07) - y;
+ int x = win->x;
+ int y = win->y;
+ int width = win->width;
+ int height = win->height;
+ int x_out = win->out_x;
+ int y_out = win->out_y;
+ int width_out = win->out_width;
+ int height_out = win->out_height;
int color_mode;
+ int bpp;
int flags;
+ unsigned int ystart = y;
+ unsigned int yspan = height;
+ unsigned int ystart_out = y_out;
+ unsigned int yspan_out = height_out;
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;
+ switch (color_mode) {
+ case OMAPFB_COLOR_YUV420:
+ /* Embedded window with different color mode */
+ bpp = 12;
+ /* X, Y, height must be aligned at 2, width at 4 pixels */
+ x &= ~1;
+ y &= ~1;
+ height = yspan = height & ~1;
+ width = width & ~3;
+ break;
+ default:
+ /* Same as the plane color mode */
+ bpp = blizzard.plane[plane_idx].bpp;
+ break;
}
- if (width & ~1) {
- unsigned int xspan = width & ~1;
- unsigned int ystart = y;
- unsigned int yspan = height;
-
- if (xspan * height * 2 > blizzard.max_transmit_size) {
- yspan = blizzard.max_transmit_size / (xspan * 2);
- 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;
+ if (width * height * bpp / 8 > blizzard.max_transmit_size) {
+ yspan = blizzard.max_transmit_size / (width * bpp / 8);
+ yspan_out = yspan * height_out / height;
+ ADD_PREQ(x, ystart, width, yspan, x_out, ystart_out,
+ width_out, yspan_out);
+ ystart += yspan;
+ ystart_out += yspan_out;
+ yspan = height - yspan;
+ yspan_out = height_out - yspan_out;
flags &= ~OMAPFB_FORMAT_FLAG_TEARSYNC;
}
- if (width)
- ADD_PREQ(x, y, 1, height);
+
+ ADD_PREQ(x, ystart, width, yspan, x_out, ystart_out,
+ width_out, yspan_out);
}
static void auto_update_complete(void *data)
}
EXPORT_SYMBOL(blizzard_update_window_async);
+static int update_full_screen(void)
+{
+ return blizzard_update_window_async(blizzard.fbdev->fb_info[0],
+ &blizzard.auto_update_window, NULL, NULL);
+
+}
+
static int blizzard_setup_plane(int plane, int channel_out,
unsigned long offset, int screen_width,
int pos_x, int pos_y, int width, int height,
case OMAPFB_COLOR_YUV422:
case OMAPFB_COLOR_YUY422:
p->bpp = 16;
- blizzard.vid_nonstd_color |= 1 << plane;
+ blizzard.vid_nonstd_color &= ~(1 << plane);
break;
case OMAPFB_COLOR_YUV420:
p->bpp = 12;
wait_for_completion(&comp);
}
+
static void blizzard_bind_client(struct omapfb_notifier_block *nb)
{
if (blizzard.update_mode == OMAPFB_MANUAL_UPDATE) {
extif_div);
}
-static unsigned long blizzard_get_caps(void)
+static void blizzard_get_caps(int plane, struct omapfb_caps *caps)
{
- unsigned long caps;
-
- caps = OMAPFB_CAPS_MANUAL_UPDATE;
+ blizzard.int_ctrl->get_caps(plane, caps);
+ caps->ctrl |= OMAPFB_CAPS_MANUAL_UPDATE |
+ OMAPFB_CAPS_WINDOW_PIXEL_DOUBLE |
+ OMAPFB_CAPS_WINDOW_SCALE |
+ OMAPFB_CAPS_WINDOW_OVERLAY;
if (blizzard.te_connected)
- caps |= OMAPFB_CAPS_TEARSYNC;
- return caps;
+ caps->ctrl |= OMAPFB_CAPS_TEARSYNC;
+ caps->wnd_color |= (1 << OMAPFB_COLOR_RGB565) |
+ (1 << OMAPFB_COLOR_YUV420);
+}
+
+static void _save_regs(struct blizzard_reg_list *list, int cnt)
+{
+ int i;
+
+ for (i = 0; i < cnt; i++, list++) {
+ int reg;
+ for (reg = list->start; reg <= list->end; reg += 2)
+ blizzard_reg_cache[reg / 2] = blizzard_read_reg(reg);
+ }
+}
+
+static void _restore_regs(struct blizzard_reg_list *list, int cnt)
+{
+ int i;
+
+ for (i = 0; i < cnt; i++, list++) {
+ int reg;
+ for (reg = list->start; reg <= list->end; reg += 2)
+ blizzard_write_reg(reg, blizzard_reg_cache[reg / 2]);
+ }
+}
+
+static void blizzard_save_all_regs(void)
+{
+ _save_regs(blizzard_pll_regs, ARRAY_SIZE(blizzard_pll_regs));
+ _save_regs(blizzard_gen_regs, ARRAY_SIZE(blizzard_gen_regs));
+}
+
+static void blizzard_restore_pll_regs(void)
+{
+ _restore_regs(blizzard_pll_regs, ARRAY_SIZE(blizzard_pll_regs));
+}
+
+static void blizzard_restore_gen_regs(void)
+{
+ _restore_regs(blizzard_gen_regs, ARRAY_SIZE(blizzard_gen_regs));
}
static void blizzard_suspend(void)
u32 l;
unsigned long tmo;
+ if (blizzard.last_color_mode) {
+ update_full_screen();
+ blizzard_sync();
+ }
blizzard.update_mode_before_suspend = blizzard.update_mode;
/* the following will disable clocks as well */
blizzard_set_update_mode(OMAPFB_UPDATE_DISABLED);
+ blizzard_save_all_regs();
+
blizzard_stop_sdram();
l = blizzard_read_reg(BLIZZARD_POWER_SAVE);
l &= ~0x03;
blizzard_write_reg(BLIZZARD_POWER_SAVE, l);
+ blizzard_restore_pll_regs();
l = blizzard_read_reg(BLIZZARD_PLL_MODE);
l &= ~0x03;
/* Enable PLL, counter function */
while (!(blizzard_read_reg(BLIZZARD_PLL_DIV) & (1 << 7)))
msleep(1);
+
blizzard_restart_sdram();
+
+ blizzard_restore_gen_regs();
+
/* Enable display */
blizzard_write_reg(BLIZZARD_DISPLAY_MODE, 0x01);
/* the following will enable clocks as necessary */
blizzard_set_update_mode(blizzard.update_mode_before_suspend);
+
+ /* Force a background update */
+ blizzard.zoom_on = 1;
+ update_full_screen();
+ blizzard_sync();
}
static int blizzard_init(struct omapfb_device *fbdev, int ext_mode,
blizzard_ctrl.set_color_key = blizzard.int_ctrl->set_color_key;
blizzard_ctrl.get_color_key = blizzard.int_ctrl->get_color_key;
+ blizzard_ctrl.setup_mem = blizzard.int_ctrl->setup_mem;
+ blizzard_ctrl.mmap = blizzard.int_ctrl->mmap;
ext_clk = ctrl_conf->get_clock_rate(fbdev->dev);
if ((r = calc_extif_timings(ext_clk, &extif_div)) < 0)
blizzard.auto_update_window.y = 0;
blizzard.auto_update_window.width = fbdev->panel->x_res;
blizzard.auto_update_window.height = fbdev->panel->y_res;
+ blizzard.auto_update_window.out_x = 0;
+ blizzard.auto_update_window.out_x = 0;
+ blizzard.auto_update_window.out_width = fbdev->panel->x_res;
+ blizzard.auto_update_window.out_height = fbdev->panel->y_res;
blizzard.auto_update_window.format = 0;
blizzard.screen_width = fbdev->panel->x_res;