static int sh_mobile_fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) { struct sh_mobile_lcdc_chan *ch = info->par; struct sh_mobile_lcdc_priv *priv = ch->lcdc; unsigned long ldrcntr; unsigned long new_pan_offset; unsigned long base_addr_y, base_addr_c; unsigned long c_offset; if (!var->nonstd) new_pan_offset = (var->yoffset * info->fix.line_length) + (var->xoffset * (info->var.bits_per_pixel / 8)); else new_pan_offset = (var->yoffset * info->fix.line_length) + (var->xoffset); if (new_pan_offset == ch->pan_offset) return 0; /* No change, do nothing */ ldrcntr = lcdc_read(priv, _LDRCNTR); /* Set the source address for the next refresh */ base_addr_y = ch->dma_handle + new_pan_offset; if (var->nonstd) { /* Set y offset */ c_offset = (var->yoffset * info->fix.line_length * (info->var.bits_per_pixel - 8)) / 8; base_addr_c = ch->dma_handle + var->xres * var->yres_virtual + c_offset; /* Set x offset */ if (info->var.bits_per_pixel == 24) base_addr_c += 2 * var->xoffset; else base_addr_c += var->xoffset; } else base_addr_c = 0; lcdc_write_chan_mirror(ch, LDSA1R, base_addr_y); if (base_addr_c) lcdc_write_chan_mirror(ch, LDSA2R, base_addr_c); if (lcdc_chan_is_sublcd(ch)) lcdc_write(ch->lcdc, _LDRCNTR, ldrcntr ^ LDRCNTR_SRS); else lcdc_write(ch->lcdc, _LDRCNTR, ldrcntr ^ LDRCNTR_MRS); ch->pan_offset = new_pan_offset; sh_mobile_lcdc_deferred_io_touch(info); return 0; }
static int sh_mobile_fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) { struct sh_mobile_lcdc_chan *ch = info->par; struct sh_mobile_lcdc_priv *priv = ch->lcdc; unsigned long ldrcntr; unsigned long new_pan_offset; new_pan_offset = (var->yoffset * info->fix.line_length) + (var->xoffset * (info->var.bits_per_pixel / 8)); if (new_pan_offset == ch->pan_offset) return 0; /* No change, do nothing */ ldrcntr = lcdc_read(priv, _LDRCNTR); /* Set the source address for the next refresh */ lcdc_write_chan_mirror(ch, LDSA1R, ch->dma_handle + new_pan_offset); if (lcdc_chan_is_sublcd(ch)) lcdc_write(ch->lcdc, _LDRCNTR, ldrcntr ^ LDRCNTR_SRS); else lcdc_write(ch->lcdc, _LDRCNTR, ldrcntr ^ LDRCNTR_MRS); ch->pan_offset = new_pan_offset; sh_mobile_lcdc_deferred_io_touch(info); return 0; }
static irqreturn_t sh_mobile_lcdc_irq(int irq, void *data) { struct sh_mobile_lcdc_priv *priv = data; struct sh_mobile_lcdc_chan *ch; unsigned long tmp; unsigned long ldintr; int is_sub; int k; /* acknowledge interrupt */ ldintr = tmp = lcdc_read(priv, _LDINTR); /* * disable further VSYNC End IRQs, preserve all other enabled IRQs, * write 0 to bits 0-6 to ack all triggered IRQs. */ tmp &= 0xffffff00 & ~LDINTR_VEE; lcdc_write(priv, _LDINTR, tmp); /* figure out if this interrupt is for main or sub lcd */ is_sub = (lcdc_read(priv, _LDSR) & (1 << 10)) ? 1 : 0; /* wake up channel and disable clocks */ for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { ch = &priv->ch[k]; if (!ch->enabled) continue; /* Frame Start */ if (ldintr & LDINTR_FS) { if (is_sub == lcdc_chan_is_sublcd(ch)) { ch->frame_end = 1; wake_up(&ch->frame_end_wait); sh_mobile_lcdc_clk_off(priv); } } /* VSYNC End */ if (ldintr & LDINTR_VES) { unsigned long ldrcntr = lcdc_read(priv, _LDRCNTR); /* Set the source address for the next refresh */ lcdc_write_chan_mirror(ch, LDSA1R, ch->dma_handle + ch->new_pan_offset); if (lcdc_chan_is_sublcd(ch)) lcdc_write(ch->lcdc, _LDRCNTR, ldrcntr ^ LDRCNTR_SRS); else lcdc_write(ch->lcdc, _LDRCNTR, ldrcntr ^ LDRCNTR_MRS); ch->pan_offset = ch->new_pan_offset; } } return IRQ_HANDLED; }
static irqreturn_t sh_mobile_lcdc_irq(int irq, void *data) { struct sh_mobile_lcdc_priv *priv = data; struct sh_mobile_lcdc_chan *ch; unsigned long tmp; unsigned long ldintr; int is_sub; int k; ldintr = tmp = lcdc_read(priv, _LDINTR); tmp &= 0xffffff00 & ~LDINTR_VEE; lcdc_write(priv, _LDINTR, tmp); is_sub = (lcdc_read(priv, _LDSR) & (1 << 10)) ? 1 : 0; for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { ch = &priv->ch[k]; if (!ch->enabled) continue; if (ldintr & LDINTR_FS) { if (is_sub == lcdc_chan_is_sublcd(ch)) { ch->frame_end = 1; wake_up(&ch->frame_end_wait); sh_mobile_lcdc_clk_off(priv); } } if (ldintr & LDINTR_VES) { unsigned long ldrcntr = lcdc_read(priv, _LDRCNTR); lcdc_write_chan_mirror(ch, LDSA1R, ch->dma_handle + ch->new_pan_offset); if (lcdc_chan_is_sublcd(ch)) lcdc_write(ch->lcdc, _LDRCNTR, ldrcntr ^ LDRCNTR_SRS); else lcdc_write(ch->lcdc, _LDRCNTR, ldrcntr ^ LDRCNTR_MRS); ch->pan_offset = ch->new_pan_offset; } } return IRQ_HANDLED; }