Commit e563dc81 authored by Imre Deak's avatar Imre Deak Committed by Juha Yrjola

ARM: OMAP: omapfb: main and LCD controller module changes

- Support for
        - overlays through separate /dev/fbX nodes
        - scaling and color space conversion
        - per-plane memory configuration either in SRAM or SDRAM

- Replace custom debug stuff with the default kernel one
Signed-off-by: default avatarImre Deak <ext-imre.deak@nokia.com>
Signed-off-by: default avatarJuha Yrjola <juha.yrjola@solidboot.com>
parent 4741bf3a
......@@ -27,12 +27,13 @@ config FB_OMAP_MANUAL_UPDATE
the frame buffer content and thus a reload of the image data to
the external frame buffer is required. If unsure, say N.
config FB_OMAP_LCD_LPH8923
bool "Philips LPH8923 LCD support"
config FB_OMAP_LCD_MIPID
bool "MIPI DBI-C/DCS compatible LCD support"
depends on FB_OMAP
help
Say Y here if you want to have support for the Philips
LPH8923 LCD.
Say Y here if you want to have support for LCDs compatible with
the Mobile Industry Processor Interface DBI-C/DCS
specification. (Supported LCDs: Philips LPH8923, Sharp LS041Y3)
config FB_OMAP_BOOTLOADER_INIT
bool "Check bootloader initializaion"
......@@ -42,6 +43,17 @@ config FB_OMAP_BOOTLOADER_INIT
already initialized the display controller. In this case the
driver will skip the initialization.
config FB_OMAP_CONSISTENT_DMA_SIZE
int "Consistent DMA memory size (MB)"
depends on FB_OMAP
range 1 14
default 2
help
Increase the DMA consistent memory size according to your video
memory needs, for example if you want to use multiple planes.
The size must be 2MB aligned.
If unsure say 1.
config FB_OMAP_DMA_TUNE
bool "Set DMA SDRAM access priority high"
depends on FB_OMAP && ARCH_OMAP1
......
......@@ -24,7 +24,7 @@ objs-y$(CONFIG_MACH_OMAP_OSK) += lcd_osk.o
objs-y$(CONFIG_MACH_OMAP_PERSEUS2) += lcd_p2.o
objs-y$(CONFIG_MACH_OMAP_APOLLON) += lcd_apollon.o
objs-y$(CONFIG_FB_OMAP_LCD_LPH8923) += lcd_lph8923.o
objs-y$(CONFIG_FB_OMAP_LCD_MIPID) += lcd_mipid.o
omapfb-objs := $(objs-yy)
/*
* File: drivers/video/omap_new/debug.c
*
* Debug support for the omapfb driver
*
* Copyright (C) 2004 Nokia Corporation
* Author: Imre Deak <imre.deak@nokia.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef __OMAPFB_DEBUG_H
#define __OMAPFB_DEBUG_H
#ifdef OMAPFB_DBG
#define DBGPRINT(level, fmt, ...) if (level <= OMAPFB_DBG) do { \
printk(KERN_DEBUG "%s: "fmt, \
__FUNCTION__, ## __VA_ARGS__); \
} while (0)
#define DBGENTER(level) DBGPRINT(level, "Enter\n")
#define DBGLEAVE(level) DBGPRINT(level, "Leave\n")
#else /* OMAPFB_DBG */
#define DBGPRINT(level, format, ...)
#define DBGENTER(level)
#define DBGLEAVE(level)
#endif /* OMAPFB_DBG */
#endif /* __OMAPFB_DEBUG_H */
......@@ -20,7 +20,6 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <linux/kernel.h>
#include <linux/dma-mapping.h>
#include <linux/vmalloc.h>
......@@ -34,11 +33,7 @@
#include "dispc.h"
/* #define OMAPFB_DBG 1 */
#include "debug.h"
#define MODULE_NAME "omapfb-dispc"
#define MODULE_NAME "dispc"
#define DISPC_BASE 0x48050400
......@@ -134,8 +129,6 @@
#define MAX_PALETTE_SIZE (256 * 16)
#define pr_err(fmt, args...) printk(KERN_ERR MODULE_NAME ": " fmt, ## args)
#define FLD_MASK(pos, len) (((1 << len) - 1) << pos)
#define MOD_REG_FLD(reg, mask, val) \
......@@ -144,22 +137,11 @@
static struct {
u32 base;
dma_addr_t fb_sram_paddr;
u32 fb_sram_size;
int fb_sram_lines;
dma_addr_t fb_sdram_paddr;
void *fb_sdram_vaddr;
u32 fb_sdram_size;
int fb_sdram_lines;
struct omapfb_mem_desc mem_desc;
dma_addr_t palette_paddr;
void *palette_vaddr;
void *fb_kern_vaddr;
int multiplane_head;
int ext_mode;
int fbmem_allocated;
......@@ -168,11 +150,16 @@ static struct {
void *irq_callback_data;
struct completion frame_done;
int fir_hinc[OMAPFB_PLANE_NUM];
int fir_vinc[OMAPFB_PLANE_NUM];
struct clk *dss_ick, *dss1_fck;
struct clk *dss_54m_fck;
enum omapfb_update_mode update_mode;
struct omapfb_device *fbdev;
struct omapfb_color_key color_key;
} dispc;
static void inline dispc_write_reg(int idx, u32 val)
......@@ -302,22 +289,31 @@ static inline int _setup_plane(int plane, int channel_out,
const u32 ps_reg[] = { DISPC_GFX_POSITION,
DISPC_VID1_BASE + DISPC_VID_POSITION,
DISPC_VID2_BASE + DISPC_VID_POSITION };
const u32 sz_reg[] = { DISPC_GFX_SIZE, DISPC_VID1_BASE + DISPC_VID_SIZE,
DISPC_VID2_BASE + DISPC_VID_SIZE };
const u32 sz_reg[] = { DISPC_GFX_SIZE,
DISPC_VID1_BASE + DISPC_VID_PICTURE_SIZE,
DISPC_VID2_BASE + DISPC_VID_PICTURE_SIZE };
const u32 ri_reg[] = { DISPC_GFX_ROW_INC,
DISPC_VID1_BASE + DISPC_VID_ROW_INC,
DISPC_VID2_BASE + DISPC_VID_ROW_INC };
const u32 vs_reg[]= { 0, DISPC_VID1_BASE + DISPC_VID_SIZE,
DISPC_VID2_BASE + DISPC_VID_SIZE };
int chout_shift, burst_shift;
int chout_val;
int color_code;
int bpp;
int cconv_en;
int set_vsize;
u32 l;
DBGPRINT(2, "plane %d channel %d paddr %u scr_width %d pos_x %d pos_y %d "
"width %d height %d color_mode %d\n",
#ifdef VERBOSE
dev_dbg(dispc.fbdev->dev, "plane %d channel %d paddr %#08x scr_width %d "
"pos_x %d pos_y %d width %d height %d color_mode %d\n",
plane, channel_out, paddr, screen_width, pos_x, pos_y,
width, height, color_mode);
#endif
set_vsize = 0;
switch (plane) {
case OMAPFB_PLANE_GFX:
burst_shift = 6;
......@@ -327,6 +323,7 @@ static inline int _setup_plane(int plane, int channel_out,
case OMAPFB_PLANE_VID2:
burst_shift = 14;
chout_shift = 16;
set_vsize = 1;
break;
default:
return -EINVAL;
......@@ -343,22 +340,25 @@ static inline int _setup_plane(int plane, int channel_out,
return -EINVAL;
}
cconv_en = 0;
switch (color_mode) {
case OMAPFB_COLOR_RGB565:
color_code = DISPC_RGB_16_BPP;
bpp = 16;
break;
case OMAPFB_COLOR_YUV422:
if (plane != 0)
if (plane == 0)
return -EINVAL;
color_code = DISPC_UYVY_422;
cconv_en = 1;
bpp = 16;
break;
case OMAPFB_COLOR_YUV420:
if (plane != 0)
case OMAPFB_COLOR_YUY422:
if (plane == 0)
return -EINVAL;
color_code = DISPC_YUV2_422;
bpp = 12;
cconv_en = 1;
bpp = 16;
break;
default:
return -EINVAL;
......@@ -368,6 +368,8 @@ static inline int _setup_plane(int plane, int channel_out,
l &= ~(0x0f << 1);
l |= color_code << 1;
l &= ~(1 << 9);
l |= cconv_en << 9;
l &= ~(0x03 << burst_shift);
l |= DISPC_BURST_8x32 << burst_shift;
......@@ -384,53 +386,145 @@ static inline int _setup_plane(int plane, int channel_out,
MOD_REG_FLD(sz_reg[plane], FLD_MASK(16, 11) | FLD_MASK(0, 11),
((height - 1) << 16) | (width - 1));
if (set_vsize) {
/* Set video size if set_scale hasn't set it */
if (!dispc.fir_hinc[plane])
MOD_REG_FLD(vs_reg[plane],
FLD_MASK(16, 11), (height - 1) << 16);
if (!dispc.fir_vinc[plane])
MOD_REG_FLD(vs_reg[plane],
FLD_MASK(0, 11), width - 1);
}
dispc_write_reg(ri_reg[plane], (screen_width - width) * bpp / 8 + 1);
return height * screen_width * bpp / 8;
}
static int omap_dispc_setup_plane(int plane, int channel_out,
unsigned long offset, int screen_width,
unsigned long offset,
int screen_width,
int pos_x, int pos_y, int width, int height,
int color_mode)
{
int yspan;
u32 paddr;
int mp_head = -1;
int r;
if (offset > dispc.fb_sram_size + dispc.fb_sdram_size)
if ((unsigned)plane > dispc.mem_desc.region_cnt)
return -EINVAL;
paddr = dispc.mem_desc.region[plane].paddr + offset;
return _setup_plane(plane, channel_out, paddr,
screen_width,
pos_x, pos_y, width, height, color_mode);
}
if (offset < dispc.fb_sram_size) {
paddr = dispc.fb_sram_paddr + offset;
yspan = min_t(int, height, dispc.fb_sram_lines);
if (yspan) {
if ((r = _setup_plane(plane, channel_out, paddr,
screen_width, pos_x, pos_y,
width, height, color_mode)) < 0)
return r;
offset += r;
height -= yspan;
pos_y += yspan;
mp_head = plane;
if (++plane > 2)
plane = OMAPFB_PLANE_GFX;
}
}
if (height) {
offset -= dispc.fb_sram_size;
paddr = dispc.fb_sdram_paddr + offset;
yspan = min_t(int, height, dispc.fb_sdram_lines);
if (yspan) {
if ((r = _setup_plane(plane, channel_out, paddr,
screen_width, pos_x, pos_y,
width, height, color_mode)) < 0)
return r;
if (mp_head != -1)
dispc.multiplane_head = mp_head;
static void write_firh_reg(int plane, int reg, u32 value)
{
u32 base;
if (plane == 1)
base = DISPC_VID1_BASE + DISPC_VID_FIR_COEF_H0;
else
base = DISPC_VID2_BASE + DISPC_VID_FIR_COEF_H0;
dispc_write_reg(base + reg * 8, value);
}
static void write_firhv_reg(int plane, int reg, u32 value)
{
u32 base;
if (plane == 1)
base = DISPC_VID1_BASE + DISPC_VID_FIR_COEF_HV0;
else
base = DISPC_VID2_BASE + DISPC_VID_FIR_COEF_HV0;
dispc_write_reg(base + reg * 8, value);
}
static void set_upsampling_coef_table(int plane)
{
const u32 coef[][2] = {
{ 0x00800000, 0x00800000 },
{ 0x0D7CF800, 0x037B02FF },
{ 0x1E70F5FF, 0x0C6F05FE },
{ 0x335FF5FE, 0x205907FB },
{ 0xF74949F7, 0x00404000 },
{ 0xF55F33FB, 0x075920FE },
{ 0xF5701EFE, 0x056F0CFF },
{ 0xF87C0DFF, 0x027B0300 },
};
int i;
for (i = 0; i < 8; i++) {
write_firh_reg(plane, i, coef[i][0]);
write_firhv_reg(plane, i, coef[i][1]);
}
}
static int omap_dispc_set_scale(int plane,
int orig_width, int orig_height,
int out_width, int out_height)
{
const u32 at_reg[] = { 0, DISPC_VID1_BASE + DISPC_VID_ATTRIBUTES,
DISPC_VID2_BASE + DISPC_VID_ATTRIBUTES };
const u32 vs_reg[] = { 0, DISPC_VID1_BASE + DISPC_VID_SIZE,
DISPC_VID2_BASE + DISPC_VID_SIZE };
const u32 fir_reg[] = { 0, DISPC_VID1_BASE + DISPC_VID_FIR,
DISPC_VID2_BASE + DISPC_VID_FIR };
u32 l;
int fir_hinc;
int fir_vinc;
if ((unsigned)plane > OMAPFB_PLANE_NUM)
return -ENODEV;
if (plane == OMAPFB_PLANE_GFX &&
(out_width != orig_width || out_height != orig_height))
return -EINVAL;
if (orig_width < out_width) {
/* Upsampling.
* Currently you can only scale both dimensions in one way.
*/
if (orig_height > out_height ||
orig_width * 8 < out_width ||
orig_height * 8 < out_height)
return -EINVAL;
set_upsampling_coef_table(plane);
} else if (orig_width > out_width) {
/* Downsampling not yet supported
*/
return -EINVAL;
}
if (!orig_width || orig_width == out_width)
fir_hinc = 0;
else
fir_hinc = 1024 * orig_width / out_width;
if (!orig_height || orig_height == out_height)
fir_vinc = 0;
else
fir_vinc = 1024 * orig_height / out_height;
dispc.fir_hinc[plane] = fir_hinc;
dispc.fir_vinc[plane] = fir_vinc;
MOD_REG_FLD(fir_reg[plane],
FLD_MASK(16, 12) | FLD_MASK(0, 12),
((fir_vinc & 4095) << 16) |
(fir_hinc & 4095));
dev_dbg(dispc.fbdev->dev, "out_width %d out_height %d orig_width %d "
"orig_height %d fir_hinc %d fir_vinc %d\n",
out_width, out_height, orig_width, orig_height,
fir_hinc, fir_vinc);
MOD_REG_FLD(vs_reg[plane],
FLD_MASK(16, 11) | FLD_MASK(0, 11),
((out_height - 1) << 16) | (out_width - 1));
l = dispc_read_reg(at_reg[plane]);
l &= ~(0x03 << 5);
l |= fir_hinc ? (1 << 5) : 0;
l |= fir_vinc ? (1 << 6) : 0;
dispc_write_reg(at_reg[plane], l);
return 0;
}
......@@ -440,16 +534,9 @@ static int omap_dispc_enable_plane(int plane, int enable)
const u32 at_reg[] = { DISPC_GFX_ATTRIBUTES,
DISPC_VID1_BASE + DISPC_VID_ATTRIBUTES,
DISPC_VID2_BASE + DISPC_VID_ATTRIBUTES };
DBGENTER(2);
if ((unsigned int)plane > 2)
if ((unsigned int)plane > dispc.mem_desc.region_cnt)
return -EINVAL;
MOD_REG_FLD(at_reg[plane], 1, enable ? 1 : 0);
if (plane == dispc.multiplane_head) {
if (++plane > 2)
plane = OMAPFB_PLANE_GFX;
MOD_REG_FLD(at_reg[plane], 1, enable ? 1 : 0);
}
return 0;
}
......@@ -492,6 +579,14 @@ static int omap_dispc_set_color_key(struct omapfb_color_key *ck)
dispc_write_reg(tr_reg, ck->trans_key);
dispc_write_reg(df_reg, ck->background);
dispc.color_key = *ck;
return 0;
}
static int omap_dispc_get_color_key(struct omapfb_color_key *ck)
{
*ck = dispc.color_key;
return 0;
}
......@@ -503,8 +598,6 @@ static int omap_dispc_set_update_mode(enum omapfb_update_mode mode)
{
int r = 0;
DBGENTER(1);
if (mode != dispc.update_mode) {
switch (mode) {
case OMAPFB_AUTO_UPDATE:
......@@ -517,7 +610,8 @@ static int omap_dispc_set_update_mode(enum omapfb_update_mode mode)
omap_dispc_enable_lcd_out(0);
if (!wait_for_completion_timeout(&dispc.frame_done,
msecs_to_jiffies(500))) {
pr_err("timeout waiting for FRAME DONE\n");
dev_err(dispc.fbdev->dev,
"timeout waiting for FRAME DONE\n");
}
dispc.update_mode = mode;
break;
......@@ -526,16 +620,62 @@ static int omap_dispc_set_update_mode(enum omapfb_update_mode mode)
}
}
DBGLEAVE(1);
return r;
}
static unsigned long omap_dispc_get_caps(void)
{
return 0;
}
static enum omapfb_update_mode omap_dispc_get_update_mode(void)
{
return dispc.update_mode;
}
static void setup_color_conv_coef(void)
{
u32 mask = FLD_MASK(16, 11) | FLD_MASK(0, 11);
int cf1_reg = DISPC_VID1_BASE + DISPC_VID_CONV_COEF0;
int cf2_reg = DISPC_VID2_BASE + DISPC_VID_CONV_COEF0;
int at1_reg = DISPC_VID1_BASE + DISPC_VID_ATTRIBUTES;
int at2_reg = DISPC_VID2_BASE + DISPC_VID_ATTRIBUTES;
const struct color_conv_coef {
int ry, rcr, rcb, gy, gcr, gcb, by, bcr, bcb;
int full_range;
} ctbl_bt601_5 = {
298, 409, 0, 298, -208, -100, 298, 0, 517, 0,
};
#if 0
const struct color_conv_coef ctbl_bt601_5_full = {
256, 351, 0, 256, -179, -86, 256, 0, 443, 1,
}, ctbl_bt709 = {
298, 459, 0, 298, -137, -55, 298, 0, 541, 0,
}, ctbl_bt709_f = {
256, 394, 0, 256, -118, -47, 256, 0, 465, 1, },
#endif
const struct color_conv_coef *ct;
#define CVAL(x, y) (((x & 2047) << 16) | (y & 2047))
ct = &ctbl_bt601_5;
MOD_REG_FLD(cf1_reg, mask, CVAL(ct->rcr, ct->ry));
MOD_REG_FLD(cf1_reg + 4, mask, CVAL(ct->gy, ct->rcb));
MOD_REG_FLD(cf1_reg + 8, mask, CVAL(ct->gcb, ct->gcr));
MOD_REG_FLD(cf1_reg + 12, mask, CVAL(ct->bcr, ct->by));
MOD_REG_FLD(cf1_reg + 16, mask, CVAL(0, ct->bcb));
MOD_REG_FLD(cf2_reg, mask, CVAL(ct->rcr, ct->ry));
MOD_REG_FLD(cf2_reg + 4, mask, CVAL(ct->gy, ct->rcb));
MOD_REG_FLD(cf2_reg + 8, mask, CVAL(ct->gcb, ct->gcr));
MOD_REG_FLD(cf2_reg + 12, mask, CVAL(ct->bcr, ct->by));
MOD_REG_FLD(cf2_reg + 16, mask, CVAL(0, ct->bcb));
#undef CVAL
MOD_REG_FLD(at1_reg, (1 << 11), ct->full_range);
MOD_REG_FLD(at2_reg, (1 << 11), ct->full_range);
}
static void calc_ck_div(int is_tft, int pck, int *lck_div, int *pck_div)
{
unsigned long fck, lck;
......@@ -556,8 +696,7 @@ static void calc_ck_div(int is_tft, int pck, int *lck_div, int *pck_div)
BUG_ON(*lck_div < 1);
if (*lck_div > 255) {
*lck_div = 255;
printk(KERN_WARNING
MODULE_NAME ": pixclock %d kHz too low.\n",
dev_warn(dispc.fbdev->dev, "pixclock %d kHz too low.\n",
pck / 1000);
}
}
......@@ -579,8 +718,6 @@ static void set_lcd_timings(void)
int is_tft = panel->config & OMAP_LCDC_PANEL_TFT;
unsigned long fck;
DBGENTER(1);
l = dispc_read_reg(DISPC_TIMING_H);
l &= ~(FLD_MASK(0, 6) | FLD_MASK(8, 8) | FLD_MASK(20, 8));
l |= ( max(1, (min(64, panel->hsw))) - 1 ) << 0;
......@@ -659,16 +796,15 @@ static irqreturn_t omap_dispc_irq_handler(int irq, void *dev, struct pt_regs *re
u32 stat = dispc_read_reg(DISPC_IRQSTATUS);
static int jabber;
DBGENTER(2);
if (stat & DISPC_IRQ_FRAMEMASK)
complete(&dispc.frame_done);
if (stat & DISPC_IRQ_MASK_ERROR) {
if (jabber++ < 5) {
pr_err("irq error status %04x\n", stat & 0x7fff);
dev_err(dispc.fbdev->dev, "irq error status %04x\n",
stat & 0x7fff);
} else {
pr_err("disable irq\n");
dev_err(dispc.fbdev->dev, "disable irq\n");
dispc_write_reg(DISPC_IRQENABLE, 0);
}
}
......@@ -684,19 +820,19 @@ static irqreturn_t omap_dispc_irq_handler(int irq, void *dev, struct pt_regs *re
static int get_dss_clocks(void)
{
if (IS_ERR((dispc.dss_ick = clk_get(dispc.fbdev->dev, "dss_ick")))) {
pr_err("can't get dss_ick");
dev_err(dispc.fbdev->dev, "can't get dss_ick");
return PTR_ERR(dispc.dss_ick);
}
if (IS_ERR((dispc.dss1_fck = clk_get(dispc.fbdev->dev, "dss1_fck")))) {
pr_err("can't get dss1_fck");
dev_err(dispc.fbdev->dev, "can't get dss1_fck");
clk_put(dispc.dss_ick);
return PTR_ERR(dispc.dss1_fck);
}
if (IS_ERR((dispc.dss_54m_fck =
clk_get(dispc.fbdev->dev, "dss_54m_fck")))) {
pr_err("can't get dss_54m_fck");
dev_err(dispc.fbdev->dev, "can't get dss_54m_fck");
clk_put(dispc.dss_ick);
clk_put(dispc.dss1_fck);
return PTR_ERR(dispc.dss_54m_fck);
......@@ -733,199 +869,69 @@ static void enable_digit_clocks(int enable)
static void omap_dispc_suspend(void)
{
DBGENTER(1);
if (dispc.update_mode == OMAPFB_AUTO_UPDATE) {
init_completion(&dispc.frame_done);
omap_dispc_enable_lcd_out(0);
if (!wait_for_completion_timeout(&dispc.frame_done,
msecs_to_jiffies(500))) {
pr_err("timeout waiting for FRAME DONE\n");
dev_err(dispc.fbdev->dev,
"timeout waiting for FRAME DONE\n");
}
enable_lcd_clocks(0);
}
DBGLEAVE(1);
}
static void omap_dispc_resume(void)
{
DBGENTER(1);
if (dispc.update_mode == OMAPFB_AUTO_UPDATE) {
enable_lcd_clocks(1);
set_lcd_timings();
load_palette();
omap_dispc_enable_lcd_out(1);
}
DBGLEAVE(1);
}
static int omap_dispc_update_window(struct omapfb_update_window *win,
static int omap_dispc_update_window(struct fb_info *fbi,
struct omapfb_update_window *win,
void (*complete_callback)(void *arg),
void *complete_callback_data)
{
return dispc.update_mode == OMAPFB_UPDATE_DISABLED ? -ENODEV : 0;
}
/* Greatest common divisor */
static int calc_gcd(int a, int b)
{
int tmp;
if (a < b) {
tmp = a;
a = b;
b = tmp;
}
for (;;) {
tmp = a % b;
if (tmp != 0) {
a = b;
b = tmp;
} else
break;
}
return b;
}
/* Least common multiple */
static int calc_lcm(int a, int b)
{
return a * b / calc_gcd(a, b);
}
static void omap_dispc_get_vram_layout(unsigned long *size, void **virt,
dma_addr_t *phys)
{
*size = dispc.fb_sram_size + dispc.fb_sdram_size;
*virt = dispc.fb_kern_vaddr;
/* Physical vram might not be contiguous. No one except own mmap
* should use this addr.
*/
*phys = 0;
}
static int omap_dispc_mmap_user(struct vm_area_struct *vma)
{
unsigned long len;
unsigned long offset;
unsigned long vaddr;
int r;
DBGPRINT(1, "vm_pgoff 0x%08lx vm_start 0x%08lx vm_end 0x%08lx\n",
vma->vm_pgoff, vma->vm_start, vma->vm_end);
if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
return -EINVAL;
offset = vma->vm_pgoff << PAGE_SHIFT;
if (offset >= dispc.fb_sram_size + dispc.fb_sdram_size)
return -EINVAL;
len = vma->vm_end - vma->vm_start;
if (offset + len > dispc.fb_sram_size + dispc.fb_sdram_size)
return -EINVAL;
vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
vma->vm_flags |= VM_PFNMAP;
vaddr = vma->vm_start;
if (dispc.fb_sram_size) {
if (offset < dispc.fb_sram_size) {
int chunk = min_t(int, dispc.fb_sram_size - offset, len);
DBGPRINT(1, "map sram va %08lx pa %08lx size %d\n",
vaddr, dispc.fb_sram_paddr + offset, chunk);
r = io_remap_pfn_range(vma, vaddr,
(dispc.fb_sram_paddr +
offset) >> PAGE_SHIFT, chunk,
vma->vm_page_prot);
if (r == -EINVAL)
return r;
if (r < 0)
return -EAGAIN;
vaddr += chunk;
len -= chunk;
offset = 0;
} else
offset -= dispc.fb_sram_size;
}
if (len) {
DBGPRINT(1, "map sdram va %08lx pa %08lx size %ld\n",
vaddr, dispc.fb_sdram_paddr + offset, len);
BUG_ON(offset > dispc.fb_sdram_size ||
offset + len > dispc.fb_sdram_size ||
vma->vm_end - vaddr != len);
r = io_remap_pfn_range(vma, vaddr, (dispc.fb_sdram_paddr +
offset) >> PAGE_SHIFT, len,
vma->vm_page_prot);
/* no teardown of the previous mapping here.
* do_mmap_pgoff will take core of that. */
if (r == -EINVAL)
return r;
if (r < 0)
return -EAGAIN;
}
return 0;
}
static int mmap_kern(void)
static int mmap_kern(struct omapfb_mem_region *region)
{
struct vm_struct *kvma;
struct vm_area_struct vma;
pgprot_t pgprot;
unsigned long vaddr;
DBGENTER(1);
kvma = get_vm_area(dispc.fb_sram_size + dispc.fb_sdram_size, VM_IOREMAP);
kvma = get_vm_area(region->size, VM_IOREMAP);
if (kvma == NULL) {
pr_err("can't get kernel vm area\n");
dev_err(dispc.fbdev->dev, "can't get kernel vm area\n");
return -ENOMEM;
}
vma.vm_mm = &init_mm;
dispc.fb_kern_vaddr = kvma->addr;
vaddr = (unsigned long)kvma->addr;
pgprot = pgprot_writecombine(pgprot_kernel);
if (dispc.fb_sram_size) {
vma.vm_start = vaddr;
vma.vm_end = vaddr + dispc.fb_sram_size;
if (io_remap_pfn_range(&vma, vaddr,
dispc.fb_sram_paddr >> PAGE_SHIFT,
dispc.fb_sram_size, pgprot) < 0) {
pr_err("kernel mmap for FBMEM failed\n");
vma.vm_end = vaddr + region->size;
if (io_remap_pfn_range(&vma, vaddr, region->paddr >> PAGE_SHIFT,
region->size, pgprot) < 0) {
dev_err(dispc.fbdev->dev, "kernel mmap for FBMEM failed\n");
return -EAGAIN;
}
vaddr += dispc.fb_sram_size;
}
if (dispc.fb_sdram_size) {
vma.vm_start = vaddr;
vma.vm_end = vaddr + dispc.fb_sdram_size;
if (io_remap_pfn_range(&vma, vaddr,
dispc.fb_sdram_paddr >> PAGE_SHIFT,
dispc.fb_sdram_size, pgprot) < 0) {
pr_err("kernel mmap for FBMEM failed\n");
return -EAGAIN;
}
}
DBGLEAVE(1);
region->vaddr = (void *)vaddr;
return 0;
}
static void unmap_kern(void)
static void unmap_kern(struct omapfb_mem_region *region)
{
vunmap(dispc.fb_kern_vaddr);
vunmap(region->vaddr);
}
static int alloc_palette_ram(void)
......@@ -933,7 +939,7 @@ static int alloc_palette_ram(void)
dispc.palette_vaddr = dma_alloc_writecombine(dispc.fbdev->dev,
MAX_PALETTE_SIZE, &dispc.palette_paddr, GFP_KERNEL);
if (dispc.palette_vaddr == NULL) {
pr_err("failed to alloc palette memory\n");
dev_err(dispc.fbdev->dev, "failed to alloc palette memory\n");
return -ENOMEM;
}
......@@ -946,107 +952,76 @@ static void free_palette_ram(void)
dispc.palette_vaddr, dispc.palette_paddr);
}
static int alloc_fbmem(int req_size)
static int alloc_fbmem(struct omapfb_mem_region *region)
{
int frame_size;
struct lcd_panel *panel = dispc.fbdev->panel;
frame_size = PAGE_ALIGN(panel->x_res * panel->bpp / 8 * panel->y_res);
if (req_size > frame_size)
frame_size = req_size;
dispc.fb_sdram_size = PAGE_ALIGN(MAX_PALETTE_SIZE) + frame_size;
dispc.fb_kern_vaddr = dma_alloc_writecombine(dispc.fbdev->dev,
dispc.fb_sdram_size, &dispc.fb_sdram_paddr, GFP_KERNEL);
region->vaddr = dma_alloc_writecombine(dispc.fbdev->dev,
region->size, &region->paddr, GFP_KERNEL);
if (dispc.fb_kern_vaddr == 0) {
pr_err("unable to allocate fb DMA memory\n");
if (region->vaddr == NULL) {
dev_err(dispc.fbdev->dev, "unable to allocate FB DMA memory\n");
return -ENOMEM;
}
return 0;
}
static void free_fbmem(void)
static void free_fbmem(struct omapfb_mem_region *region)
{
dma_free_writecombine(dispc.fbdev->dev, dispc.fb_sdram_size,
dispc.fb_kern_vaddr, dispc.fb_sdram_paddr);
dma_free_writecombine(dispc.fbdev->dev, region->size,
region->vaddr, region->paddr);
}
static int setup_fbmem(int req_size)
static int setup_fbmem(struct omapfb_mem_desc *req_md)
{
struct lcd_panel *panel = dispc.fbdev->panel;
struct omapfb_platform_data *conf;
unsigned long size_align;
int line_size;
int frame_size;
int lines;
struct omapfb_mem_region *rg;
int i;
int r;
conf = dispc.fbdev->dev->platform_data;
if (conf->fbmem.fb_sram_size + conf->fbmem.fb_sdram_size == 0) {
if ((r = alloc_fbmem(req_size)) < 0)
return r;
dispc.fbmem_allocated = 1;
dispc.fb_sdram_lines = panel->y_res;
return 0;
if (!req_md->region_cnt) {
dev_err(dispc.fbdev->dev, "no memory regions defined\n");
return -ENOENT;
}
dispc.fb_sram_paddr = conf->fbmem.fb_sram_start;
dispc.fb_sram_size = conf->fbmem.fb_sram_size;
dispc.fb_sdram_paddr = conf->fbmem.fb_sdram_start;
dispc.fb_sdram_size = conf->fbmem.fb_sdram_size;
line_size = panel->x_res * panel->bpp / 8;
frame_size = PAGE_ALIGN(line_size * panel->y_res);
rg = &req_md->region[0];
size_align = calc_lcm(line_size, PAGE_SIZE);
if (dispc.fb_sram_size + dispc.fb_sdram_size < frame_size ||
(dispc.fb_sdram_size && (dispc.fb_sram_size % size_align))) {
pr_err("Invalid FB memory configuration\n");
return -EINVAL;
for (i = 0; i < req_md->region_cnt; i++, rg++) {
if (rg->paddr) {
rg->alloc = 0;
if ((r = mmap_kern(rg)) < 0)
return r;
} else {
rg->alloc = 1;
if ((r = alloc_fbmem(rg)) < 0)
return r;
}
if (dispc.fb_sram_size + dispc.fb_sdram_size < req_size) {
pr_err("%d vram was requested, but only %u is available\n",
req_size, dispc.fb_sram_size + dispc.fb_sdram_size);
}
lines = dispc.fb_sram_size / line_size;
lines = min_t(int, panel->y_res, lines);
dispc.fb_sram_lines = lines;
lines = panel->y_res - lines;
dispc.fb_sdram_lines = lines;
if ((r = mmap_kern()) < 0)
return r;
DBGPRINT(1, "fb_sram %08x size %08x fb_sdram %08x size %08x\n",
dispc.fb_sram_paddr, dispc.fb_sram_size,
dispc.fb_sdram_paddr, dispc.fb_sdram_size);
dispc.mem_desc = *req_md;
return 0;
}
static void cleanup_fbmem(void)
{
if (dispc.fbmem_allocated)
free_fbmem();
int i;
for (i = 0; i < dispc.mem_desc.region_cnt; i++) {
if (dispc.mem_desc.region[i].alloc)
free_fbmem(&dispc.mem_desc.region[i]);
else
unmap_kern();
unmap_kern(&dispc.mem_desc.region[i]);
}
}
static int omap_dispc_init(struct omapfb_device *fbdev, int ext_mode,
int req_vram_size)
struct omapfb_mem_desc *req_vram)
{
int r;
u32 l;
struct lcd_panel *panel = fbdev->panel;
int tmo = 10000;
int skip_init = 0;
DBGENTER(1);
int i;
memset(&dispc, 0, sizeof(dispc));
......@@ -1054,13 +1029,6 @@ static int omap_dispc_init(struct omapfb_device *fbdev, int ext_mode,
dispc.fbdev = fbdev;
dispc.ext_mode = ext_mode;
dispc.multiplane_head = -1;
if (fbdev->dev->platform_data == NULL) {
pr_err("missing FB configuration\n");
return -ENOENT;
}
init_completion(&dispc.frame_done);
if ((r = get_dss_clocks()) < 0)
......@@ -1068,14 +1036,11 @@ static int omap_dispc_init(struct omapfb_device *fbdev, int ext_mode,
enable_lcd_clocks(1);
l = dispc_read_reg(DISPC_REVISION);
pr_info(MODULE_NAME ": version %d.%d\n", l >> 4 & 0x0f, l & 0x0f);
#ifdef CONFIG_FB_OMAP_BOOTLOADER_INIT
l = dispc_read_reg(DISPC_CONTROL);
/* LCD enabled ? */
if (l & 1) {
pr_info(MODULE_NAME ": skipping hardware initialization\n");
pr_info("omapfb: skipping hardware initialization\n");
skip_init = 1;
}
#endif
......@@ -1089,7 +1054,7 @@ static int omap_dispc_init(struct omapfb_device *fbdev, int ext_mode,
while (!(dispc_read_reg(DISPC_SYSSTATUS) & 1)) {
if (!--tmo) {
pr_err("soft reset failed\n");
dev_err(dispc.fbdev->dev, "soft reset failed\n");
r = -ENODEV;
enable_digit_clocks(0);
goto fail1;
......@@ -1106,8 +1071,8 @@ static int omap_dispc_init(struct omapfb_device *fbdev, int ext_mode,
omap_dispc_enable_irqs(DISPC_IRQ_FRAMEMASK);
if ((r = request_irq(INT_24XX_DSS_IRQ, omap_dispc_irq_handler,
0, MODULE_NAME, NULL)) < 0) {
pr_err("can't get DSS IRQ\n");
0, MODULE_NAME, fbdev)) < 0) {
dev_err(dispc.fbdev->dev, "can't get DSS IRQ\n");
goto fail1;
}
......@@ -1117,12 +1082,14 @@ static int omap_dispc_init(struct omapfb_device *fbdev, int ext_mode,
if ((r = alloc_palette_ram()) < 0)
goto fail2;
if ((r = setup_fbmem(req_vram_size)) < 0)
if ((r = setup_fbmem(req_vram)) < 0)
goto fail3;
if (!skip_init) {
memset(dispc.fb_kern_vaddr, 0,
dispc.fb_sram_size + dispc.fb_sdram_size);
for (i = 0; i < dispc.mem_desc.region_cnt; i++) {
memset(dispc.mem_desc.region[i].vaddr, 0,
dispc.mem_desc.region[i].size);
}
/* Set logic clock to fck, pixel clock to fck/2 for now */
MOD_REG_FLD(DISPC_DIVISOR, FLD_MASK(16, 8), 1 << 16);
......@@ -1132,22 +1099,29 @@ static int omap_dispc_init(struct omapfb_device *fbdev, int ext_mode,
setup_plane_fifo(1);
setup_plane_fifo(2);
setup_color_conv_coef();
set_lcd_tft_mode(panel->config & OMAP_LCDC_PANEL_TFT);
set_lcd_data_lines(panel->data_lines);
set_load_mode(DISPC_LOAD_FRAME_ONLY);
if (!ext_mode) {
set_lcd_data_lines(panel->data_lines);
omap_dispc_set_lcd_size(panel->x_res, panel->y_res);
set_lcd_timings();
}
} else
set_lcd_data_lines(panel->bpp);
enable_rfbi_mode(ext_mode);
}
l = dispc_read_reg(DISPC_REVISION);
pr_info("omapfb: DISPC version %d.%d initialized\n",
l >> 4 & 0x0f, l & 0x0f);
return 0;
fail3:
free_palette_ram();
fail2:
free_irq(INT_24XX_DSS_IRQ, NULL);
free_irq(INT_24XX_DSS_IRQ, fbdev);
fail1:
enable_lcd_clocks(0);
put_dss_clocks();
......@@ -1164,17 +1138,10 @@ static void omap_dispc_cleanup(void)
put_dss_clocks();
}
static unsigned long omap_dispc_get_caps(void)
{
return 0;
}
struct lcd_ctrl omap2_int_ctrl = {
const struct lcd_ctrl omap2_int_ctrl = {
.name = "internal",
.init = omap_dispc_init,
.cleanup = omap_dispc_cleanup,
.get_vram_layout = omap_dispc_get_vram_layout,
.mmap = omap_dispc_mmap_user,
.get_caps = omap_dispc_get_caps,
.set_update_mode = omap_dispc_set_update_mode,
.get_update_mode = omap_dispc_get_update_mode,
......@@ -1182,9 +1149,8 @@ struct lcd_ctrl omap2_int_ctrl = {
.suspend = omap_dispc_suspend,
.resume = omap_dispc_resume,
.setup_plane = omap_dispc_setup_plane,
.set_scale = omap_dispc_set_scale,
.enable_plane = omap_dispc_enable_plane,
.set_color_key = omap_dispc_set_color_key,
.get_color_key = omap_dispc_get_color_key,
};
MODULE_DESCRIPTION("TI OMAP LCDC controller");
MODULE_LICENSE("GPL");
......@@ -32,11 +32,7 @@
#include <asm/arch/dma.h>
#include <asm/arch/omapfb.h>
/* #define OMAPFB_DBG 1 */
#include "debug.h"
#define MODULE_NAME "omapfb-hwa742"
#define MODULE_NAME "hwa742"
#define HWA742_REV_CODE_REG 0x0
#define HWA742_CONFIG_REG 0x2
......@@ -80,23 +76,21 @@
#define HWA742_AUTO_UPDATE_TIME (HZ / 20)
#define pr_err(fmt, args...) printk(KERN_ERR MODULE_NAME ": " fmt, ## args)
/* Reserve 4 request slots for requests in irq context */
#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;
......@@ -111,7 +105,7 @@ struct hwa742_request {
} par;
};
struct hwa742_struct {
struct {
enum omapfb_update_mode update_mode;
enum omapfb_update_mode update_mode_before_suspend;
......@@ -140,6 +134,8 @@ struct hwa742_struct {
struct lcd_ctrl *int_ctrl;
} hwa742;
struct lcd_ctrl hwa742_ctrl;
static u8 hwa742_read_reg(u8 reg)
{
u8 data;
......@@ -186,10 +182,14 @@ static void set_format_regs(int conv, int transl, int flags)
{
if (flags & OMAPFB_FORMAT_FLAG_DOUBLE) {
hwa742.window_type = ((hwa742.window_type & 0xfc) | 0x01);
DBGPRINT(2, "hwa742: enabled pixel doubling\n");
#ifdef VERBOSE
dev_dbg(hwa742.fbdev->dev, "hwa742: enabled pixel doubling\n");
#endif
} else {
hwa742.window_type = (hwa742.window_type & 0xfc);
DBGPRINT(2, "hwa742: disabled pixel doubling\n");
#ifdef VERBOSE
dev_dbg(hwa742.fbdev->dev, "hwa742: disabled pixel doubling\n");
#endif
}
hwa742_write_reg(HWA742_INPUT_MODE_REG, conv);
......@@ -239,8 +239,6 @@ static void process_pending_requests(void)
{
unsigned long flags;
DBGENTER(2);
spin_lock_irqsave(&hwa742.req_lock, flags);
while (!list_empty(&hwa742.pending_req_list)) {
......@@ -266,8 +264,6 @@ static void process_pending_requests(void)
}
spin_unlock_irqrestore(&hwa742.req_lock, flags);
DBGLEAVE(2);
}
static void submit_req_list(struct list_head *head)
......@@ -275,8 +271,6 @@ static void submit_req_list(struct list_head *head)
unsigned long flags;
int process = 1;
DBGENTER(2);
spin_lock_irqsave(&hwa742.req_lock, flags);
if (likely(!list_empty(&hwa742.pending_req_list)))
process = 0;
......@@ -285,8 +279,6 @@ static void submit_req_list(struct list_head *head)
if (process)
process_pending_requests();
DBGLEAVE(2);
}
static void request_complete(void *data)
......@@ -320,8 +312,11 @@ static int send_frame_handler(struct hwa742_request *req)
int flags = par->flags;
int scr_width = 800;
DBGPRINT(2, "x %d y %d w %d h %d scr_width %d color_mode %d flags %d\n",
#ifdef VERBOSE
dev_dbg(hwa742.fbdev->dev, "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);
#endif
switch (color_mode) {
case OMAPFB_COLOR_YUV422:
......@@ -425,13 +420,9 @@ static void create_req_list(struct omapfb_update_window *win,
static void auto_update_complete(void *data)
{
DBGENTER(2);
if (!hwa742.stop_auto_update)
mod_timer(&hwa742.auto_update_timer,
jiffies + HWA742_AUTO_UPDATE_TIME);
DBGLEAVE(2);
}
static void hwa742_update_window_auto(unsigned long arg)
......@@ -439,8 +430,6 @@ static void hwa742_update_window_auto(unsigned long arg)
LIST_HEAD(req_list);
struct hwa742_request *last;
DBGENTER(2);
create_req_list(&hwa742.auto_update_window, &req_list);
last = list_entry(req_list.prev, struct hwa742_request, entry);
......@@ -448,11 +437,10 @@ static void hwa742_update_window_auto(unsigned long arg)
last->complete_data = NULL;
submit_req_list(&req_list);
DBGLEAVE(2);
}
int hwa742_update_window_async(struct omapfb_update_window *win,
int hwa742_update_window_async(struct fb_info *fbi,
struct omapfb_update_window *win,
void (*complete_callback)(void *arg),
void *complete_callback_data)
{
......@@ -460,15 +448,13 @@ int hwa742_update_window_async(struct omapfb_update_window *win,
struct hwa742_request *last;
int r = 0;
DBGENTER(2);
if (hwa742.update_mode != OMAPFB_MANUAL_UPDATE) {
DBGPRINT(1, "invalid update mode\n");
dev_dbg(hwa742.fbdev->dev, "invalid update mode\n");
r = -EINVAL;
goto out;
}
if (unlikely(win->format & ~(0x03 | OMAPFB_FORMAT_FLAG_DOUBLE))) {
DBGPRINT(1, "invalid window flag");
dev_dbg(hwa742.fbdev->dev, "invalid window flag");
r = -EINVAL;
goto out;
}
......@@ -482,7 +468,6 @@ int hwa742_update_window_async(struct omapfb_update_window *win,
submit_req_list(&req_list);
out:
DBGLEAVE(2);
return r;
}
EXPORT_SYMBOL(hwa742_update_window_async);
......@@ -521,8 +506,6 @@ static void hwa742_sync(void)
struct hwa742_request *req;
struct completion comp;
DBGENTER(2);
req = alloc_req();
req->handler = sync_handler;
......@@ -534,13 +517,11 @@ static void hwa742_sync(void)
submit_req_list(&req_list);
wait_for_completion(&comp);
DBGLEAVE(2);
}
static void hwa742_bind_client(struct omapfb_notifier_block *nb)
{
DBGPRINT(1, "update_mode %d\n", hwa742.update_mode);
dev_dbg(hwa742.fbdev->dev, "update_mode %d\n", hwa742.update_mode);
if (hwa742.update_mode == OMAPFB_MANUAL_UPDATE) {
omapfb_notify_clients(hwa742.fbdev, OMAPFB_EVENT_READY);
}
......@@ -548,20 +529,14 @@ static void hwa742_bind_client(struct omapfb_notifier_block *nb)
static int hwa742_set_update_mode(enum omapfb_update_mode mode)
{
int r = 0;
DBGENTER(1);
if (mode != OMAPFB_MANUAL_UPDATE && mode != OMAPFB_AUTO_UPDATE &&
mode != OMAPFB_UPDATE_DISABLED) {
r = -EINVAL;
goto out;
}
mode != OMAPFB_UPDATE_DISABLED)
return -EINVAL;
if (mode == hwa742.update_mode)
goto out;
return 0;
printk(KERN_INFO "hwa742: setting update mode to %s\n",
pr_info("omapfb: hwa742: setting update mode to %s\n",
mode == OMAPFB_UPDATE_DISABLED ? "disabled" :
(mode == OMAPFB_AUTO_UPDATE ? "auto" : "manual"));
......@@ -591,10 +566,8 @@ static int hwa742_set_update_mode(enum omapfb_update_mode mode)
case OMAPFB_UPDATE_DISABLED:
break;
}
out:
DBGLEAVE(1);
return r;
return 0;
}
static enum omapfb_update_mode hwa742_get_update_mode(void)
......@@ -622,7 +595,7 @@ static int calc_reg_timing(unsigned long sysclk, int div)
* WriteCycle = 2*SYSCLK + 2 ns,
* CSPulseWidth = 10 ns */
systim = 1000000000 / (sysclk / 1000);
DBGPRINT(1, "HWA742 systim %lu ps extif_clk_period %u ps"
dev_dbg(hwa742.fbdev->dev, "HWA742 systim %lu ps extif_clk_period %u ps"
"extif_clk_div %d\n", systim, hwa742.extif_clk_period, div);
t = &hwa742.reg_timings;
......@@ -643,12 +616,12 @@ static int calc_reg_timing(unsigned long sysclk, int div)
t->re_cycle_time = t->re_off_time;
t->cs_pulse_width = 0;
DBGPRINT(1, "[reg]cson %d csoff %d reon %d reoff %d\n",
dev_dbg(hwa742.fbdev->dev, "[reg]cson %d csoff %d reon %d reoff %d\n",
t->cs_on_time, t->cs_off_time, t->re_on_time, t->re_off_time);
DBGPRINT(1, "[reg]weon %d weoff %d recyc %d wecyc %d\n",
dev_dbg(hwa742.fbdev->dev, "[reg]weon %d weoff %d recyc %d wecyc %d\n",
t->we_on_time, t->we_off_time, t->re_cycle_time,
t->we_cycle_time);
DBGPRINT(1, "[reg]rdaccess %d cspulse %d\n",
dev_dbg(hwa742.fbdev->dev, "[reg]rdaccess %d cspulse %d\n",
t->access_time, t->cs_pulse_width);
return hwa742.extif->convert_timings(t);
......@@ -669,7 +642,7 @@ static int calc_lut_timing(unsigned long sysclk, int div)
* CSPulseWidth = 10 ns
*/
systim = 1000000000 / (sysclk / 1000);
DBGPRINT(1, "HWA742 systim %lu ps extif_clk_period %u ps"
dev_dbg(hwa742.fbdev->dev, "HWA742 systim %lu ps extif_clk_period %u ps"
"extif_clk_div %d\n", systim, hwa742.extif_clk_period, div);
t = &hwa742.lut_timings;
......@@ -694,12 +667,12 @@ static int calc_lut_timing(unsigned long sysclk, int div)
t->re_cycle_time = t->re_off_time;
t->cs_pulse_width = 0;
DBGPRINT(1, "[lut]cson %d csoff %d reon %d reoff %d\n",
dev_dbg(hwa742.fbdev->dev, "[lut]cson %d csoff %d reon %d reoff %d\n",
t->cs_on_time, t->cs_off_time, t->re_on_time, t->re_off_time);
DBGPRINT(1, "[lut]weon %d weoff %d recyc %d wecyc %d\n",
dev_dbg(hwa742.fbdev->dev, "[lut]weon %d weoff %d recyc %d wecyc %d\n",
t->we_on_time, t->we_off_time, t->re_cycle_time,
t->we_cycle_time);
DBGPRINT(1, "[lut]rdaccess %d cspulse %d\n",
dev_dbg(hwa742.fbdev->dev, "[lut]rdaccess %d cspulse %d\n",
t->access_time, t->cs_pulse_width);
return hwa742.extif->convert_timings(t);
......@@ -727,7 +700,7 @@ static int calc_extif_timings(unsigned long sysclk)
return 0;
err:
pr_err("can't setup timings\n");
dev_err(hwa742.fbdev->dev, "can't setup timings\n");
return -1;
}
......@@ -748,7 +721,7 @@ static void hwa742_suspend(void)
static void hwa742_resume(void)
{
if (clk_enable(hwa742.sys_ck) != 0)
pr_err("failed to enable SYS clock\n");
dev_err(hwa742.fbdev->dev, "failed to enable SYS clock\n");
/* Disable sleep mode */
hwa742_write_reg(HWA742_POWER_SAVE, 0);
while (1) {
......@@ -761,25 +734,24 @@ static void hwa742_resume(void)
hwa742_set_update_mode(hwa742.update_mode_before_suspend);
}
struct lcd_ctrl hwa742_ctrl;
static int hwa742_init(struct omapfb_device *fbdev, int ext_mode, int req_vram_size)
static int hwa742_init(struct omapfb_device *fbdev, int ext_mode,
struct omapfb_mem_desc *req_vram)
{
int r = 0, i;
u8 rev, conf;
unsigned long sysfreq;
int div, nd;
DBGENTER(1);
hwa742.fbdev = fbdev;
hwa742.sys_ck = clk_get(0, "bclk");
if (IS_ERR(hwa742.sys_ck)) {
pr_err("can't get SYS clock\n");
dev_err(fbdev->dev, "can't get SYS clock\n");
return PTR_ERR(hwa742.sys_ck);
}
if ((r = clk_enable(hwa742.sys_ck)) != 0) {
pr_err("can't enable SYS clock\n");
dev_err(fbdev->dev, "can't enable SYS clock\n");
clk_put(hwa742.sys_ck);
return r;
}
......@@ -792,15 +764,12 @@ static int hwa742_init(struct omapfb_device *fbdev, int ext_mode, int req_vram_s
spin_lock_init(&hwa742.req_lock);
if ((r = hwa742.int_ctrl->init(fbdev, 1, req_vram_size)) < 0)
if ((r = hwa742.int_ctrl->init(fbdev, 1, req_vram)) < 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;
sysfreq = clk_get_rate(hwa742.sys_ck);
if ((r = calc_extif_timings(sysfreq)) < 0)
goto err3;
......@@ -816,17 +785,14 @@ static int hwa742_init(struct omapfb_device *fbdev, int ext_mode, int req_vram_s
rev = hwa742_read_reg(HWA742_REV_CODE_REG);
if ((rev & 0xfc) != 0x80) {
pr_err("invalid revision %02x\n", rev);
dev_err(fbdev->dev, "invalid revision %02x\n", rev);
r = -ENODEV;
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 & 0x03, conf & 0x07);
if (!(hwa742_read_reg(HWA742_PLL_DIV_REG) & 0x80)) {
pr_err("controller not initialized by the bootloader\n");
dev_err(hwa742.fbdev->dev,
"controller not initialized by the bootloader\n");
r = -ENODEV;
goto err2;
}
......@@ -848,8 +814,6 @@ static int hwa742_init(struct omapfb_device *fbdev, int ext_mode, int req_vram_s
hwa742.prev_color_mode = -1;
hwa742.prev_flags = 0;
hwa742.fbdev = fbdev;
INIT_LIST_HEAD(&hwa742.free_req_list);
INIT_LIST_HEAD(&hwa742.pending_req_list);
for (i = 0; i < ARRAY_SIZE(hwa742.req_pool); i++)
......@@ -857,6 +821,10 @@ static int hwa742_init(struct omapfb_device *fbdev, int ext_mode, int req_vram_s
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("omapfb: hwa742 LCD controller rev. %d "
"initialized (CNF pins %x)\n", rev & 0x03, conf & 0x07);
return 0;
err3:
hwa742.extif->cleanup();
......
......@@ -20,7 +20,6 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/device.h>
......@@ -38,11 +37,7 @@
#include <asm/mach-types.h>
/* #define OMAPFB_DBG 1 */
#include "debug.h"
#define MODULE_NAME "omapfb-lcdc"
#define MODULE_NAME "lcdc"
#define OMAP_LCDC_BASE 0xfffec000
#define OMAP_LCDC_SIZE 256
......@@ -78,8 +73,6 @@
#define MAX_PALETTE_SIZE PAGE_SIZE
#define pr_err(fmt, args...) printk(KERN_ERR MODULE_NAME ": " fmt, ## args)
enum lcdc_load_mode {
OMAP_LCDC_LOAD_PALETTE,
OMAP_LCDC_LOAD_FRAME,
......@@ -115,16 +108,16 @@ static struct omap_lcd_controller {
dma_addr_t vram_phys;
void *vram_virt;
unsigned long vram_size;
} omap_lcdc;
} lcdc;
static void inline enable_irqs(int mask)
{
omap_lcdc.irq_mask |= mask;
lcdc.irq_mask |= mask;
}
static void inline disable_irqs(int mask)
{
omap_lcdc.irq_mask &= ~mask;
lcdc.irq_mask &= ~mask;
}
static void set_load_mode(enum lcdc_load_mode mode)
......@@ -155,7 +148,7 @@ static void enable_controller(void)
l = omap_readl(OMAP_LCDC_CONTROL);
l |= OMAP_LCDC_CTRL_LCD_EN;
l &= ~OMAP_LCDC_IRQ_MASK;
l |= omap_lcdc.irq_mask | OMAP_LCDC_IRQ_DONE; /* enabled IRQs */
l |= lcdc.irq_mask | OMAP_LCDC_IRQ_DONE; /* enabled IRQs */
omap_writel(l, OMAP_LCDC_CONTROL);
}
......@@ -176,11 +169,11 @@ static void disable_controller_async(void)
static void disable_controller(void)
{
init_completion(&omap_lcdc.last_frame_complete);
init_completion(&lcdc.last_frame_complete);
disable_controller_async();
if (!wait_for_completion_timeout(&omap_lcdc.last_frame_complete,
if (!wait_for_completion_timeout(&lcdc.last_frame_complete,
msecs_to_jiffies(500)))
pr_err("timeout waiting for FRAME DONE\n");
dev_err(lcdc.fbdev->dev, "timeout waiting for FRAME DONE\n");
}
static void reset_controller(u32 status)
......@@ -191,7 +184,8 @@ static void reset_controller(u32 status)
disable_controller_async();
reset_count++;
if (reset_count == 1 || time_after(jiffies, last_jiffies + HZ)) {
pr_err("resetting (status %#010x,reset count %lu)\n",
dev_err(lcdc.fbdev->dev,
"resetting (status %#010x,reset count %lu)\n",
status, reset_count);
last_jiffies = jiffies;
}
......@@ -199,12 +193,13 @@ static void reset_controller(u32 status)
enable_controller();
} else {
reset_count = 0;
pr_err("too many reset attempts, giving up.\n");
dev_err(lcdc.fbdev->dev,
"too many reset attempts, giving up.\n");
}
}
/* Configure the LCD DMA according to the current mode specified by parameters
* in omap_lcdc.fbdev and fbdev->var.
* in lcdc.fbdev and fbdev->var.
*/
static void setup_lcd_dma(void)
{
......@@ -215,22 +210,23 @@ static void setup_lcd_dma(void)
0,
OMAP_DMA_DATA_TYPE_S32,
};
struct fb_var_screeninfo *var = &omap_lcdc.fbdev->fb_info->var;
struct omapfb_plane_struct *plane = lcdc.fbdev->fb_info[0]->par;
struct fb_var_screeninfo *var = &lcdc.fbdev->fb_info[0]->var;
unsigned long src;
int esize, xelem, yelem;
src = omap_lcdc.vram_phys + omap_lcdc.frame_offset;
src = lcdc.vram_phys + lcdc.frame_offset;
switch (var->rotate) {
case 0:
if (omap_lcdc.fbdev->mirror || (src & 3) ||
omap_lcdc.color_mode == OMAPFB_COLOR_YUV420 ||
(omap_lcdc.xres & 1))
if (plane->info.mirror || (src & 3) ||
lcdc.color_mode == OMAPFB_COLOR_YUV420 ||
(lcdc.xres & 1))
esize = 2;
else
esize = 4;
xelem = omap_lcdc.xres * omap_lcdc.bpp / 8 / esize;
yelem = omap_lcdc.yres;
xelem = lcdc.xres * lcdc.bpp / 8 / esize;
yelem = lcdc.yres;
break;
case 90:
case 180:
......@@ -239,30 +235,33 @@ static void setup_lcd_dma(void)
BUG();
}
esize = 2;
xelem = omap_lcdc.yres * omap_lcdc.bpp / 16;
yelem = omap_lcdc.xres;
xelem = lcdc.yres * lcdc.bpp / 16;
yelem = lcdc.xres;
break;
default:
BUG();
return;
}
DBGPRINT(2, "setup_dma: src %#010lx esize %d xelem %d yelem %d\n",
#ifdef VERBOSE
dev_dbg(lcdc.fbdev->dev,
"setup_dma: src %#010lx esize %d xelem %d yelem %d\n",
src, esize, xelem, yelem);
#endif
omap_set_lcd_dma_b1(src, xelem, yelem, dma_elem_type[esize]);
if (!cpu_is_omap15xx()) {
int bpp = omap_lcdc.bpp;
int bpp = lcdc.bpp;
/* YUV support is only for external mode when we have the
* YUV window embedded in a 16bpp frame buffer.
*/
if (omap_lcdc.color_mode == OMAPFB_COLOR_YUV420)
if (lcdc.color_mode == OMAPFB_COLOR_YUV420)
bpp = 16;
/* Set virtual xres elem size */
omap_set_lcd_dma_b1_vxres(
omap_lcdc.screen_width * bpp / 8 / esize);
lcdc.screen_width * bpp / 8 / esize);
/* Setup transformations */
omap_set_lcd_dma_b1_rotation(var->rotate);
omap_set_lcd_dma_b1_mirror(omap_lcdc.fbdev->mirror);
omap_set_lcd_dma_b1_mirror(plane->info.mirror);
}
omap_setup_lcd_dma();
}
......@@ -286,11 +285,11 @@ static irqreturn_t lcdc_irq_handler(int irq, void *dev_id, struct pt_regs *fp)
l = omap_readl(OMAP_LCDC_CONTROL);
l &= ~OMAP_LCDC_IRQ_DONE;
omap_writel(l, OMAP_LCDC_CONTROL);
complete(&omap_lcdc.last_frame_complete);
complete(&lcdc.last_frame_complete);
}
if (status & OMAP_LCDC_STAT_LOADED_PALETTE) {
disable_controller_async();
complete(&omap_lcdc.palette_load_complete);
complete(&lcdc.palette_load_complete);
}
}
......@@ -319,12 +318,10 @@ static int omap_lcdc_setup_plane(int plane, int channel_out,
int pos_x, int pos_y, int width, int height,
int color_mode)
{
struct fb_var_screeninfo *var = &omap_lcdc.fbdev->fb_info->var;
struct lcd_panel *panel = omap_lcdc.fbdev->panel;
struct fb_var_screeninfo *var = &lcdc.fbdev->fb_info[0]->var;
struct lcd_panel *panel = lcdc.fbdev->panel;
int rot_x, rot_y;
DBGENTER(2);
if (var->rotate == 0) {
rot_x = panel->x_res;
rot_y = panel->y_res;
......@@ -334,43 +331,45 @@ static int omap_lcdc_setup_plane(int plane, int channel_out,
}
if (plane != 0 || channel_out != 0 || pos_x != 0 || pos_y != 0 ||
width > rot_x || height > rot_y) {
DBGPRINT(1, "invalid plane params plane %d pos_x %d "
"pos_y %d w %d h %d\n", plane, pos_x, pos_y,
width, height);
#ifdef VERBOSE
dev_dbg(lcdc.fbdev->dev,
"invalid plane params plane %d pos_x %d pos_y %d "
"w %d h %d\n", plane, pos_x, pos_y, width, height);
#endif
return -EINVAL;
}
omap_lcdc.frame_offset = offset;
omap_lcdc.xres = width;
omap_lcdc.yres = height;
omap_lcdc.screen_width = screen_width;
omap_lcdc.color_mode = color_mode;
lcdc.frame_offset = offset;
lcdc.xres = width;
lcdc.yres = height;
lcdc.screen_width = screen_width;
lcdc.color_mode = color_mode;
switch (color_mode) {
case OMAPFB_COLOR_CLUT_8BPP:
omap_lcdc.bpp = 8;
omap_lcdc.palette_code = 0x3000;
omap_lcdc.palette_size = 512;
lcdc.bpp = 8;
lcdc.palette_code = 0x3000;
lcdc.palette_size = 512;
break;
case OMAPFB_COLOR_RGB565:
omap_lcdc.bpp = 16;
omap_lcdc.palette_code = 0x4000;
omap_lcdc.palette_size = 32;
lcdc.bpp = 16;
lcdc.palette_code = 0x4000;
lcdc.palette_size = 32;
break;
case OMAPFB_COLOR_RGB444:
omap_lcdc.bpp = 16;
omap_lcdc.palette_code = 0x4000;
omap_lcdc.palette_size = 32;
lcdc.bpp = 16;
lcdc.palette_code = 0x4000;
lcdc.palette_size = 32;
break;
case OMAPFB_COLOR_YUV420:
if (omap_lcdc.ext_mode) {
omap_lcdc.bpp = 12;
if (lcdc.ext_mode) {
lcdc.bpp = 12;
break;
}
/* fallthrough */
case OMAPFB_COLOR_YUV422:
if (omap_lcdc.ext_mode) {
omap_lcdc.bpp = 16;
if (lcdc.ext_mode) {
lcdc.bpp = 16;
break;
}
/* fallthrough */
......@@ -381,32 +380,31 @@ static int omap_lcdc_setup_plane(int plane, int channel_out,
* bpp4: code 0x2000 size 256
* bpp12: code 0x4000 size 32
*/
DBGPRINT(1, "invalid color mode %d\n", color_mode);
dev_dbg(lcdc.fbdev->dev, "invalid color mode %d\n", color_mode);
BUG();
return -1;
}
if (omap_lcdc.ext_mode) {
if (lcdc.ext_mode) {
setup_lcd_dma();
return 0;
}
if (omap_lcdc.update_mode == OMAPFB_AUTO_UPDATE) {
if (lcdc.update_mode == OMAPFB_AUTO_UPDATE) {
disable_controller();
omap_stop_lcd_dma();
setup_lcd_dma();
enable_controller();
}
DBGLEAVE(2);
return 0;
}
static int omap_lcdc_enable_plane(int plane, int enable)
{
DBGPRINT(2, "plane %d enable %d update_mode %d ext_mode %d\n",
plane, enable, omap_lcdc.update_mode,
omap_lcdc.ext_mode);
dev_dbg(lcdc.fbdev->dev,
"plane %d enable %d update_mode %d ext_mode %d\n",
plane, enable, lcdc.update_mode, lcdc.ext_mode);
if (plane != OMAPFB_PLANE_GFX)
return -EINVAL;
......@@ -421,33 +419,29 @@ static void load_palette(void)
{
u16 *palette;
DBGENTER(1);
palette = (u16 *)omap_lcdc.palette_virt;
palette = (u16 *)lcdc.palette_virt;
*(u16 *)palette &= 0x0fff;
*(u16 *)palette |= omap_lcdc.palette_code;
*(u16 *)palette |= lcdc.palette_code;
omap_set_lcd_dma_b1(omap_lcdc.palette_phys,
omap_lcdc.palette_size / 4 + 1, 1, OMAP_DMA_DATA_TYPE_S32);
omap_set_lcd_dma_b1(lcdc.palette_phys,
lcdc.palette_size / 4 + 1, 1, OMAP_DMA_DATA_TYPE_S32);
omap_set_lcd_dma_single_transfer(1);
omap_setup_lcd_dma();
init_completion(&omap_lcdc.palette_load_complete);
init_completion(&lcdc.palette_load_complete);
enable_irqs(OMAP_LCDC_IRQ_LOADED_PALETTE);
set_load_mode(OMAP_LCDC_LOAD_PALETTE);
enable_controller();
if (!wait_for_completion_timeout(&omap_lcdc.palette_load_complete,
if (!wait_for_completion_timeout(&lcdc.palette_load_complete,
msecs_to_jiffies(500)))
pr_err("timeout waiting for FRAME DONE\n");
dev_err(lcdc.fbdev->dev, "timeout waiting for FRAME DONE\n");
/* The controller gets disabled in the irq handler */
disable_irqs(OMAP_LCDC_IRQ_LOADED_PALETTE);
omap_stop_lcd_dma();
omap_set_lcd_dma_single_transfer(omap_lcdc.ext_mode);
DBGLEAVE(1);
omap_set_lcd_dma_single_transfer(lcdc.ext_mode);
}
/* Used only in internal controller mode */
......@@ -456,10 +450,10 @@ static int omap_lcdc_setcolreg(u_int regno, u16 red, u16 green, u16 blue,
{
u16 *palette;
if (omap_lcdc.color_mode != OMAPFB_COLOR_CLUT_8BPP || regno > 255)
if (lcdc.color_mode != OMAPFB_COLOR_CLUT_8BPP || regno > 255)
return -EINVAL;
palette = (u16 *)omap_lcdc.palette_virt;
palette = (u16 *)lcdc.palette_virt;
palette[regno] &= ~0x0fff;
palette[regno] |= ((red >> 12) << 8) | ((green >> 12) << 4 ) |
......@@ -482,7 +476,7 @@ static void calc_ck_div(int is_tft, int pck, int *pck_div)
unsigned long lck;
pck = max(1, pck);
lck = clk_get_rate(omap_lcdc.lcd_ck);
lck = clk_get_rate(lcdc.lcd_ck);
*pck_div = (lck + pck - 1) / pck;
if (is_tft)
*pck_div = max(2, *pck_div);
......@@ -491,7 +485,7 @@ static void calc_ck_div(int is_tft, int pck, int *pck_div)
if (*pck_div > 255) {
/* FIXME: try to adjust logic clock divider as well */
*pck_div = 255;
printk(KERN_WARNING MODULE_NAME ": pixclock %d kHz too low.\n",
dev_warn(lcdc.fbdev->dev, "pixclock %d kHz too low.\n",
pck / 1000);
}
}
......@@ -499,7 +493,7 @@ static void calc_ck_div(int is_tft, int pck, int *pck_div)
static void inline setup_regs(void)
{
u32 l;
struct lcd_panel *panel = omap_lcdc.fbdev->panel;
struct lcd_panel *panel = lcdc.fbdev->panel;
int is_tft = panel->config & OMAP_LCDC_PANEL_TFT;
unsigned long lck;
int pcd;
......@@ -535,14 +529,14 @@ static void inline setup_regs(void)
l = omap_readl(OMAP_LCDC_TIMING2);
l &= ~0xff;
lck = clk_get_rate(omap_lcdc.lcd_ck);
lck = clk_get_rate(lcdc.lcd_ck);
if (!panel->pcd)
calc_ck_div(is_tft, panel->pixel_clock * 1000, &pcd);
else {
printk(KERN_WARNING
MODULE_NAME ": Pixel clock divider value is obsolete.\n"
MODULE_NAME ": Try to set pixel_clock to %lu and pcd to 0 "
dev_warn(lcdc.fbdev->dev,
"Pixel clock divider value is obsolete.\n"
"Try to set pixel_clock to %lu and pcd to 0 "
"in drivers/video/omap/lcd_%s.c and submit a patch.\n",
lck / panel->pcd / 1000, panel->name);
......@@ -564,9 +558,7 @@ static int omap_lcdc_set_update_mode(enum omapfb_update_mode mode)
{
int r = 0;
DBGENTER(1);
if (mode != omap_lcdc.update_mode) {
if (mode != lcdc.update_mode) {
switch (mode) {
case OMAPFB_AUTO_UPDATE:
setup_regs();
......@@ -579,31 +571,30 @@ static int omap_lcdc_set_update_mode(enum omapfb_update_mode mode)
enable_irqs(OMAP_LCDC_IRQ_DONE);
/* This will start the actual DMA transfer */
enable_controller();
omap_lcdc.update_mode = mode;
lcdc.update_mode = mode;
break;
case OMAPFB_UPDATE_DISABLED:
disable_controller();
omap_stop_lcd_dma();
omap_lcdc.update_mode = mode;
lcdc.update_mode = mode;
break;
default:
r = -EINVAL;
}
}
DBGLEAVE(1);
return r;
}
static enum omapfb_update_mode omap_lcdc_get_update_mode(void)
{
return omap_lcdc.update_mode;
return lcdc.update_mode;
}
/* PM code called only in internal controller mode */
static void omap_lcdc_suspend(void)
{
if (omap_lcdc.update_mode == OMAPFB_AUTO_UPDATE) {
if (lcdc.update_mode == OMAPFB_AUTO_UPDATE) {
disable_controller();
omap_stop_lcd_dma();
}
......@@ -611,7 +602,7 @@ static void omap_lcdc_suspend(void)
static void omap_lcdc_resume(void)
{
if (omap_lcdc.update_mode == OMAPFB_AUTO_UPDATE) {
if (lcdc.update_mode == OMAPFB_AUTO_UPDATE) {
setup_regs();
load_palette();
setup_lcd_dma();
......@@ -626,23 +617,15 @@ static unsigned long omap_lcdc_get_caps(void)
return 0;
}
static void omap_lcdc_get_vram_layout(unsigned long *size, void **virt,
dma_addr_t *phys)
{
*size = omap_lcdc.vram_size;
*virt = (u8 *)omap_lcdc.vram_virt;
*phys = omap_lcdc.vram_phys;
}
int omap_lcdc_set_dma_callback(void (*callback)(void *data), void *data)
{
BUG_ON(callback == NULL);
if (omap_lcdc.dma_callback)
if (lcdc.dma_callback)
return -EBUSY;
else {
omap_lcdc.dma_callback = callback;
omap_lcdc.dma_callback_data = data;
lcdc.dma_callback = callback;
lcdc.dma_callback_data = data;
}
return 0;
}
......@@ -650,15 +633,14 @@ EXPORT_SYMBOL(omap_lcdc_set_dma_callback);
void omap_lcdc_free_dma_callback(void)
{
omap_lcdc.dma_callback = NULL;
lcdc.dma_callback = NULL;
}
EXPORT_SYMBOL(omap_lcdc_free_dma_callback);
static void lcdc_dma_handler(u16 status, void *data)
{
DBGENTER(2);
if (omap_lcdc.dma_callback)
omap_lcdc.dma_callback(omap_lcdc.dma_callback_data);
if (lcdc.dma_callback)
lcdc.dma_callback(lcdc.dma_callback_data);
}
static int mmap_kern(void)
......@@ -668,158 +650,141 @@ static int mmap_kern(void)
pgprot_t pgprot;
unsigned long vaddr;
DBGENTER(1);
kvma = get_vm_area(omap_lcdc.vram_size, VM_IOREMAP);
kvma = get_vm_area(lcdc.vram_size, VM_IOREMAP);
if (kvma == NULL) {
pr_err("can't get kernel vm area\n");
dev_err(lcdc.fbdev->dev, "can't get kernel vm area\n");
return -ENOMEM;
}
vma.vm_mm = &init_mm;
vaddr = (unsigned long)kvma->addr;
vma.vm_start = vaddr;
vma.vm_end = vaddr + omap_lcdc.vram_size;
vma.vm_end = vaddr + lcdc.vram_size;
pgprot = pgprot_writecombine(pgprot_kernel);
if (io_remap_pfn_range(&vma, vaddr,
omap_lcdc.vram_phys >> PAGE_SHIFT,
omap_lcdc.vram_size, pgprot) < 0) {
pr_err("kernel mmap for FB memory failed\n");
lcdc.vram_phys >> PAGE_SHIFT,
lcdc.vram_size, pgprot) < 0) {
dev_err(lcdc.fbdev->dev, "kernel mmap for FB memory failed\n");
return -EAGAIN;
}
omap_lcdc.vram_virt = (void *)vaddr;
DBGLEAVE(1);
lcdc.vram_virt = (void *)vaddr;
return 0;
}
static void unmap_kern(void)
{
vunmap(omap_lcdc.vram_virt);
vunmap(lcdc.vram_virt);
}
static int alloc_palette_ram(void)
{
omap_lcdc.palette_virt = dma_alloc_writecombine(omap_lcdc.fbdev->dev,
MAX_PALETTE_SIZE, &omap_lcdc.palette_phys, GFP_KERNEL);
if (omap_lcdc.palette_virt == NULL) {
pr_err("failed to alloc palette memory\n");
lcdc.palette_virt = dma_alloc_writecombine(lcdc.fbdev->dev,
MAX_PALETTE_SIZE, &lcdc.palette_phys, GFP_KERNEL);
if (lcdc.palette_virt == NULL) {
dev_err(lcdc.fbdev->dev, "failed to alloc palette memory\n");
return -ENOMEM;
}
memset(omap_lcdc.palette_virt, 0, MAX_PALETTE_SIZE);
memset(lcdc.palette_virt, 0, MAX_PALETTE_SIZE);
return 0;
}
static void free_palette_ram(void)
{
dma_free_writecombine(omap_lcdc.fbdev->dev, MAX_PALETTE_SIZE,
omap_lcdc.palette_virt, omap_lcdc.palette_phys);
dma_free_writecombine(lcdc.fbdev->dev, MAX_PALETTE_SIZE,
lcdc.palette_virt, lcdc.palette_phys);
}
static int alloc_fbmem(int req_size)
static int alloc_fbmem(struct omapfb_mem_region *region)
{
int bpp;
int frame_size;
struct lcd_panel *panel = omap_lcdc.fbdev->panel;
frame_size = PAGE_ALIGN(panel->x_res * panel->bpp / 8 * panel->y_res);
if (req_size > frame_size)
frame_size = req_size;
omap_lcdc.vram_size = frame_size;
omap_lcdc.vram_virt = dma_alloc_writecombine(omap_lcdc.fbdev->dev,
omap_lcdc.vram_size, &omap_lcdc.vram_phys, GFP_KERNEL);
struct lcd_panel *panel = lcdc.fbdev->panel;
if (omap_lcdc.vram_virt == NULL) {
pr_err("unable to allocate FB DMA memory\n");
bpp = panel->bpp;
if (bpp == 12)
bpp = 16;
frame_size = PAGE_ALIGN(panel->x_res * bpp / 8 * panel->y_res);
if (region->size > frame_size)
frame_size = region->size;
lcdc.vram_size = frame_size;
lcdc.vram_virt = dma_alloc_writecombine(lcdc.fbdev->dev,
lcdc.vram_size, &lcdc.vram_phys, GFP_KERNEL);
if (lcdc.vram_virt == NULL) {
dev_err(lcdc.fbdev->dev, "unable to allocate FB DMA memory\n");
return -ENOMEM;
}
region->size = frame_size;
region->paddr = lcdc.vram_phys;
region->alloc = 1;
memset(omap_lcdc.vram_virt, 0, omap_lcdc.vram_size);
memset(lcdc.vram_virt, 0, lcdc.vram_size);
return 0;
}
static void free_fbmem(void)
{
dma_free_writecombine(omap_lcdc.fbdev->dev, omap_lcdc.vram_size,
omap_lcdc.vram_virt, omap_lcdc.vram_phys);
dma_free_writecombine(lcdc.fbdev->dev, lcdc.vram_size,
lcdc.vram_virt, lcdc.vram_phys);
}
static int setup_fbmem(int req_size)
static int setup_fbmem(struct omapfb_mem_desc *req_md)
{
struct lcd_panel *panel = omap_lcdc.fbdev->panel;
struct omapfb_platform_data *conf;
int frame_size;
int r;
conf = omap_lcdc.fbdev->dev->platform_data;
if (conf->fbmem.fb_sram_size) {
pr_err("can't use FB SRAM in OMAP1\n");
if (!req_md->region_cnt) {
dev_err(lcdc.fbdev->dev, "no memory regions defined\n");
return -EINVAL;
}
if (conf->fbmem.fb_sdram_size == 0) {
omap_lcdc.fbmem_allocated = 1;
if ((r = alloc_fbmem(req_size)) < 0)
return r;
return 0;
if (req_md->region_cnt > 1) {
dev_err(lcdc.fbdev->dev, "only one plane is supported\n");
req_md->region_cnt = 1;
}
if (panel->bpp == 12)
frame_size = PAGE_ALIGN(panel->x_res * 16 / 8 * panel->y_res);
else
frame_size = PAGE_ALIGN(panel->x_res * panel->bpp / 8 * panel->y_res);
if (conf->fbmem.fb_sdram_size < frame_size) {
pr_err("invalid FB memory configuration\n");
return -EINVAL;
}
if (conf->fbmem.fb_sdram_size < req_size) {
pr_err("%d vram was requested, but only %u is available\n",
req_size, conf->fbmem.fb_sdram_size);
if (req_md->region[0].paddr == 0) {
lcdc.fbmem_allocated = 1;
if ((r = alloc_fbmem(&req_md->region[0])) < 0)
return r;
return 0;
}
omap_lcdc.vram_phys = conf->fbmem.fb_sdram_start;
omap_lcdc.vram_size = conf->fbmem.fb_sdram_size;
lcdc.vram_phys = req_md->region[0].paddr;
lcdc.vram_size = req_md->region[0].size;
if ((r = mmap_kern()) < 0)
return r;
DBGPRINT(1, "vram at %08x size %08lx mapped to 0x%p\n",
omap_lcdc.vram_phys, omap_lcdc.vram_size, omap_lcdc.vram_virt);
dev_dbg(lcdc.fbdev->dev, "vram at %08x size %08lx mapped to 0x%p\n",
lcdc.vram_phys, lcdc.vram_size, lcdc.vram_virt);
return 0;
}
static void cleanup_fbmem(void)
{
if (omap_lcdc.fbmem_allocated)
if (lcdc.fbmem_allocated)
free_fbmem();
else
unmap_kern();
}
static int omap_lcdc_init(struct omapfb_device *fbdev, int ext_mode,
int req_vram_size)
struct omapfb_mem_desc *req_vram)
{
int r;
u32 l;
int rate;
struct clk *tc_ck;
DBGENTER(1);
omap_lcdc.irq_mask = 0;
lcdc.irq_mask = 0;
omap_lcdc.fbdev = fbdev;
omap_lcdc.ext_mode = ext_mode;
pr_info(MODULE_NAME ": init\n");
lcdc.fbdev = fbdev;
lcdc.ext_mode = ext_mode;
l = 0;
omap_writel(l, OMAP_LCDC_CONTROL);
......@@ -827,16 +792,16 @@ static int omap_lcdc_init(struct omapfb_device *fbdev, int ext_mode,
/* FIXME:
* According to errata some platforms have a clock rate limitiation
*/
omap_lcdc.lcd_ck = clk_get(NULL, "lcd_ck");
if (IS_ERR(omap_lcdc.lcd_ck)) {
pr_err("unable to access LCD clock\n");
r = PTR_ERR(omap_lcdc.lcd_ck);
lcdc.lcd_ck = clk_get(NULL, "lcd_ck");
if (IS_ERR(lcdc.lcd_ck)) {
dev_err(fbdev->dev, "unable to access LCD clock\n");
r = PTR_ERR(lcdc.lcd_ck);
goto fail0;
}
tc_ck = clk_get(NULL, "tc_ck");
if (IS_ERR(tc_ck)) {
pr_err("unable to access TC clock\n");
dev_err(fbdev->dev, "unable to access TC clock\n");
r = PTR_ERR(tc_ck);
goto fail1;
}
......@@ -846,23 +811,22 @@ static int omap_lcdc_init(struct omapfb_device *fbdev, int ext_mode,
if (machine_is_omap_h3())
rate /= 3;
r = clk_set_rate(omap_lcdc.lcd_ck, rate);
r = clk_set_rate(lcdc.lcd_ck, rate);
if (r) {
pr_err("failed to adjust LCD rate\n");
dev_err(fbdev->dev, "failed to adjust LCD rate\n");
goto fail1;
}
clk_enable(omap_lcdc.lcd_ck);
clk_enable(lcdc.lcd_ck);
r = request_irq(OMAP_LCDC_IRQ, lcdc_irq_handler, 0, "omap-lcdc",
omap_lcdc.fbdev);
r = request_irq(OMAP_LCDC_IRQ, lcdc_irq_handler, 0, MODULE_NAME, fbdev);
if (r) {
pr_err("unable to get IRQ\n");
dev_err(fbdev->dev, "unable to get IRQ\n");
goto fail2;
}
r = omap_request_lcd_dma(lcdc_dma_handler, NULL);
if (r) {
pr_err("unable to get LCD DMA\n");
dev_err(fbdev->dev, "unable to get LCD DMA\n");
goto fail3;
}
......@@ -873,12 +837,11 @@ static int omap_lcdc_init(struct omapfb_device *fbdev, int ext_mode,
if ((r = alloc_palette_ram()) < 0)
goto fail4;
req_vram_size = 1024 * 1024;
if ((r = setup_fbmem(req_vram_size)) < 0)
if ((r = setup_fbmem(req_vram)) < 0)
goto fail5;
pr_info("omapfb: LCDC initialized\n");
DBGLEAVE(1);
return 0;
fail5:
if (!ext_mode)
......@@ -886,32 +849,30 @@ fail5:
fail4:
omap_free_lcd_dma();
fail3:
free_irq(OMAP_LCDC_IRQ, omap_lcdc.fbdev);
free_irq(OMAP_LCDC_IRQ, lcdc.fbdev);
fail2:
clk_disable(omap_lcdc.lcd_ck);
clk_disable(lcdc.lcd_ck);
fail1:
clk_put(omap_lcdc.lcd_ck);
clk_put(lcdc.lcd_ck);
fail0:
DBGLEAVE(1);
return r;
}
static void omap_lcdc_cleanup(void)
{
if (!omap_lcdc.ext_mode)
if (!lcdc.ext_mode)
free_palette_ram();
cleanup_fbmem();
omap_free_lcd_dma();
free_irq(OMAP_LCDC_IRQ, omap_lcdc.fbdev);
clk_disable(omap_lcdc.lcd_ck);
clk_put(omap_lcdc.lcd_ck);
free_irq(OMAP_LCDC_IRQ, lcdc.fbdev);
clk_disable(lcdc.lcd_ck);
clk_put(lcdc.lcd_ck);
}
struct lcd_ctrl omap1_int_ctrl = {
const struct lcd_ctrl omap1_int_ctrl = {
.name = "internal",
.init = omap_lcdc_init,
.cleanup = omap_lcdc_cleanup,
.get_vram_layout = omap_lcdc_get_vram_layout,
.get_caps = omap_lcdc_get_caps,
.set_update_mode = omap_lcdc_set_update_mode,
.get_update_mode = omap_lcdc_get_update_mode,
......@@ -922,6 +883,3 @@ struct lcd_ctrl omap1_int_ctrl = {
.enable_plane = omap_lcdc_enable_plane,
.setcolreg = omap_lcdc_setcolreg,
};
MODULE_DESCRIPTION("TI OMAP LCDC controller");
MODULE_LICENSE("GPL");
......@@ -26,36 +26,19 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/mm.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
#include <asm/uaccess.h>
#include <asm/atomic.h>
#include <asm/mach-types.h>
#include <asm/arch/dma.h>
#include <asm/arch/irqs.h>
#include <asm/arch/mux.h>
#include <asm/arch/board.h>
#include <asm/arch/omapfb.h>
/* #define OMAPFB_DBG 1 */
#include "debug.h"
#define OMAPFB_DRIVER "omapfb"
#define MODULE_NAME "omapfb"
#define pr_err(fmt, args...) printk(KERN_ERR MODULE_NAME ": " fmt, ## args)
static unsigned int def_accel;
static unsigned long def_vram;
static unsigned long def_vram[OMAPFB_PLANE_NUM];
static int def_vram_cnt;
static unsigned long def_vxres;
static unsigned long def_vyres;
static unsigned int def_rotate;
......@@ -87,7 +70,6 @@ static struct caps_table_struct {
extern struct lcd_ctrl omap1_int_ctrl;
extern struct lcd_ctrl omap2_int_ctrl;
extern struct lcd_ctrl hwa742_ctrl;
extern struct lcd_ctrl blizzard_ctrl;
static struct lcd_ctrl *ctrls[] = {
#ifdef CONFIG_ARCH_OMAP1
......@@ -103,9 +85,9 @@ static struct lcd_ctrl *ctrls[] = {
#ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
#ifdef CONFIG_ARCH_OMAP1
extern struct lcd_ctrl_extif sossi_extif;
extern struct lcd_ctrl_extif omap1_ext_if;
#else
extern struct lcd_ctrl_extif rfbi_extif;
extern struct lcd_ctrl_extif omap2_ext_if;
#endif
#endif
......@@ -141,27 +123,48 @@ static const int dma_elem_type[] = {
static int ctrl_init(struct omapfb_device *fbdev)
{
int r;
int i;
/* kernel/module vram parameters override boot tags/board config */
if (def_vram_cnt) {
for (i = 0; i < def_vram_cnt; i++)
fbdev->mem_desc.region[i].size = def_vram[i];
fbdev->mem_desc.region_cnt = i;
} else {
struct omapfb_platform_data *conf;
DBGENTER(1);
conf = fbdev->dev->platform_data;
fbdev->mem_desc = conf->mem_desc;
}
r = fbdev->ctrl->init(fbdev, 0, def_vram);
if (!fbdev->mem_desc.region_cnt) {
struct lcd_panel *panel = fbdev->panel;
int def_size;
int bpp = panel->bpp;
/* 12 bpp is packed in 16 bits */
if (bpp == 12)
bpp = 16;
def_size = def_vxres * def_vyres * bpp / 8;
fbdev->mem_desc.region_cnt = 1;
fbdev->mem_desc.region[0].size = def_size;
}
r = fbdev->ctrl->init(fbdev, 0, &fbdev->mem_desc);
if (r < 0) {
pr_err("controller initialization failed\n");
goto exit;
dev_err(fbdev->dev, "controller initialization failed (%d)\n", r);
return r;
}
fbdev->ctrl->get_vram_layout(&fbdev->vram_size, &fbdev->vram_virt_base,
&fbdev->vram_phys_base);
DBGPRINT(1, "vram_phys %08x vram_virt %p vram_size=%lu\n",
fbdev->vram_phys_base, fbdev->vram_virt_base,
fbdev->vram_size);
DBGLEAVE(1);
#ifdef DEBUG
for (i = 0; i < fbdev->mem_desc.region_cnt; i++) {
dev_dbg(fbdev->dev, "region%d phys %08x virt %p size=%lu\n",
i,
fbdev->mem_desc.region[i].paddr,
fbdev->mem_desc.region[i].vaddr,
fbdev->mem_desc.region[i].size);
}
#endif
return 0;
exit:
DBGLEAVE(1);
return r;
}
static void ctrl_cleanup(struct omapfb_device *fbdev)
......@@ -169,21 +172,28 @@ static void ctrl_cleanup(struct omapfb_device *fbdev)
fbdev->ctrl->cleanup();
}
static int ctrl_change_mode(struct omapfb_device *fbdev)
static int ctrl_change_mode(struct fb_info *fbi)
{
int r;
unsigned long offset;
struct fb_var_screeninfo *var = &fbdev->fb_info->var;
struct omapfb_plane_struct *plane = fbi->par;
struct omapfb_device *fbdev = plane->fbdev;
struct fb_var_screeninfo *var = &fbi->var;
DBGPRINT(1, "xoffset %d yoffset %d line_length %d bits_per_pixel %d\n",
var->xoffset, var->yoffset, fbdev->fb_info->fix.line_length,
var->bits_per_pixel);
offset = var->yoffset * fbdev->fb_info->fix.line_length +
offset = var->yoffset * fbi->fix.line_length +
var->xoffset * var->bits_per_pixel / 8;
r = fbdev->ctrl->setup_plane(OMAPFB_PLANE_GFX, OMAPFB_CHANNEL_OUT_LCD,
offset, var->xres_virtual, 0, 0, var->xres,
var->yres, fbdev->color_mode);
DBGLEAVE(1);
omapfb_rqueue_lock(fbdev);
r = fbdev->ctrl->setup_plane(plane->idx, plane->info.channel_out,
offset, var->xres_virtual,
plane->info.pos_x, plane->info.pos_y,
var->xres, var->yres, plane->color_mode);
if (fbdev->ctrl->set_scale != NULL)
r = fbdev->ctrl->set_scale(plane->idx,
var->xres, var->yres,
plane->info.out_width,
plane->info.out_height);
omapfb_rqueue_unlock(fbdev);
return r;
}
......@@ -196,8 +206,6 @@ static int ctrl_change_mode(struct omapfb_device *fbdev)
/* Called each time the omapfb device is opened */
static int omapfb_open(struct fb_info *info, int user)
{
DBGENTER(1);
DBGLEAVE(1);
return 0;
}
......@@ -207,11 +215,7 @@ static void omapfb_sync(struct fb_info *info);
* gfx DMA operations are ended, before we return. */
static int omapfb_release(struct fb_info *info, int user)
{
DBGENTER(1);
omapfb_sync(info);
DBGLEAVE(1);
return 0;
}
......@@ -222,13 +226,15 @@ static int omapfb_release(struct fb_info *info, int user)
static int _setcolreg(struct fb_info *info, u_int regno, u_int red, u_int green,
u_int blue, u_int transp, int update_hw_pal)
{
struct omapfb_device *fbdev = (struct omapfb_device *)info->par;
struct omapfb_plane_struct *plane = info->par;
struct omapfb_device *fbdev = plane->fbdev;
struct fb_var_screeninfo *var = &info->var;
int r = 0;
switch (fbdev->color_mode) {
switch (plane->color_mode) {
case OMAPFB_COLOR_YUV422:
case OMAPFB_COLOR_YUV420:
case OMAPFB_COLOR_YUY422:
r = -EINVAL;
break;
case OMAPFB_COLOR_CLUT_8BPP:
......@@ -251,8 +257,10 @@ static int _setcolreg(struct fb_info *info, u_int regno, u_int red, u_int green,
if (regno < 16) {
u16 pal;
pal = ((red >> (16 - var->red.length)) << var->red.offset) |
((green >> (16 - var->green.length)) << var->green.offset) |
pal = ((red >> (16 - var->red.length)) <<
var->red.offset) |
((green >> (16 - var->green.length)) <<
var->green.offset) |
(blue >> (16 - var->blue.length));
((u32 *)(info->pseudo_palette))[regno] = pal;
}
......@@ -266,15 +274,7 @@ static int _setcolreg(struct fb_info *info, u_int regno, u_int red, u_int green,
static int omapfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
u_int transp, struct fb_info *info)
{
int r = 0;
DBGENTER(2);
_setcolreg(info, regno, red, green, blue, transp, 1);
DBGLEAVE(2);
return r;
return _setcolreg(info, regno, red, green, blue, transp, 1);
}
static int omapfb_setcmap(struct fb_cmap *cmap, struct fb_info *info)
......@@ -301,35 +301,22 @@ static int omapfb_setcmap(struct fb_cmap *cmap, struct fb_info *info)
return 0;
}
static int omapfb_mmap(struct fb_info *info, struct vm_area_struct *vma)
{
struct omapfb_device *fbdev = info->par;
int r;
omapfb_rqueue_lock(fbdev);
r = fbdev->ctrl->mmap(vma);
omapfb_rqueue_unlock(fbdev);
return r;
}
static void omapfb_update_full_screen(struct omapfb_device *fbdev);
static int omapfb_update_full_screen(struct fb_info *fbi);
static int omapfb_blank(int blank, struct fb_info *fbi)
{
struct omapfb_device *fbdev = (struct omapfb_device *)fbi->par;
struct omapfb_plane_struct *plane = fbi->par;
struct omapfb_device *fbdev = plane->fbdev;
int do_update = 0;
int r = 0;
DBGENTER(1);
omapfb_rqueue_lock(fbdev);
switch (blank) {
case VESA_NO_BLANKING:
if (fbdev->state == OMAPFB_SUSPENDED) {
if (fbdev->ctrl->resume)
fbdev->ctrl->resume();
fbdev->panel->enable();
fbdev->panel->enable(fbdev->panel);
fbdev->state = OMAPFB_ACTIVE;
if (fbdev->ctrl->get_update_mode() ==
OMAPFB_MANUAL_UPDATE)
......@@ -338,7 +325,7 @@ static int omapfb_blank(int blank, struct fb_info *fbi)
break;
case VESA_POWERDOWN:
if (fbdev->state == OMAPFB_ACTIVE) {
fbdev->panel->disable();
fbdev->panel->disable(fbdev->panel);
if (fbdev->ctrl->suspend)
fbdev->ctrl->suspend();
fbdev->state = OMAPFB_SUSPENDED;
......@@ -349,16 +336,16 @@ static int omapfb_blank(int blank, struct fb_info *fbi)
}
omapfb_rqueue_unlock(fbdev);
if (do_update)
omapfb_update_full_screen(fbdev);
if (r == 0 && do_update)
r = omapfb_update_full_screen(fbi);
DBGLEAVE(1);
return r;
}
static void omapfb_sync(struct fb_info *fbi)
{
struct omapfb_device *fbdev = (struct omapfb_device *)fbi->par;
struct omapfb_plane_struct *plane = fbi->par;
struct omapfb_device *fbdev = plane->fbdev;
omapfb_rqueue_lock(fbdev);
if (fbdev->ctrl->sync)
......@@ -369,17 +356,22 @@ static void omapfb_sync(struct fb_info *fbi)
/* Set fb_info.fix fields and also updates fbdev.
* When calling this fb_info.var must be set up already.
*/
static void set_fb_fix(struct omapfb_device *fbdev)
static void set_fb_fix(struct fb_info *fbi)
{
struct fb_info *fbi = fbdev->fb_info;
struct fb_fix_screeninfo *fix = &fbi->fix;
struct fb_var_screeninfo *var = &fbi->var;
int bpp;
strncpy(fix->id, OMAPFB_DRIVER, sizeof(fix->id));
fix->type = FB_TYPE_PACKED_PIXELS;
switch (var->bits_per_pixel) {
bpp = var->bits_per_pixel;
if (var->nonstd)
fix->visual = FB_VISUAL_PSEUDOCOLOR;
else switch (var->bits_per_pixel) {
case 16:
case 12:
fix->visual = FB_VISUAL_TRUECOLOR;
/* 12bpp is stored in 16 bits */
bpp = 16;
break;
case 1:
case 2:
......@@ -389,61 +381,118 @@ static void set_fb_fix(struct omapfb_device *fbdev)
break;
}
fix->accel = FB_ACCEL_OMAP1610;
fix->line_length = var->xres_virtual * var->bits_per_pixel / 8;
fix->smem_len = fbdev->vram_size;
fix->smem_start = fbdev->vram_phys_base;
fix->line_length = var->xres_virtual * bpp / 8;
}
static int set_color_mode(struct omapfb_plane_struct *plane,
struct fb_var_screeninfo *var)
{
switch (var->nonstd) {
case 0:
break;
case OMAPFB_COLOR_YUV422:
var->bits_per_pixel = 16;
plane->color_mode = var->nonstd;
return 0;
case OMAPFB_COLOR_YUV420:
var->bits_per_pixel = 12;
plane->color_mode = var->nonstd;
return 0;
case OMAPFB_COLOR_YUY422:
var->bits_per_pixel = 16;
plane->color_mode = var->nonstd;
return 0;
default:
return -EINVAL;
}
switch (var->bits_per_pixel) {
case 1:
plane->color_mode = OMAPFB_COLOR_CLUT_1BPP;
return 0;
case 2:
plane->color_mode = OMAPFB_COLOR_CLUT_2BPP;
return 0;
case 4:
plane->color_mode = OMAPFB_COLOR_CLUT_4BPP;
return 0;
case 8:
plane->color_mode = OMAPFB_COLOR_CLUT_8BPP;
return 0;
case 12:
plane->color_mode = OMAPFB_COLOR_RGB444;
return 0;
case 16:
plane->color_mode = OMAPFB_COLOR_RGB565;
return 0;
default:
return -EINVAL;
}
}
/* Check the values in var against our capabilities and in case of out of
* bound values try to adjust them.
*/
static int set_fb_var(struct omapfb_device *fbdev,
static int set_fb_var(struct fb_info *fbi,
struct fb_var_screeninfo *var)
{
int bpp;
unsigned long max_frame_size;
unsigned long line_size;
int xres_min, xres_max;
int yres_min, yres_max;
struct omapfb_plane_struct *plane = fbi->par;
struct omapfb_device *fbdev = plane->fbdev;
struct lcd_panel *panel = fbdev->panel;
if (panel->bpp == 12)
bpp = var->bits_per_pixel = 16; /* 12-bit bpp mode stores colours in 16-bits */
else
bpp = var->bits_per_pixel = panel->bpp;
switch (panel->bpp) {
case 16:
fbdev->color_mode = OMAPFB_COLOR_RGB565;
break;
case 12:
fbdev->color_mode = OMAPFB_COLOR_RGB444;
break;
case 8:
fbdev->color_mode = OMAPFB_COLOR_CLUT_8BPP;
break;
default:
/* FIXME: other BPPs not yet supported */
if (set_color_mode(plane, var) < 0)
return -EINVAL;
}
bpp = var->bits_per_pixel;
if (plane->color_mode == OMAPFB_COLOR_RGB444)
bpp = 16;
switch (var->rotate) {
case 0:
case 180:
var->xres = fbdev->panel->x_res;
var->yres = fbdev->panel->y_res;
xres_min = OMAPFB_PLANE_XRES_MIN;
xres_max = panel->x_res;
yres_min = OMAPFB_PLANE_YRES_MIN;
yres_max = panel->y_res;
if (cpu_is_omap1510()) {
var->xres = panel->x_res;
var->yres = panel->y_res;
}
break;
case 90:
case 270:
var->xres = fbdev->panel->y_res;
var->yres = fbdev->panel->x_res;
xres_min = OMAPFB_PLANE_YRES_MIN;
xres_max = panel->y_res;
yres_min = OMAPFB_PLANE_XRES_MIN;
yres_max = panel->x_res;
if (cpu_is_omap1510()) {
var->xres = panel->y_res;
var->yres = panel->x_res;
}
break;
default:
return -EINVAL;
}
if (var->xres < xres_min)
var->xres = xres_min;
if (var->yres < yres_min)
var->yres = yres_min;
if (var->xres > xres_max)
var->xres = xres_max;
if (var->yres > yres_max)
var->yres = yres_max;
if (var->xres_virtual < var->xres)
var->xres_virtual = var->xres;
if (var->yres_virtual < var->yres)
var->yres_virtual = var->yres;
max_frame_size = fbdev->vram_size;
max_frame_size = fbdev->mem_desc.region[plane->idx].size;
line_size = var->xres_virtual * bpp / 8;
if (line_size * var->yres_virtual > max_frame_size) {
/* Try to keep yres_virtual first */
......@@ -462,23 +511,25 @@ static int set_fb_var(struct omapfb_device *fbdev,
var->yoffset = var->yres_virtual - var->yres;
line_size = var->xres * bpp / 8;
if (fbdev->color_mode == OMAPFB_COLOR_RGB444)
{
var->red.offset = 8; var->red.length = 4; var->red.msb_right = 0;
var->green.offset= 4; var->green.length = 4; var->green.msb_right = 0;
var->blue.offset = 0; var->blue.length = 4; var->blue.msb_right = 0;
}
else
{
var->red.offset = 11; var->red.length = 5; var->red.msb_right = 0;
var->green.offset= 5; var->green.length = 6; var->green.msb_right = 0;
var->blue.offset = 0; var->blue.length = 5; var->blue.msb_right = 0;
if (plane->color_mode == OMAPFB_COLOR_RGB444) {
var->red.offset = 8; var->red.length = 4;
var->red.msb_right = 0;
var->green.offset = 4; var->green.length = 4;
var->green.msb_right = 0;
var->blue.offset = 0; var->blue.length = 4;
var->blue.msb_right = 0;
} else {
var->red.offset = 11; var->red.length = 5;
var->red.msb_right = 0;
var->green.offset= 5; var->green.length = 6;
var->green.msb_right = 0;
var->blue.offset = 0; var->blue.length = 5;
var->blue.msb_right = 0;
}
var->height = -1;
var->width = -1;
var->grayscale = 0;
var->nonstd = 0;
/* pixclock in ps, the rest in pixclock */
var->pixclock = 10000000 / (panel->pixel_clock / 100);
......@@ -501,21 +552,15 @@ static struct fb_var_screeninfo new_var;
/* Set rotation (0, 90, 180, 270 degree), and switch to the new mode. */
static void omapfb_rotate(struct fb_info *fbi, int rotate)
{
struct omapfb_device *fbdev = (struct omapfb_device *)fbi->par;
DBGENTER(1);
if (cpu_is_omap1510() && rotate != fbdev->fb_info->var.rotate) {
if (cpu_is_omap1510() && rotate != fbi->var.rotate) {
memcpy(&new_var, &fbi->var, sizeof(new_var));
new_var.rotate = rotate;
if (set_fb_var(fbdev, &new_var) == 0 &&
if (set_fb_var(fbi, &new_var) == 0 &&
memcmp(&new_var, &fbi->var, sizeof(new_var))) {
memcpy(&fbi->var, &new_var, sizeof(new_var));
ctrl_change_mode(fbdev);
ctrl_change_mode(fbi);
}
}
DBGLEAVE(1);
}
/* Set new x,y offsets in the virtual display for the visible area and switch
......@@ -524,44 +569,38 @@ static void omapfb_rotate(struct fb_info *fbi, int rotate)
static int omapfb_pan_display(struct fb_var_screeninfo *var,
struct fb_info *fbi)
{
struct omapfb_device *fbdev = (struct omapfb_device *)fbi->par;
int r = 0;
DBGENTER(1);
if (var->xoffset != fbi->var.xoffset ||
var->yoffset != fbi->var.yoffset) {
memcpy(&new_var, &fbi->var, sizeof(new_var));
new_var.xoffset = var->xoffset;
new_var.yoffset = var->yoffset;
if (set_fb_var(fbdev, &new_var))
if (set_fb_var(fbi, &new_var))
r = -EINVAL;
else {
memcpy(&fbi->var, &new_var, sizeof(new_var));
ctrl_change_mode(fbdev);
ctrl_change_mode(fbi);
}
}
DBGLEAVE(1);
return r;
}
/* Set mirror to vertical axis and switch to the new mode. */
static int omapfb_mirror(struct omapfb_device *fbdev, int mirror)
static int omapfb_mirror(struct fb_info *fbi, int mirror)
{
struct omapfb_plane_struct *plane = fbi->par;
int r = 0;
DBGENTER(1);
mirror = mirror ? 1 : 0;
if (cpu_is_omap1510())
r = -EINVAL;
else if (mirror != fbdev->mirror) {
fbdev->mirror = mirror;
r = ctrl_change_mode(fbdev);
else if (mirror != plane->info.mirror) {
plane->info.mirror = mirror;
r = ctrl_change_mode(fbi);
}
DBGLEAVE(1);
return r;
}
......@@ -570,15 +609,7 @@ static int omapfb_mirror(struct omapfb_device *fbdev, int mirror)
*/
static int omapfb_check_var(struct fb_var_screeninfo *var, struct fb_info *fbi)
{
struct omapfb_device *fbdev = (struct omapfb_device *)fbi->par;
int r;
DBGENTER(1);
r = set_fb_var(fbdev, var);
DBGLEAVE(1);
return r;
return set_fb_var(fbi, var);
}
/* Switch to a new mode. The parameters for it has been check already by
......@@ -586,126 +617,137 @@ static int omapfb_check_var(struct fb_var_screeninfo *var, struct fb_info *fbi)
*/
static int omapfb_set_par(struct fb_info *fbi)
{
int r;
struct omapfb_device *fbdev = (struct omapfb_device *)fbi->par;
DBGENTER(1);
set_fb_fix(fbdev);
r = ctrl_change_mode(fbdev);
DBGLEAVE(1);
return r;
set_fb_fix(fbi);
return ctrl_change_mode(fbi);
}
int omapfb_update_window_async(struct omapfb_update_window *win,
int omapfb_update_window_async(struct fb_info *fbi,
struct omapfb_update_window *win,
void (*callback)(void *),
void *callback_data)
{
struct omapfb_device *fbdev = omapfb_dev;
struct omapfb_plane_struct *plane = fbi->par;
struct omapfb_device *fbdev = plane->fbdev;
struct fb_var_screeninfo *var;
DBGENTER(2);
if (fbdev == NULL) {
DBGPRINT(1, "no fbdev\n");
return -ENODEV;
}
var = &fbi->var;
var = &fbdev->fb_info->var;
if (win->x >= var->xres || win->y >= var->yres) {
DBGPRINT(1, "invalid x %d, y %d\n", win->x, win->y);
if (win->x >= var->xres || win->y >= var->yres)
return -EINVAL;
}
if (!fbdev->ctrl->update_window ||
fbdev->ctrl->get_update_mode() != OMAPFB_MANUAL_UPDATE) {
DBGPRINT(1, "invalid update mode\n");
fbdev->ctrl->get_update_mode() != OMAPFB_MANUAL_UPDATE)
return -ENODEV;
}
if (win->x + win->width >= var->xres)
win->width = var->xres - win->x;
if (win->y + win->height >= var->yres)
win->height = var->yres - win->y;
if (!win->width || !win->height) {
DBGPRINT(1, "zero size window\n");
if (!win->width || !win->height)
return 0;
}
return fbdev->ctrl->update_window(win, callback, callback_data);
return fbdev->ctrl->update_window(fbi, win, callback, callback_data);
}
EXPORT_SYMBOL(omapfb_update_window_async);
static int omapfb_update_win(struct omapfb_device *fbdev,
static int omapfb_update_win(struct fb_info *fbi,
struct omapfb_update_window *win)
{
struct omapfb_plane_struct *plane = fbi->par;
int ret;
omapfb_rqueue_lock(fbdev);
ret = omapfb_update_window_async(win, NULL, 0);
omapfb_rqueue_unlock(fbdev);
omapfb_rqueue_lock(plane->fbdev);
ret = omapfb_update_window_async(fbi, win, NULL, 0);
omapfb_rqueue_unlock(plane->fbdev);
return ret;
}
static void omapfb_update_full_screen(struct omapfb_device *fbdev)
static int omapfb_update_full_screen(struct fb_info *fbi)
{
struct omapfb_plane_struct *plane = fbi->par;
struct omapfb_device *fbdev = plane->fbdev;
struct omapfb_update_window win;
int r;
if (!fbdev->ctrl->update_window ||
fbdev->ctrl->get_update_mode() != OMAPFB_MANUAL_UPDATE)
return -ENODEV;
win.x = 0;
win.y = 0;
win.width = fbdev->panel->x_res;
win.height = fbdev->panel->y_res;
win.width = fbi->var.xres;
win.height = fbi->var.yres;
win.format = 0;
omapfb_rqueue_lock(fbdev);
fbdev->ctrl->update_window(&win, NULL, 0);
r = fbdev->ctrl->update_window(fbi, &win, NULL, 0);
omapfb_rqueue_unlock(fbdev);
return r;
}
static int omapfb_setup_plane(struct omapfb_device *fbdev,
struct omapfb_setup_plane *sp)
static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi)
{
struct omapfb_plane_struct *plane = fbi->par;
struct omapfb_device *fbdev = plane->fbdev;
int r;
omapfb_rqueue_lock(fbdev);
r = fbdev->ctrl->setup_plane(sp->plane, sp->channel_out, sp->offset,
sp->width, sp->pos_x, sp->pos_y, sp->width,
sp->height, sp->color_mode);
omapfb_rqueue_unlock(fbdev);
plane->info = *pi;
r = ctrl_change_mode(fbi);
if (r < 0)
return r;
return fbdev->ctrl->enable_plane(plane->idx, pi->enabled);
}
static int omapfb_enable_plane(struct omapfb_device *fbdev, int plane,
int enable)
static int omapfb_query_plane(struct fb_info *fbi, struct omapfb_plane_info *pi)
{
struct omapfb_plane_struct *plane = fbi->par;
*pi = plane->info;
return 0;
}
static int omapfb_set_color_key(struct omapfb_device *fbdev,
struct omapfb_color_key *ck)
{
int r;
if (!fbdev->ctrl->set_color_key)
return -ENODEV;
omapfb_rqueue_lock(fbdev);
r = fbdev->ctrl->enable_plane(plane, enable);
r = fbdev->ctrl->set_color_key(ck);
omapfb_rqueue_unlock(fbdev);
return r;
}
static int omapfb_set_color_key(struct omapfb_device *fbdev,
static int omapfb_get_color_key(struct omapfb_device *fbdev,
struct omapfb_color_key *ck)
{
int r;
if (!fbdev->ctrl->set_color_key)
if (!fbdev->ctrl->get_color_key)
return -ENODEV;
omapfb_rqueue_lock(fbdev);
r = fbdev->ctrl->set_color_key(ck);
r = fbdev->ctrl->get_color_key(ck);
omapfb_rqueue_unlock(fbdev);
return r;
}
static BLOCKING_NOTIFIER_HEAD(omapfb_notifier_list);
static struct blocking_notifier_head omapfb_client_list[OMAPFB_PLANE_NUM];
static int notifier_inited;
static void omapfb_init_notifier(void)
{
int i;
for (i = 0; i < OMAPFB_PLANE_NUM; i++)
BLOCKING_INIT_NOTIFIER_HEAD(&omapfb_client_list[i]);
}
int omapfb_register_client(struct omapfb_notifier_block *omapfb_nb,
omapfb_notifier_callback_t callback,
......@@ -713,12 +755,20 @@ int omapfb_register_client(struct omapfb_notifier_block *omapfb_nb,
{
int r;
DBGENTER(1);
if ((unsigned)omapfb_nb->plane_idx > OMAPFB_PLANE_NUM)
return -EINVAL;
if (!notifier_inited) {
omapfb_init_notifier();
notifier_inited = 1;
}
omapfb_nb->nb.notifier_call = (int (*)(struct notifier_block *,
unsigned long, void *))callback;
omapfb_nb->data = callback_data;
r = blocking_notifier_chain_register(&omapfb_notifier_list, &omapfb_nb->nb);
r = blocking_notifier_chain_register(
&omapfb_client_list[omapfb_nb->plane_idx],
&omapfb_nb->nb);
if (r)
return r;
if (omapfb_dev != NULL &&
......@@ -732,15 +782,22 @@ EXPORT_SYMBOL(omapfb_register_client);
int omapfb_unregister_client(struct omapfb_notifier_block *omapfb_nb)
{
return blocking_notifier_chain_unregister(&omapfb_notifier_list,
&omapfb_nb->nb);
return blocking_notifier_chain_unregister(
&omapfb_client_list[omapfb_nb->plane_idx], &omapfb_nb->nb);
}
EXPORT_SYMBOL(omapfb_unregister_client);
void omapfb_notify_clients(struct omapfb_device *fbdev, unsigned long event)
{
DBGENTER(1);
blocking_notifier_call_chain(&omapfb_notifier_list, event, fbdev);
int i;
if (!notifier_inited)
/* no client registered yet */
return;
for (i = 0; i < OMAPFB_PLANE_NUM; i++)
blocking_notifier_call_chain(&omapfb_client_list[i], event,
fbdev->fb_info[i]);
}
EXPORT_SYMBOL(omapfb_notify_clients);
......@@ -767,13 +824,12 @@ static enum omapfb_update_mode omapfb_get_update_mode(struct omapfb_device *fbde
return r;
}
static unsigned long omapfb_get_caps(struct fb_info *fbi)
static unsigned long omapfb_get_caps(struct omapfb_device *fbdev)
{
struct omapfb_device *fbdev = (struct omapfb_device *)fbi->par;
unsigned long caps;
caps = 0;
caps |= fbdev->panel->get_caps();
caps |= fbdev->panel->get_caps(fbdev->panel);
caps |= fbdev->ctrl->get_caps();
return caps;
}
......@@ -782,7 +838,7 @@ static unsigned long omapfb_get_caps(struct fb_info *fbi)
void omapfb_write_first_pixel(struct omapfb_device *fbdev, u16 pixval)
{
omapfb_rqueue_lock(fbdev);
*(u16 *)fbdev->vram_virt_base = pixval;
*(u16 *)fbdev->mem_desc.region[0].vaddr = pixval;
if (fbdev->ctrl->get_update_mode() == OMAPFB_MANUAL_UPDATE) {
struct omapfb_update_window win;
......@@ -791,42 +847,41 @@ void omapfb_write_first_pixel(struct omapfb_device *fbdev, u16 pixval)
win.width = 1;
win.height = 1;
win.format = 0;
fbdev->ctrl->update_window(&win, NULL, 0);
fbdev->ctrl->update_window(fbdev->fb_info[0], &win, NULL, 0);
}
omapfb_rqueue_unlock(fbdev);
}
EXPORT_SYMBOL(omapfb_write_first_pixel);
/* Ioctl interface. Part of the kernel mode frame buffer API is duplicated
* here to be accessible by user mode code. In addition transparent copy
* graphics transformations, frame flipping support is provided through this
* interface.
* here to be accessible by user mode code.
*/
static int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd,
unsigned long arg)
{
struct omapfb_device *fbdev = (struct omapfb_device *)fbi->par;
struct omapfb_plane_struct *plane = fbi->par;
struct omapfb_device *fbdev = plane->fbdev;
struct fb_ops *ops = fbi->fbops;
union {
struct omapfb_update_window update_window;
struct omapfb_setup_plane setup_plane;
struct omapfb_enable_plane enable_plane;
struct omapfb_plane_info plane_info;
struct omapfb_color_key color_key;
enum omapfb_update_mode update_mode;
unsigned long caps;
unsigned int mirror;
int plane_out;
int enable_plane;
} p;
int r = 0;
BUG_ON(!ops);
DBGPRINT(2, "cmd=%010x\n", cmd);
switch (cmd)
{
case OMAPFB_MIRROR:
if (get_user(p.mirror, (int __user *)arg))
r = -EFAULT;
else
omapfb_mirror(fbdev, p.mirror);
omapfb_mirror(fbi, p.mirror);
break;
case OMAPFB_SYNC_GFX:
omapfb_sync(fbi);
......@@ -851,7 +906,7 @@ static int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd,
r = -EFAULT;
else {
p.update_window.format = 0;
r = omapfb_update_win(fbdev, &p.update_window);
r = omapfb_update_win(fbi, &p.update_window);
}
break;
case OMAPFB_UPDATE_WINDOW:
......@@ -859,22 +914,21 @@ static int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd,
sizeof(p.update_window)))
r = -EFAULT;
else
r = omapfb_update_win(fbdev, &p.update_window);
r = omapfb_update_win(fbi, &p.update_window);
break;
case OMAPFB_SETUP_PLANE:
if (copy_from_user(&p.setup_plane, (void __user *)arg,
sizeof(p.setup_plane)))
if (copy_from_user(&p.plane_info, (void __user *)arg,
sizeof(p.plane_info)))
r = -EFAULT;
else
r = omapfb_setup_plane(fbdev, &p.setup_plane);
r = omapfb_setup_plane(fbi, &p.plane_info);
break;
case OMAPFB_ENABLE_PLANE:
if (copy_from_user(&p.enable_plane, (void __user *)arg,
sizeof(p.enable_plane)))
case OMAPFB_QUERY_PLANE:
if ((r = omapfb_query_plane(fbi, &p.plane_info)) < 0)
break;
if (copy_to_user((void __user *)arg, &p.plane_info,
sizeof(p.plane_info)))
r = -EFAULT;
else
r = omapfb_enable_plane(fbdev,
p.enable_plane.plane, p.enable_plane.enable);
break;
case OMAPFB_SET_COLOR_KEY:
if (copy_from_user(&p.color_key, (void __user *)arg,
......@@ -883,9 +937,11 @@ static int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd,
else
r = omapfb_set_color_key(fbdev, &p.color_key);
break;
case OMAPFB_GET_CAPS:
p.caps = omapfb_get_caps(fbi);
if (put_user(p.caps, (unsigned long __user *)arg))
case OMAPFB_GET_COLOR_KEY:
if ((r = omapfb_get_color_key(fbdev, &p.color_key)) < 0)
break;
if (copy_to_user((void __user *)arg, &p.color_key,
sizeof(p.color_key)))
r = -EFAULT;
break;
case OMAPFB_LCD_TEST:
......@@ -900,7 +956,7 @@ static int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd,
r = -EINVAL;
break;
}
r = fbdev->panel->run_test(test_num);
r = fbdev->panel->run_test(fbdev->panel, test_num);
break;
}
case OMAPFB_CTRL_TEST:
......@@ -922,7 +978,6 @@ static int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd,
r = -EINVAL;
}
DBGLEAVE(2);
return r;
}
......@@ -956,8 +1011,7 @@ static ssize_t omapfb_show_caps_num(struct device *dev, struct device_attribute
{
struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data;
return snprintf(buf, PAGE_SIZE, "%#010lx\n",
omapfb_get_caps(fbdev->fb_info));
return snprintf(buf, PAGE_SIZE, "%#010lx\n", omapfb_get_caps(fbdev));
}
static ssize_t omapfb_show_caps_text(struct device *dev, struct device_attribute *attr, char *buf)
......@@ -967,7 +1021,7 @@ static ssize_t omapfb_show_caps_text(struct device *dev, struct device_attribute
int i;
unsigned long caps;
caps = omapfb_get_caps(fbdev->fb_info);
caps = omapfb_get_caps(fbdev);
for (i = 0; i < ARRAY_SIZE(omapfb_caps_table) && pos < PAGE_SIZE; i++) {
if (omapfb_caps_table[i].flag & caps) {
pos += snprintf(&buf[pos], PAGE_SIZE - pos, "%s\n",
......@@ -998,7 +1052,7 @@ static ssize_t omapfb_show_bklight_level(struct device *dev,
if (fbdev->panel->get_bklight_level) {
r = snprintf(buf, PAGE_SIZE, "%d\n",
fbdev->panel->get_bklight_level());
fbdev->panel->get_bklight_level(fbdev->panel));
} else
r = -ENODEV;
return r;
......@@ -1015,7 +1069,7 @@ static ssize_t omapfb_store_bklight_level(struct device *dev,
unsigned int level;
if (sscanf(buf, "%10d", &level) == 1) {
r = fbdev->panel->set_bklight_level(level);
r = fbdev->panel->set_bklight_level(fbdev->panel, level);
} else
r = -EINVAL;
} else
......@@ -1031,7 +1085,7 @@ static ssize_t omapfb_show_bklight_max(struct device *dev,
if (fbdev->panel->get_bklight_level) {
r = snprintf(buf, PAGE_SIZE, "%d\n",
fbdev->panel->get_bklight_max());
fbdev->panel->get_bklight_max(fbdev->panel));
} else
r = -ENODEV;
return r;
......@@ -1101,7 +1155,7 @@ fail2:
fail1:
device_remove_file(fbdev->dev, &dev_attr_caps_num);
fail0:
pr_err("unable to register sysfs interface\n");
dev_err(fbdev->dev, "unable to register sysfs interface\n");
return r;
}
......@@ -1121,48 +1175,92 @@ static void omapfb_unregister_sysfs(struct omapfb_device *fbdev)
/* Initialize system fb_info object and set the default video mode.
* The frame buffer memory already allocated by lcddma_init
*/
static int fbinfo_init(struct omapfb_device *fbdev)
static int fbinfo_init(struct omapfb_device *fbdev, struct fb_info *info,
struct omapfb_mem_region *region)
{
struct fb_info *info = fbdev->fb_info;
struct fb_var_screeninfo *var = &info->var;
struct fb_fix_screeninfo *fix = &info->fix;
int r = 0;
DBGENTER(1);
BUG_ON(!fbdev->vram_virt_base);
info->fbops = &omapfb_ops;
info->flags = FBINFO_FLAG_DEFAULT;
info->screen_base = (char __iomem *)fbdev->vram_virt_base;
strncpy(fix->id, MODULE_NAME, sizeof(fix->id));
info->screen_base = (char __iomem *)region->vaddr;
fix->smem_start = region->paddr;
fix->smem_len = region->size;
info->pseudo_palette = fbdev->pseudo_palette;
var->accel_flags = def_accel ? FB_ACCELF_TEXT : 0;
var->xres = def_vxres;
var->yres = def_vyres;
var->xres_virtual = def_vxres;
var->yres_virtual = def_vyres;
var->rotate = def_rotate;
var->bits_per_pixel = fbdev->panel->bpp;
fbdev->mirror = def_mirror;
set_fb_var(fbdev, var);
set_fb_fix(fbdev);
set_fb_var(info, var);
set_fb_fix(info);
r = fb_alloc_cmap(&info->cmap, 16, 0);
if (r != 0)
pr_err("unable to allocate color map memory\n");
dev_err(fbdev->dev, "unable to allocate color map memory\n");
DBGLEAVE(1);
return r;
}
/* Release the fb_info object */
static void fbinfo_cleanup(struct omapfb_device *fbdev)
static void fbinfo_cleanup(struct omapfb_device *fbdev, struct fb_info *fbi)
{
fb_dealloc_cmap(&fbi->cmap);
}
static void planes_cleanup(struct omapfb_device *fbdev)
{
DBGENTER(1);
int i;
fb_dealloc_cmap(&fbdev->fb_info->cmap);
for (i = 0; i < fbdev->mem_desc.region_cnt; i++) {
if (fbdev->fb_info[i] == NULL)
break;
fbinfo_cleanup(fbdev, fbdev->fb_info[i]);
framebuffer_release(fbdev->fb_info[i]);
}
}
static int planes_init(struct omapfb_device *fbdev)
{
struct fb_info *fbi;
int i;
int r;
DBGLEAVE(1);
for (i = 0; i < fbdev->mem_desc.region_cnt; i++) {
struct omapfb_plane_struct *plane;
fbi = framebuffer_alloc(sizeof(struct omapfb_plane_struct),
fbdev->dev);
if (fbi == NULL) {
dev_err(fbdev->dev,
"unable to allocate memory for plane info\n");
planes_cleanup(fbdev);
return -ENOMEM;
}
plane = fbi->par;
plane->idx = i;
plane->fbdev = fbdev;
plane->info.mirror = def_mirror;
fbdev->fb_info[i] = fbi;
if ((r = fbinfo_init(fbdev, fbi,
&fbdev->mem_desc.region[i])) < 0) {
framebuffer_release(fbi);
planes_cleanup(fbdev);
return r;
}
plane->info.out_width = fbi->var.xres;
plane->info.out_height = fbi->var.yres;
}
return 0;
}
/* Free driver resources. Can be called to rollback an aborted initialization
......@@ -1170,24 +1268,27 @@ static void fbinfo_cleanup(struct omapfb_device *fbdev)
*/
static void omapfb_free_resources(struct omapfb_device *fbdev, int state)
{
int i;
switch (state) {
case OMAPFB_ACTIVE:
unregister_framebuffer(fbdev->fb_info);
for (i = 0; i < fbdev->mem_desc.region_cnt; i++)
unregister_framebuffer(fbdev->fb_info[i]);
case 7:
omapfb_unregister_sysfs(fbdev);
case 6:
fbdev->panel->disable();
fbdev->panel->disable(fbdev->panel);
case 5:
omapfb_set_update_mode(fbdev, OMAPFB_UPDATE_DISABLED);
case 4:
fbinfo_cleanup(fbdev);
planes_cleanup(fbdev);
case 3:
ctrl_cleanup(fbdev);
case 2:
fbdev->panel->cleanup();
fbdev->panel->cleanup(fbdev->panel);
case 1:
dev_set_drvdata(fbdev->dev, NULL);
framebuffer_release(fbdev->fb_info);
kfree(fbdev);
case 0:
/* nothing to free */
break;
......@@ -1202,13 +1303,9 @@ static int omapfb_find_ctrl(struct omapfb_device *fbdev)
char name[17];
int i;
conf = (struct omapfb_platform_data *)fbdev->dev->platform_data;
conf = fbdev->dev->platform_data;
fbdev->ctrl = NULL;
if (conf == NULL) {
DBGPRINT(1, "omap_lcd_config not found\n");
return -1;
}
strncpy(name, conf->lcd.ctrl_name, sizeof(name) - 1);
name[sizeof(name) - 1] = '\0';
......@@ -1219,7 +1316,7 @@ static int omapfb_find_ctrl(struct omapfb_device *fbdev)
}
for (i = 0; i < ARRAY_SIZE(ctrls); i++) {
DBGPRINT(1, "ctrl %s\n", ctrls[i]->name);
dev_dbg(fbdev->dev, "ctrl %s\n", ctrls[i]->name);
if (strcmp(ctrls[i]->name, name) == 0) {
fbdev->ctrl = ctrls[i];
break;
......@@ -1227,7 +1324,7 @@ static int omapfb_find_ctrl(struct omapfb_device *fbdev)
}
if (fbdev->ctrl == NULL) {
DBGPRINT(1, "ctrl %s not supported\n", name);
dev_dbg(fbdev->dev, "ctrl %s not supported\n", name);
return -1;
}
......@@ -1249,44 +1346,48 @@ static void check_required_callbacks(struct omapfb_device *fbdev)
/* Called by LDM binding to probe and attach a new device.
* Initialization sequence:
* 1. allocate system fb_info structure
* select panel type according to machine type
* 2. init LCD panel
* 1. allocate system omapfb_device structure
* 2. select controller type according to platform configuration
* init LCD panel
* 3. init LCD controller and LCD DMA
* 4. init system fb_info structure
* 5. init gfx DMA
* 4. init system fb_info structure for all planes
* 5. setup video mode for first plane and enable it
* 6. enable LCD panel
* start LCD frame transfer
* 7. register system fb_info structure
* 7. register sysfs attributes
* OMAPFB_ACTIVE: register system fb_info structure for all planes
*/
static int omapfb_do_probe(struct platform_device *pdev, struct lcd_panel *panel)
{
struct omapfb_device *fbdev = NULL;
struct fb_info *fbi;
int init_state;
unsigned long phz, hhz, vhz;
unsigned long vram;
int i;
int r = 0;
DBGENTER(1);
init_state = 0;
if (pdev->num_resources != 0) {
pr_err("probed for an unknown device\n");
dev_err(&pdev->dev, "probed for an unknown device\n");
r = -ENODEV;
goto cleanup;
}
fbi = framebuffer_alloc(sizeof(struct omapfb_device), &pdev->dev);
if (fbi == NULL) {
pr_err("unable to allocate memory for device info\n");
if (pdev->dev.platform_data == NULL) {
dev_err(&pdev->dev, "missing platform data\n");
r = -ENOENT;
goto cleanup;
}
fbdev = kzalloc(sizeof(struct omapfb_device), GFP_KERNEL);
if (fbdev == NULL) {
dev_err(&pdev->dev,
"unable to allocate memory for device info\n");
r = -ENOMEM;
goto cleanup;
}
init_state++;
fbdev = (struct omapfb_device *)fbi->par;
fbdev->fb_info = fbi;
fbdev->dev = &pdev->dev;
fbdev->panel = panel;
platform_set_drvdata(pdev, fbdev);
......@@ -1296,25 +1397,30 @@ static int omapfb_do_probe(struct platform_device *pdev, struct lcd_panel *panel
#ifdef CONFIG_ARCH_OMAP1
fbdev->int_ctrl = &omap1_int_ctrl;
#ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
fbdev->ext_if = &sossi_extif;
fbdev->ext_if = &omap1_ext_if;
#endif
#else /* OMAP2 */
fbdev->int_ctrl = &omap2_int_ctrl;
#ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
fbdev->ext_if = &rfbi_extif;
fbdev->ext_if = &omap2_ext_if;
#endif
#endif
if (omapfb_find_ctrl(fbdev) < 0) {
pr_err("LCD controller not found, board not supported\n");
dev_err(fbdev->dev,
"LCD controller not found, board not supported\n");
r = -ENODEV;
goto cleanup;
}
pr_info(MODULE_NAME ": configured for panel %s\n", fbdev->panel->name);
r = fbdev->panel->init(fbdev);
r = fbdev->panel->init(fbdev->panel, fbdev);
if (r)
goto cleanup;
pr_info("omapfb: configured for panel %s\n", fbdev->panel->name);
def_vxres = def_vxres ? : fbdev->panel->x_res;
def_vyres = def_vyres ? : fbdev->panel->y_res;
init_state++;
r = ctrl_init(fbdev);
......@@ -1322,15 +1428,9 @@ static int omapfb_do_probe(struct platform_device *pdev, struct lcd_panel *panel
goto cleanup;
init_state++;
/* We depend on doing this after ctrl_init, since it can redefine
* member functions.
*/
if (fbdev->ctrl->mmap)
omapfb_ops.fb_mmap = omapfb_mmap;
check_required_callbacks(fbdev);
r = fbinfo_init(fbdev);
r = planes_init(fbdev);
if (r)
goto cleanup;
init_state++;
......@@ -1338,23 +1438,25 @@ static int omapfb_do_probe(struct platform_device *pdev, struct lcd_panel *panel
#ifdef CONFIG_FB_OMAP_DMA_TUNE
/* Set DMA priority for EMIFF access to highest */
if (cpu_class_is_omap1())
omap_set_dma_priority(0, OMAP_DMA_PORT_EMIFF, 15);
omap_set_dma_priority(OMAP_DMA_PORT_EMIFF, 15);
#endif
r = ctrl_change_mode(fbdev);
r = ctrl_change_mode(fbdev->fb_info[0]);
if (r) {
pr_err("mode setting failed\n");
dev_err(fbdev->dev, "mode setting failed\n");
goto cleanup;
}
if (!manual_update)
omapfb_enable_plane(fbdev, OMAPFB_PLANE_GFX, 1);
/* GFX plane is enabled by default */
r = fbdev->ctrl->enable_plane(OMAPFB_PLANE_GFX, 1);
if (r)
goto cleanup;
omapfb_set_update_mode(fbdev, manual_update ?
OMAPFB_MANUAL_UPDATE : OMAPFB_AUTO_UPDATE);
init_state++;
r = fbdev->panel->enable();
r = fbdev->panel->enable(fbdev->panel);
if (r)
goto cleanup;
init_state++;
......@@ -1364,11 +1466,16 @@ static int omapfb_do_probe(struct platform_device *pdev, struct lcd_panel *panel
goto cleanup;
init_state++;
r = register_framebuffer(fbdev->fb_info);
vram = 0;
for (i = 0; i < fbdev->mem_desc.region_cnt; i++) {
r = register_framebuffer(fbdev->fb_info[i]);
if (r != 0) {
pr_err("register_framebuffer failed\n");
dev_err(fbdev->dev,
"registering framebuffer %d failed\n", i);
goto cleanup;
}
vram += fbdev->mem_desc.region[i].size;
}
fbdev->state = OMAPFB_ACTIVE;
......@@ -1379,18 +1486,17 @@ static int omapfb_do_probe(struct platform_device *pdev, struct lcd_panel *panel
omapfb_dev = fbdev;
pr_info(MODULE_NAME ": initialized vram=%lu "
"pixclock %lu kHz hfreq %lu.%lu kHz vfreq %lu.%lu Hz\n",
fbdev->vram_size,
pr_info("omapfb: Framebuffer initialized. Total vram %lu planes %d\n",
vram, fbdev->mem_desc.region_cnt);
pr_info("omapfb: Pixclock %lu kHz hfreq %lu.%lu kHz "
"vfreq %lu.%lu Hz\n",
phz / 1000, hhz / 10000, hhz % 10, vhz / 10, vhz % 10);
DBGLEAVE(1);
return 0;
cleanup:
omapfb_free_resources(fbdev, init_state);
DBGLEAVE(1);
return r;
}
......@@ -1398,7 +1504,7 @@ static int omapfb_probe(struct platform_device *pdev)
{
BUG_ON(fbdev_pdev != NULL);
DBGENTER(1);
/* Delay actual initialization until the LCD is registered */
fbdev_pdev = pdev;
if (fbdev_panel != NULL)
omapfb_do_probe(fbdev_pdev, fbdev_panel);
......@@ -1409,7 +1515,6 @@ void omapfb_register_panel(struct lcd_panel *panel)
{
BUG_ON(fbdev_panel != NULL);
DBGENTER(1);
fbdev_panel = panel;
if (fbdev_pdev != NULL)
omapfb_do_probe(fbdev_pdev, fbdev_panel);
......@@ -1421,13 +1526,11 @@ static int omapfb_remove(struct platform_device *pdev)
struct omapfb_device *fbdev = platform_get_drvdata(pdev);
enum omapfb_state saved_state = fbdev->state;
DBGENTER(1);
/* FIXME: wait till completion of pending events */
fbdev->state = OMAPFB_DISABLED;
omapfb_free_resources(fbdev, saved_state);
DBGLEAVE(1);
return 0;
}
......@@ -1436,11 +1539,7 @@ static int omapfb_suspend(struct platform_device *pdev, pm_message_t mesg)
{
struct omapfb_device *fbdev = platform_get_drvdata(pdev);
DBGENTER(1);
omapfb_blank(VESA_POWERDOWN, fbdev->fb_info);
DBGLEAVE(1);
omapfb_blank(VESA_POWERDOWN, fbdev->fb_info[0]);
return 0;
}
......@@ -1450,11 +1549,7 @@ static int omapfb_resume(struct platform_device *pdev)
{
struct omapfb_device *fbdev = platform_get_drvdata(pdev);
DBGENTER(1);
omapfb_blank(VESA_NO_BLANKING, fbdev->fb_info);
DBGLEAVE(1);
omapfb_blank(VESA_NO_BLANKING, fbdev->fb_info[0]);
return 0;
}
......@@ -1464,7 +1559,7 @@ static struct platform_driver omapfb_driver = {
.suspend = omapfb_suspend,
.resume = omapfb_resume,
.driver = {
.name = OMAPFB_DRIVER,
.name = MODULE_NAME,
.owner = THIS_MODULE,
},
};
......@@ -1477,32 +1572,35 @@ static int __init omapfb_setup(char *options)
char *this_opt = NULL;
int r = 0;
DBGENTER(1);
pr_debug("omapfb: options %s\n", options);
if (!options || !*options)
goto exit;
return 0;
while (!r && (this_opt = strsep(&options, ",")) != NULL) {
if (!strncmp(this_opt, "accel", 5))
def_accel = 1;
else if (!strncmp(this_opt, "vram:", 5)) {
char *suffix;
def_vram = (simple_strtoul(this_opt + 5, &suffix, 0));
unsigned long vram;
vram = (simple_strtoul(this_opt + 5, &suffix, 0));
switch (suffix[0]) {
case '\0':
break;
case 'm':
case 'M':
def_vram *= 1024;
vram *= 1024;
/* Fall through */
case 'k':
case 'K':
def_vram *= 1024;
vram *= 1024;
break;
default:
pr_err("invalid vram suffix\n");
pr_debug("omapfb: invalid vram suffix %c\n",
suffix[0]);
r = -1;
}
def_vram[def_vram_cnt++] = vram;
}
else if (!strncmp(this_opt, "vxres:", 6))
def_vxres = simple_strtoul(this_opt + 6, NULL, 0);
......@@ -1515,12 +1613,11 @@ static int __init omapfb_setup(char *options)
else if (!strncmp(this_opt, "manual_update", 13))
manual_update = 1;
else {
pr_err("invalid option\n");
pr_debug("omapfb: invalid option\n");
r = -1;
}
}
exit:
DBGLEAVE(1);
return r;
}
......@@ -1529,44 +1626,29 @@ exit:
/* Register both the driver and the device */
static int __init omapfb_init(void)
{
int r = 0;
DBGENTER(1);
#ifndef MODULE
{
char *option;
if (fb_get_options("omapfb", &option)) {
r = -ENODEV;
goto exit;
}
if (fb_get_options("omapfb", &option))
return -ENODEV;
omapfb_setup(option);
}
#endif
/* Register the driver with LDM */
if (platform_driver_register(&omapfb_driver)) {
pr_err("failed to register omapfb driver\n");
r = -ENODEV;
goto exit;
pr_debug("failed to register omapfb driver\n");
return -ENODEV;
}
exit:
DBGLEAVE(1);
return r;
return 0;
}
static void __exit omapfb_cleanup(void)
{
DBGENTER(1);
platform_driver_unregister(&omapfb_driver);
DBGLEAVE(1);
}
module_param_named(accel, def_accel, uint, 0664);
module_param_named(vram, def_vram, ulong, 0664);
module_param_array_named(vram, def_vram, ulong, &def_vram_cnt, 0664);
module_param_named(vxres, def_vxres, long, 0664);
module_param_named(vyres, def_vyres, long, 0664);
module_param_named(rotate, def_rotate, uint, 0664);
......
......@@ -21,7 +21,6 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/i2c.h>
......@@ -35,14 +34,6 @@
#include "dispc.h"
/* #define OMAPFB_DBG 1 */
#include "debug.h"
#define MODULE_NAME "omapfb-rfbi"
#define pr_err(fmt, args...) printk(KERN_ERR MODULE_NAME ": " fmt, ## args)
#define RFBI_BASE 0x48050800
#define RFBI_REVISION 0x0000
#define RFBI_SYSCONFIG 0x0010
......@@ -73,10 +64,9 @@ static struct {
void *lcdc_callback_data;
unsigned long l4_khz;
int bits_per_cycle;
struct omapfb_device *fbdev;
} rfbi;
struct lcd_ctrl_extif rfbi_extif;
static inline void rfbi_write_reg(int idx, u32 val)
{
__raw_writel(val, rfbi.base + idx);
......@@ -87,7 +77,7 @@ static inline u32 rfbi_read_reg(int idx)
return __raw_readl(rfbi.base + idx);
}
#ifdef OMAPFB_DBG
#ifdef VERBOSE
static void rfbi_print_timings(void)
{
u32 l;
......@@ -98,16 +88,20 @@ static void rfbi_print_timings(void)
if (l & (1 << 4))
time *= 2;
DBGPRINT(1, "Tick time %u ps\n", time);
dev_dbg(rfbi.fbdev->dev, "Tick time %u ps\n", time);
l = rfbi_read_reg(RFBI_ONOFF_TIME0);
DBGPRINT(1, "CSONTIME %d, CSOFFTIME %d, WEONTIME %d, WEOFFTIME %d, "
dev_dbg(rfbi.fbdev->dev,
"CSONTIME %d, CSOFFTIME %d, WEONTIME %d, WEOFFTIME %d, "
"REONTIME %d, REOFFTIME %d\n",
l & 0x0f, (l >> 4) & 0x3f, (l >> 10) & 0x0f, (l >> 14) & 0x3f,
(l >> 20) & 0x0f, (l >> 24) & 0x3f);
l = rfbi_read_reg(RFBI_CYCLE_TIME0);
DBGPRINT(1, "WECYCLETIME %d, RECYCLETIME %d, CSPULSEWIDTH %d, "
dev_dbg(rfbi.fbdev->dev,
"WECYCLETIME %d, RECYCLETIME %d, CSPULSEWIDTH %d, "
"ACCESSTIME %d\n",
(l & 0x3f), (l >> 6) & 0x3f, (l >> 12) & 0x3f, (l >> 22) & 0x3f);
(l & 0x3f), (l >> 6) & 0x3f, (l >> 12) & 0x3f,
(l >> 22) & 0x3f);
}
#else
static void rfbi_print_timings(void) {}
......@@ -341,20 +335,18 @@ static void rfbi_set_bits_per_cycle(int bpc)
rfbi.bits_per_cycle = bpc;
}
static int rfbi_init(void)
static int rfbi_init(struct omapfb_device *fbdev)
{
u32 l;
int r;
struct clk *dss_ick;
rfbi.fbdev = fbdev;
rfbi.base = io_p2v(RFBI_BASE);
l = rfbi_read_reg(RFBI_REVISION);
pr_info(MODULE_NAME ": version %d.%d\n", (l >> 4) & 0x0f, l & 0x0f);
dss_ick = clk_get(NULL, "dss_ick");
if (IS_ERR(dss_ick)) {
pr_err("can't get dss_ick\n");
dev_err(fbdev->dev, "can't get dss_ick\n");
return PTR_ERR(dss_ick);
}
......@@ -383,10 +375,14 @@ static int rfbi_init(void)
rfbi_write_reg(RFBI_CONTROL, l);
if ((r = omap_dispc_request_irq(rfbi_dma_callback, NULL)) < 0) {
pr_err("can't get DISPC irq\n");
dev_err(fbdev->dev, "can't get DISPC irq\n");
return r;
}
l = rfbi_read_reg(RFBI_REVISION);
pr_info("omapfb: RFBI version %d.%d initialized\n",
(l >> 4) & 0x0f, l & 0x0f);
return 0;
}
......@@ -395,7 +391,7 @@ static void rfbi_cleanup(void)
omap_dispc_free_irq();
}
struct lcd_ctrl_extif rfbi_extif = {
const struct lcd_ctrl_extif omap2_ext_if = {
.init = rfbi_init,
.cleanup = rfbi_cleanup,
.get_clk_info = rfbi_get_clk_info,
......@@ -406,6 +402,7 @@ struct lcd_ctrl_extif rfbi_extif = {
.read_data = rfbi_read_data,
.write_data = rfbi_write_data,
.transfer_area = rfbi_transfer_area,
.max_transmit_size = (u32)~0,
};
......@@ -20,7 +20,6 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/mm.h>
......@@ -33,10 +32,6 @@
#include "lcdc.h"
/* #define OMAPFB_DBG 1 */
#include "debug.h"
#define MODULE_NAME "omapfb-sossi"
#define OMAP_SOSSI_BASE 0xfffbac00
......@@ -60,10 +55,8 @@
#define SOSSI_MAX_XMIT_BYTES (512 * 1024)
#define pr_err(fmt, args...) printk(KERN_ERR MODULE_NAME ": " fmt, ## args)
static struct sossi {
int base;
static struct {
void __iomem *base;
unsigned long dpll_khz;
int bus_pick_width;
void (*lcdc_callback)(void *data);
......@@ -76,9 +69,10 @@ static struct sossi {
* the timings
*/
int last_access;
} sossi;
struct lcd_ctrl_extif sossi_extif;
struct omapfb_device *fbdev;
struct lcd_ctrl_extif *extif;
} sossi;
static inline u32 sossi_read_reg(int reg)
{
......@@ -126,86 +120,8 @@ static void sossi_clear_bits(int reg, u32 bits)
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(KERN_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;
}
static u32 ps_to_sossi_ticks(u32 ps, int div)
{
u32 clk_period = KHZ_TO_PS(sossi.dpll_khz) * div;
......@@ -299,49 +215,14 @@ static int calc_wr_timings(struct extif_timings *t)
return 0;
}
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 - 1;
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 _set_timing(int div, int tw0, int tw1)
{
u32 l;
DBGPRINT(2, "Using TW0 = %d, TW1 = %d, div = %d\n",
#ifdef VERBOSE
dev_dbg(sossi.fbdev->dev, "Using TW0 = %d, TW1 = %d, div = %d\n",
tw0 + 1, tw1 + 1, div + 1);
#endif
l = omap_readl(MOD_CONF_CTRL_1);
l &= ~(7 << 17);
......@@ -363,36 +244,6 @@ static inline void set_timing(int access)
}
}
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 */
......@@ -446,6 +297,78 @@ static void set_cycles(unsigned int len)
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 - 1;
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 = KHZ_TO_PS(sossi.dpll_khz);
*max_clk_div = 8;
}
static void sossi_set_bits_per_cycle(int bpc)
{
u32 l;
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;
}
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_write_command(const void *data, unsigned int len)
{
set_timing(WR_ACCESS);
......@@ -483,8 +406,6 @@ static void sossi_transfer_area(int width, int height,
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();
}
......@@ -521,7 +442,79 @@ static void sossi_read_data(void *data, unsigned int len)
sossi_stop_transfer();
}
struct lcd_ctrl_extif sossi_extif = {
static int sossi_init(struct omapfb_device *fbdev)
{
u32 l, k;
struct clk *dpll_clk;
int r;
sossi.fbdev = fbdev;
sossi.base = (void __iomem *)IO_ADDRESS(OMAP_SOSSI_BASE);
dpll_clk = clk_get(fbdev->dev, "ck_dpll1");
if (IS_ERR(dpll_clk)) {
dev_err(fbdev->dev, "can't get dpll1 clock\n");
return PTR_ERR(dpll_clk);
}
sossi.dpll_khz = clk_get_rate(dpll_clk) / 1000;
clk_put(dpll_clk);
/* 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) {
dev_err(fbdev->dev,
"invalid SoSSI sync pattern: %08x, %08x\n", l, k);
return -ENODEV;
}
if ((r = omap_lcdc_set_dma_callback(sossi_dma_callback, NULL)) < 0) {
dev_err(fbdev->dev, "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("omapfb: 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);
return 0;
}
static void sossi_cleanup(void)
{
omap_lcdc_free_dma_callback();
}
const struct lcd_ctrl_extif omap1_ext_if = {
.init = sossi_init,
.cleanup = sossi_cleanup,
.get_clk_info = sossi_get_clk_info,
......@@ -532,4 +525,7 @@ struct lcd_ctrl_extif sossi_extif = {
.read_data = sossi_read_data,
.write_data = sossi_write_data,
.transfer_area = sossi_transfer_area,
.max_transmit_size = SOSSI_MAX_XMIT_BYTES,
};
......@@ -24,6 +24,9 @@
#ifndef __OMAPFB_H
#define __OMAPFB_H
#include <asm/ioctl.h>
#include <asm/types.h>
/* IOCTL commands. */
#define OMAP_IOW(num, dtype) _IOW('O', num, dtype)
......@@ -36,14 +39,14 @@
#define OMAPFB_VSYNC OMAP_IO(38)
#define OMAPFB_SET_UPDATE_MODE OMAP_IOW(40, int)
#define OMAPFB_UPDATE_WINDOW_OLD OMAP_IOW(41, struct omapfb_update_window_old)
#define OMAPFB_GET_CAPS OMAP_IOR(42, unsigned long)
#define OMAPFB_GET_UPDATE_MODE OMAP_IOW(43, int)
#define OMAPFB_LCD_TEST OMAP_IOW(45, int)
#define OMAPFB_CTRL_TEST OMAP_IOW(46, int)
#define OMAPFB_UPDATE_WINDOW OMAP_IOW(47, struct omapfb_update_window)
#define OMAPFB_SETUP_PLANE OMAP_IOW(48, struct omapfb_setup_plane)
#define OMAPFB_ENABLE_PLANE OMAP_IOW(49, struct omapfb_enable_plane)
#define OMAPFB_SET_COLOR_KEY OMAP_IOW(50, struct omapfb_color_key)
#define OMAPFB_GET_COLOR_KEY OMAP_IOW(51, struct omapfb_color_key)
#define OMAPFB_SETUP_PLANE OMAP_IOW(52, struct omapfb_plane_info)
#define OMAPFB_QUERY_PLANE OMAP_IOW(53, struct omapfb_plane_info)
#define OMAPFB_CAPS_GENERIC_MASK 0x00000fff
#define OMAPFB_CAPS_LCDC_MASK 0x00fff000
......@@ -56,6 +59,9 @@
#define OMAPFB_FORMAT_MASK 0x00ff
#define OMAPFB_FORMAT_FLAG_DOUBLE 0x0100
#define OMAPFB_EVENT_READY 1
#define OMAPFB_EVENT_DISABLED 2
enum omapfb_color_format {
OMAPFB_COLOR_RGB565 = 0,
OMAPFB_COLOR_YUV422,
......@@ -65,6 +71,7 @@ enum omapfb_color_format {
OMAPFB_COLOR_CLUT_2BPP,
OMAPFB_COLOR_CLUT_1BPP,
OMAPFB_COLOR_RGB444,
OMAPFB_COLOR_YUY422,
};
struct omapfb_update_window {
......@@ -89,18 +96,16 @@ enum omapfb_channel_out {
OMAPFB_CHANNEL_OUT_DIGIT,
};
struct omapfb_setup_plane {
__u8 plane;
struct omapfb_plane_info {
__u32 pos_x;
__u32 pos_y;
__u8 enabled;
__u8 channel_out;
__u32 offset;
__u32 pos_x, pos_y;
__u32 width, height;
__u32 color_mode;
};
struct omapfb_enable_plane {
__u8 plane;
__u8 enable;
__u8 mirror;
__u8 reserved1;
__u32 out_width;
__u32 out_height;
__u32 reserved2[12];
};
enum omapfb_color_key_type {
......@@ -142,6 +147,9 @@ enum omapfb_update_mode {
#define OMAP_LCDC_PANEL_TFT 0x0100
#define OMAPFB_PLANE_XRES_MIN 8
#define OMAPFB_PLANE_YRES_MIN 8
#ifdef CONFIG_ARCH_OMAP1
#define OMAPFB_PLANE_NUM 1
#else
......@@ -170,15 +178,17 @@ struct lcd_panel {
int pcd; /* pixel clock divider.
Obsolete use pixel_clock instead */
int (*init) (struct omapfb_device *fbdev);
void (*cleanup) (void);
int (*enable) (void);
void (*disable) (void);
unsigned long (*get_caps) (void);
int (*set_bklight_level)(unsigned int level);
unsigned int (*get_bklight_level)(void);
unsigned int (*get_bklight_max) (void);
int (*run_test) (int test_num);
int (*init) (struct lcd_panel *panel,
struct omapfb_device *fbdev);
void (*cleanup) (struct lcd_panel *panel);
int (*enable) (struct lcd_panel *panel);
void (*disable) (struct lcd_panel *panel);
unsigned long (*get_caps) (struct lcd_panel *panel);
int (*set_bklight_level)(struct lcd_panel *panel,
unsigned int level);
unsigned int (*get_bklight_level)(struct lcd_panel *panel);
unsigned int (*get_bklight_max) (struct lcd_panel *panel);
int (*run_test) (struct lcd_panel *panel, int test_num);
};
struct omapfb_device;
......@@ -203,7 +213,7 @@ struct extif_timings {
};
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);
int (*convert_timings) (struct extif_timings *timings);
......@@ -214,30 +224,41 @@ struct lcd_ctrl_extif {
void (*write_data) (const void *buf, unsigned int len);
void (*transfer_area) (int width, int height,
void (callback)(void * data), void *data);
unsigned long max_transmit_size;
};
struct omapfb_notifier_block {
struct notifier_block nb;
void *data;
int plane_idx;
};
typedef int (*omapfb_notifier_callback_t)(struct omapfb_notifier_block *,
typedef int (*omapfb_notifier_callback_t)(struct notifier_block *,
unsigned long event,
struct omapfb_device *fbdev);
void *fbi);
struct omapfb_mem_region {
dma_addr_t paddr;
void *vaddr;
unsigned long size;
int alloc:1;
};
struct omapfb_mem_desc {
int region_cnt;
struct omapfb_mem_region region[OMAPFB_PLANE_NUM];
};
struct lcd_ctrl {
const char *name;
void *data;
int (*init) (struct omapfb_device *fbdev,
int ext_mode, int req_vram_size);
int ext_mode,
struct omapfb_mem_desc *req_md);
void (*cleanup) (void);
void (*bind_client) (struct omapfb_notifier_block *nb);
void (*get_vram_layout)(unsigned long *size,
void **virt_base,
dma_addr_t *phys_base);
int (*mmap) (struct vm_area_struct *vma);
unsigned long (*get_caps) (void);
int (*set_update_mode)(enum omapfb_update_mode mode);
enum omapfb_update_mode (*get_update_mode)(void);
......@@ -246,8 +267,12 @@ struct lcd_ctrl {
int screen_width,
int pos_x, int pos_y, int width,
int height, int color_mode);
int (*set_scale) (int plane,
int orig_width, int orig_height,
int out_width, int out_height);
int (*enable_plane) (int plane, int enable);
int (*update_window) (struct omapfb_update_window *win,
int (*update_window) (struct fb_info *fbi,
struct omapfb_update_window *win,
void (*callback)(void *),
void *callback_data);
void (*sync) (void);
......@@ -258,6 +283,7 @@ struct lcd_ctrl {
u16 blue, u16 transp,
int update_hw_mem);
int (*set_color_key) (struct omapfb_color_key *ck);
int (*get_color_key) (struct omapfb_color_key *ck);
};
......@@ -267,19 +293,20 @@ enum omapfb_state {
OMAPFB_ACTIVE = 100
};
struct omapfb_plane_struct {
int idx;
struct omapfb_plane_info info;
enum omapfb_color_format color_mode;
struct omapfb_device *fbdev;
};
struct omapfb_device {
int state;
int ext_lcdc; /* Using external
LCD controller */
struct mutex rqueue_mutex;
void *vram_virt_base;
dma_addr_t vram_phys_base;
unsigned long vram_size;
int color_mode;
int palette_size;
int mirror;
u32 pseudo_palette[17];
struct lcd_panel *panel; /* LCD panel */
......@@ -287,19 +314,17 @@ struct omapfb_device {
struct lcd_ctrl *int_ctrl; /* internal LCD ctrl */
struct lcd_ctrl_extif *ext_if; /* LCD ctrl external
interface */
struct fb_info *fb_info;
struct device *dev;
struct omapfb_mem_desc mem_desc;
struct fb_info *fb_info[OMAPFB_PLANE_NUM];
};
struct omapfb_platform_data {
struct omap_lcd_config lcd;
struct omap_fbmem_config fbmem;
struct omapfb_mem_desc mem_desc;
};
#define OMAPFB_EVENT_READY 1
#define OMAPFB_EVENT_DISABLED 2
#ifdef CONFIG_ARCH_OMAP1
extern struct lcd_ctrl omap1_lcd_ctrl;
#else
......@@ -314,7 +339,8 @@ extern int omapfb_register_client(struct omapfb_notifier_block *nb,
omapfb_notifier_callback_t callback,
void *callback_data);
extern int omapfb_unregister_client(struct omapfb_notifier_block *nb);
extern int omapfb_update_window_async(struct omapfb_update_window *win,
extern int omapfb_update_window_async(struct fb_info *fbi,
struct omapfb_update_window *win,
void (*callback)(void *),
void *callback_data);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment