From dcdf2f7e7e154957f913e5468e3715e1a0401138 Mon Sep 17 00:00:00 2001 From: Anatolij Gustschin Date: Fri, 13 May 2011 11:05:08 +0200 Subject: [PATCH 1/5] video: mb862xxfb: correct fix.smem_len field initialization Initialize smem_len field to the actual frame buffer size and not to the whole video RAM size. This prevents overwriting other video memory (which could be used by other layers, cursors or accelerated drivers) by frame buffer applications relying on fix.smem_len. Signed-off-by: Anatolij Gustschin --- drivers/video/mb862xx/mb862xxfb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/video/mb862xx/mb862xxfb.c b/drivers/video/mb862xx/mb862xxfb.c index c76e663a6cd4..825795894daa 100644 --- a/drivers/video/mb862xx/mb862xxfb.c +++ b/drivers/video/mb862xx/mb862xxfb.c @@ -336,7 +336,6 @@ static int mb862xxfb_init_fbinfo(struct fb_info *fbi) strcpy(fbi->fix.id, DRV_NAME); fbi->fix.smem_start = (unsigned long)par->fb_base_phys; - fbi->fix.smem_len = par->mapped_vram; fbi->fix.mmio_start = (unsigned long)par->mmio_base_phys; fbi->fix.mmio_len = par->mmio_len; fbi->fix.accel = FB_ACCEL_NONE; @@ -420,6 +419,7 @@ static int mb862xxfb_init_fbinfo(struct fb_info *fbi) FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; fbi->fix.line_length = (fbi->var.xres_virtual * fbi->var.bits_per_pixel) / 8; + fbi->fix.smem_len = fbi->fix.line_length * fbi->var.yres_virtual; return 0; } From 3cadf9455c31de340ed77394dfad330caeb66b58 Mon Sep 17 00:00:00 2001 From: Anatolij Gustschin Date: Fri, 13 May 2011 14:12:15 +0200 Subject: [PATCH 2/5] video: mb862xxfb: use pre-initialized configuration for PCI GDCs If the bootloader has already initialized the display controller, do not re-initialize it in the driver. Take over the bootloader's configuration instead. This is already supported for non PCI GDCs Lime and Mint. Add this functionality for PCI GDCs Coral-P and Coral-PA. It is useful to avoid flicker and also avoids unneeded init delays while booting. Signed-off-by: Anatolij Gustschin --- drivers/video/mb862xx/mb862xxfb.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/drivers/video/mb862xx/mb862xxfb.c b/drivers/video/mb862xx/mb862xxfb.c index 825795894daa..a1b81e73394c 100644 --- a/drivers/video/mb862xx/mb862xxfb.c +++ b/drivers/video/mb862xx/mb862xxfb.c @@ -746,13 +746,21 @@ static int coralp_init(struct mb862xxfb_par *par) cn = (ver & GC_CID_CNAME_MSK) >> 8; ver = ver & GC_CID_VERSION_MSK; if (cn == 3) { + unsigned long reg; + dev_info(par->dev, "Fujitsu Coral-%s GDC Rev.%d found\n",\ (ver == 6) ? "P" : (ver == 8) ? "PA" : "?", par->pdev->revision); - outreg(host, GC_CCF, GC_CCF_CGE_166 | GC_CCF_COT_133); - udelay(200); - outreg(host, GC_MMR, GC_MMR_CORALP_EVB_VAL); - udelay(10); + reg = inreg(disp, GC_DCM1); + if (reg & GC_DCM01_DEN && reg & GC_DCM01_L0E) + par->pre_init = 1; + + if (!par->pre_init) { + outreg(host, GC_CCF, GC_CCF_CGE_166 | GC_CCF_COT_133); + udelay(200); + outreg(host, GC_MMR, GC_MMR_CORALP_EVB_VAL); + udelay(10); + } /* Clear interrupt status */ outreg(host, GC_IST, 0); } else { From 12ed0c4baa4144ab3560ae793b5120316d74c0fe Mon Sep 17 00:00:00 2001 From: Anatolij Gustschin Date: Fri, 13 May 2011 12:52:29 +0200 Subject: [PATCH 3/5] video: mb862xxfb: relocate register space to get contiguous vram By default the GDC registers are located in the middle of the 64MiB area for video RAM and registers. When 32MiB VRAM or more is used, relocate the register space to the top of the 64MiB space so that we get the contiguous VRAM for GDC frame buffer layers, drawing frames, capture and cursor buffers. Signed-off-by: Anatolij Gustschin --- drivers/video/mb862xx/mb862xx_reg.h | 6 ++---- drivers/video/mb862xx/mb862xxfb.c | 14 +++++++++++++- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/drivers/video/mb862xx/mb862xx_reg.h b/drivers/video/mb862xx/mb862xx_reg.h index 2ba65e118500..737fc011caff 100644 --- a/drivers/video/mb862xx/mb862xx_reg.h +++ b/drivers/video/mb862xx/mb862xx_reg.h @@ -5,11 +5,8 @@ #ifndef _MB862XX_REG_H #define _MB862XX_REG_H -#ifdef MB862XX_MMIO_BOTTOM -#define MB862XX_MMIO_BASE 0x03fc0000 -#else #define MB862XX_MMIO_BASE 0x01fc0000 -#endif +#define MB862XX_MMIO_HIGH_BASE 0x03fc0000 #define MB862XX_I2C_BASE 0x0000c000 #define MB862XX_DISP_BASE 0x00010000 #define MB862XX_CAP_BASE 0x00018000 @@ -23,6 +20,7 @@ #define GC_IMASK 0x00000024 #define GC_SRST 0x0000002c #define GC_CCF 0x00000038 +#define GC_RSW 0x0000005c #define GC_CID 0x000000f0 #define GC_REVISION 0x00000084 diff --git a/drivers/video/mb862xx/mb862xxfb.c b/drivers/video/mb862xx/mb862xxfb.c index a1b81e73394c..ffb6a2c36d3c 100644 --- a/drivers/video/mb862xx/mb862xxfb.c +++ b/drivers/video/mb862xx/mb862xxfb.c @@ -742,6 +742,12 @@ static int coralp_init(struct mb862xxfb_par *par) par->refclk = GC_DISP_REFCLK_400; + if (par->mapped_vram >= 0x2000000) { + /* relocate gdc registers space */ + writel(1, par->fb_base + MB862XX_MMIO_BASE + GC_RSW); + udelay(1); /* wait at least 20 bus cycles */ + } + ver = inreg(host, GC_CID); cn = (ver & GC_CID_CNAME_MSK) >> 8; ver = ver & GC_CID_VERSION_MSK; @@ -907,7 +913,13 @@ static int __devinit mb862xx_pci_probe(struct pci_dev *pdev, case PCI_DEVICE_ID_FUJITSU_CORALPA: par->fb_base_phys = pci_resource_start(par->pdev, 0); par->mapped_vram = CORALP_MEM_SIZE; - par->mmio_base_phys = par->fb_base_phys + MB862XX_MMIO_BASE; + if (par->mapped_vram >= 0x2000000) { + par->mmio_base_phys = par->fb_base_phys + + MB862XX_MMIO_HIGH_BASE; + } else { + par->mmio_base_phys = par->fb_base_phys + + MB862XX_MMIO_BASE; + } par->mmio_len = MB862XX_MMIO_SIZE; par->type = BT_CORALP; break; From f8a6b1f44833a4eb4c323b8b71fc592646212090 Mon Sep 17 00:00:00 2001 From: Anatolij Gustschin Date: Tue, 24 May 2011 15:19:48 +0200 Subject: [PATCH 4/5] video: mb862xx: add support for controller's I2C bus adapter Add adapter driver for I2C adapter in Coral-P(A)/Lime GDCs. So we can easily access devices on controller's I2C bus using i2c-dev interface. Signed-off-by: Anatolij Gustschin --- drivers/video/Kconfig | 9 + drivers/video/mb862xx/Makefile | 5 +- drivers/video/mb862xx/mb862xx-i2c.c | 177 ++++++++++++++++++ drivers/video/mb862xx/mb862xx_reg.h | 21 +++ drivers/video/mb862xx/mb862xxfb.h | 9 + .../mb862xx/{mb862xxfb.c => mb862xxfbdrv.c} | 4 + 6 files changed, 224 insertions(+), 1 deletion(-) create mode 100644 drivers/video/mb862xx/mb862xx-i2c.c rename drivers/video/mb862xx/{mb862xxfb.c => mb862xxfbdrv.c} (99%) diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 7326962565ce..549b960667c8 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -2294,6 +2294,15 @@ config FB_MB862XX_LIME endchoice +config FB_MB862XX_I2C + bool "Support I2C bus on MB862XX GDC" + depends on FB_MB862XX && I2C + default y + help + Selecting this option adds Coral-P(A)/Lime GDC I2C bus adapter + driver to support accessing I2C devices on controller's I2C bus. + These are usually some video decoder chips. + config FB_EP93XX tristate "EP93XX frame buffer support" depends on FB && ARCH_EP93XX diff --git a/drivers/video/mb862xx/Makefile b/drivers/video/mb862xx/Makefile index d7777714166b..5707ed0e31a7 100644 --- a/drivers/video/mb862xx/Makefile +++ b/drivers/video/mb862xx/Makefile @@ -2,4 +2,7 @@ # Makefile for the MB862xx framebuffer driver # -obj-$(CONFIG_FB_MB862XX) := mb862xxfb.o mb862xxfb_accel.o +obj-$(CONFIG_FB_MB862XX) += mb862xxfb.o + +mb862xxfb-y := mb862xxfbdrv.o mb862xxfb_accel.o +mb862xxfb-$(CONFIG_FB_MB862XX_I2C) += mb862xx-i2c.o diff --git a/drivers/video/mb862xx/mb862xx-i2c.c b/drivers/video/mb862xx/mb862xx-i2c.c new file mode 100644 index 000000000000..cb77d3b4657d --- /dev/null +++ b/drivers/video/mb862xx/mb862xx-i2c.c @@ -0,0 +1,177 @@ +/* + * Coral-P(A)/Lime I2C adapter driver + * + * (C) 2011 DENX Software Engineering, Anatolij Gustschin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include +#include +#include + +#include "mb862xxfb.h" +#include "mb862xx_reg.h" + +static int mb862xx_i2c_wait_event(struct i2c_adapter *adap) +{ + struct mb862xxfb_par *par = adap->algo_data; + u32 reg; + + do { + udelay(1); + reg = inreg(i2c, GC_I2C_BCR); + if (reg & (I2C_INT | I2C_BER)) + break; + } while (1); + + return (reg & I2C_BER) ? 0 : 1; +} + +static int mb862xx_i2c_do_address(struct i2c_adapter *adap, int addr) +{ + struct mb862xxfb_par *par = adap->algo_data; + + outreg(i2c, GC_I2C_DAR, addr); + outreg(i2c, GC_I2C_CCR, I2C_CLOCK_AND_ENABLE); + outreg(i2c, GC_I2C_BCR, par->i2c_rs ? I2C_REPEATED_START : I2C_START); + if (!mb862xx_i2c_wait_event(adap)) + return -EIO; + par->i2c_rs = !(inreg(i2c, GC_I2C_BSR) & I2C_LRB); + return par->i2c_rs; +} + +static int mb862xx_i2c_write_byte(struct i2c_adapter *adap, u8 byte) +{ + struct mb862xxfb_par *par = adap->algo_data; + + outreg(i2c, GC_I2C_DAR, byte); + outreg(i2c, GC_I2C_BCR, I2C_START); + if (!mb862xx_i2c_wait_event(adap)) + return -EIO; + return !(inreg(i2c, GC_I2C_BSR) & I2C_LRB); +} + +static int mb862xx_i2c_read_byte(struct i2c_adapter *adap, u8 *byte, int last) +{ + struct mb862xxfb_par *par = adap->algo_data; + + outreg(i2c, GC_I2C_BCR, I2C_START | (last ? 0 : I2C_ACK)); + if (!mb862xx_i2c_wait_event(adap)) + return 0; + *byte = inreg(i2c, GC_I2C_DAR); + return 1; +} + +void mb862xx_i2c_stop(struct i2c_adapter *adap) +{ + struct mb862xxfb_par *par = adap->algo_data; + + outreg(i2c, GC_I2C_BCR, I2C_STOP); + outreg(i2c, GC_I2C_CCR, I2C_DISABLE); + par->i2c_rs = 0; +} + +static int mb862xx_i2c_read(struct i2c_adapter *adap, struct i2c_msg *m) +{ + int i, ret = 0; + int last = m->len - 1; + + for (i = 0; i < m->len; i++) { + if (!mb862xx_i2c_read_byte(adap, &m->buf[i], i == last)) { + ret = -EIO; + break; + } + } + return ret; +} + +static int mb862xx_i2c_write(struct i2c_adapter *adap, struct i2c_msg *m) +{ + int i, ret = 0; + + for (i = 0; i < m->len; i++) { + if (!mb862xx_i2c_write_byte(adap, m->buf[i])) { + ret = -EIO; + break; + } + } + return ret; +} + +static int mb862xx_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, + int num) +{ + struct mb862xxfb_par *par = adap->algo_data; + struct i2c_msg *m; + int addr; + int i = 0, err = 0; + + dev_dbg(par->dev, "%s: %d msgs\n", __func__, num); + + for (i = 0; i < num; i++) { + m = &msgs[i]; + if (!m->len) { + dev_dbg(par->dev, "%s: null msgs\n", __func__); + continue; + } + addr = m->addr; + if (m->flags & I2C_M_RD) + addr |= 1; + + err = mb862xx_i2c_do_address(adap, addr); + if (err < 0) + break; + if (m->flags & I2C_M_RD) + err = mb862xx_i2c_read(adap, m); + else + err = mb862xx_i2c_write(adap, m); + } + + if (i) + mb862xx_i2c_stop(adap); + + return (err < 0) ? err : i; +} + +static u32 mb862xx_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_SMBUS_BYTE_DATA; +} + +static const struct i2c_algorithm mb862xx_algo = { + .master_xfer = mb862xx_xfer, + .functionality = mb862xx_func, +}; + +static struct i2c_adapter mb862xx_i2c_adapter = { + .name = "MB862xx I2C adapter", + .algo = &mb862xx_algo, + .owner = THIS_MODULE, +}; + +int mb862xx_i2c_init(struct mb862xxfb_par *par) +{ + int ret; + + mb862xx_i2c_adapter.algo_data = par; + par->adap = &mb862xx_i2c_adapter; + + ret = i2c_add_adapter(par->adap); + if (ret < 0) { + dev_err(par->dev, "failed to add %s\n", + mb862xx_i2c_adapter.name); + } + return ret; +} + +void mb862xx_i2c_exit(struct mb862xxfb_par *par) +{ + if (par->adap) { + i2c_del_adapter(par->adap); + par->adap = NULL; + } +} diff --git a/drivers/video/mb862xx/mb862xx_reg.h b/drivers/video/mb862xx/mb862xx_reg.h index 737fc011caff..5784b018f15d 100644 --- a/drivers/video/mb862xx/mb862xx_reg.h +++ b/drivers/video/mb862xx/mb862xx_reg.h @@ -80,6 +80,27 @@ #define GC_DISP_REFCLK_400 400 +/* I2C */ +#define GC_I2C_BSR 0x00000000 /* BSR */ +#define GC_I2C_BCR 0x00000004 /* BCR */ +#define GC_I2C_CCR 0x00000008 /* CCR */ +#define GC_I2C_ADR 0x0000000C /* ADR */ +#define GC_I2C_DAR 0x00000010 /* DAR */ + +#define I2C_DISABLE 0x00000000 +#define I2C_STOP 0x00000000 +#define I2C_START 0x00000010 +#define I2C_REPEATED_START 0x00000030 +#define I2C_CLOCK_AND_ENABLE 0x0000003f +#define I2C_READY 0x01 +#define I2C_INT 0x01 +#define I2C_INTE 0x02 +#define I2C_ACK 0x08 +#define I2C_BER 0x80 +#define I2C_BEIE 0x40 +#define I2C_TRX 0x80 +#define I2C_LRB 0x10 + /* Carmine specific */ #define MB86297_DRAW_BASE 0x00020000 #define MB86297_DISP0_BASE 0x00100000 diff --git a/drivers/video/mb862xx/mb862xxfb.h b/drivers/video/mb862xx/mb862xxfb.h index d7e7cb76bbf2..d5dd7d9ec0cd 100644 --- a/drivers/video/mb862xx/mb862xxfb.h +++ b/drivers/video/mb862xx/mb862xxfb.h @@ -57,11 +57,20 @@ struct mb862xxfb_par { unsigned int refclk; /* disp. reference clock */ struct mb862xx_gc_mode *gc_mode; /* GDC mode init data */ int pre_init; /* don't init display if 1 */ + struct i2c_adapter *adap; /* GDC I2C bus adapter */ + int i2c_rs; u32 pseudo_palette[16]; }; extern void mb862xxfb_init_accel(struct fb_info *info, int xres); +#ifdef CONFIG_FB_MB862XX_I2C +extern int mb862xx_i2c_init(struct mb862xxfb_par *par); +extern void mb862xx_i2c_exit(struct mb862xxfb_par *par); +#else +static inline int mb862xx_i2c_init(struct mb862xxfb_par *par) { return 0; } +static inline void mb862xx_i2c_exit(struct mb862xxfb_par *par) { } +#endif #if defined(CONFIG_FB_MB862XX_LIME) && defined(CONFIG_FB_MB862XX_PCI_GDC) #error "Select Lime GDC or CoralP/Carmine support, but not both together" diff --git a/drivers/video/mb862xx/mb862xxfb.c b/drivers/video/mb862xx/mb862xxfbdrv.c similarity index 99% rename from drivers/video/mb862xx/mb862xxfb.c rename to drivers/video/mb862xx/mb862xxfbdrv.c index ffb6a2c36d3c..0cc20b4fbcb5 100644 --- a/drivers/video/mb862xx/mb862xxfb.c +++ b/drivers/video/mb862xx/mb862xxfbdrv.c @@ -772,6 +772,8 @@ static int coralp_init(struct mb862xxfb_par *par) } else { return -ENODEV; } + + mb862xx_i2c_init(par); return 0; } @@ -1029,6 +1031,8 @@ static void __devexit mb862xx_pci_remove(struct pci_dev *pdev) outreg(host, GC_IMASK, 0); } + mb862xx_i2c_exit(par); + device_remove_file(&pdev->dev, &dev_attr_dispregs); pci_set_drvdata(pdev, NULL); From f64d8a5fdec35ed36f76130517a5580974a324a4 Mon Sep 17 00:00:00 2001 From: Anatolij Gustschin Date: Fri, 13 May 2011 13:31:37 +0200 Subject: [PATCH 5/5] video: mb862xxfb: add support for L1 displaying Allow displaying L1 video data on top of the primary L0 layer. The L1 layer position and dimensions can be configured and the layer enabled/disabled by using the appropriate L1 controls added by this patch. Signed-off-by: Anatolij Gustschin --- drivers/video/mb862xx/mb862xx_reg.h | 31 +++++++ drivers/video/mb862xx/mb862xxfb.h | 27 +++++++ drivers/video/mb862xx/mb862xxfbdrv.c | 116 ++++++++++++++++++++++++++- 3 files changed, 173 insertions(+), 1 deletion(-) diff --git a/drivers/video/mb862xx/mb862xx_reg.h b/drivers/video/mb862xx/mb862xx_reg.h index 5784b018f15d..9df48b8edc94 100644 --- a/drivers/video/mb862xx/mb862xx_reg.h +++ b/drivers/video/mb862xx/mb862xx_reg.h @@ -51,10 +51,16 @@ #define GC_L0OA0 0x00000024 #define GC_L0DA0 0x00000028 #define GC_L0DY_L0DX 0x0000002c +#define GC_L1M 0x00000030 +#define GC_L1DA 0x00000034 #define GC_DCM1 0x00000100 #define GC_L0EM 0x00000110 #define GC_L0WY_L0WX 0x00000114 #define GC_L0WH_L0WW 0x00000118 +#define GC_L1EM 0x00000120 +#define GC_L1WY_L1WX 0x00000124 +#define GC_L1WH_L1WW 0x00000128 +#define GC_DLS 0x00000180 #define GC_DCM2 0x00000104 #define GC_DCM3 0x00000108 #define GC_CPM_CUTC 0x000000a0 @@ -66,6 +72,11 @@ #define GC_CPM_CEN0 0x00100000 #define GC_CPM_CEN1 0x00200000 +#define GC_DCM1_DEN 0x80000000 +#define GC_DCM1_L1E 0x00020000 +#define GC_L1M_16 0x80000000 +#define GC_L1M_YC 0x40000000 +#define GC_L1M_CS 0x20000000 #define GC_DCM01_ESY 0x00000004 #define GC_DCM01_SC 0x00003f00 @@ -77,6 +88,7 @@ #define GC_L0M_L0C_16 0x80000000 #define GC_L0EM_L0EC_24 0x40000000 #define GC_L0M_L0W_UNIT 64 +#define GC_L1EM_DM 0x02000000 #define GC_DISP_REFCLK_400 400 @@ -101,6 +113,25 @@ #define I2C_TRX 0x80 #define I2C_LRB 0x10 +/* Capture registers and bits */ +#define GC_CAP_VCM 0x00000000 +#define GC_CAP_CSC 0x00000004 +#define GC_CAP_VCS 0x00000008 +#define GC_CAP_CBM 0x00000010 +#define GC_CAP_CBOA 0x00000014 +#define GC_CAP_CBLA 0x00000018 +#define GC_CAP_IMG_START 0x0000001C +#define GC_CAP_IMG_END 0x00000020 +#define GC_CAP_CMSS 0x00000048 +#define GC_CAP_CMDS 0x0000004C + +#define GC_VCM_VIE 0x80000000 +#define GC_VCM_CM 0x03000000 +#define GC_VCM_VS_PAL 0x00000002 +#define GC_CBM_OO 0x80000000 +#define GC_CBM_HRV 0x00000010 +#define GC_CBM_CBST 0x00000001 + /* Carmine specific */ #define MB86297_DRAW_BASE 0x00020000 #define MB86297_DISP0_BASE 0x00100000 diff --git a/drivers/video/mb862xx/mb862xxfb.h b/drivers/video/mb862xx/mb862xxfb.h index d5dd7d9ec0cd..8550630c1e01 100644 --- a/drivers/video/mb862xx/mb862xxfb.h +++ b/drivers/video/mb862xx/mb862xxfb.h @@ -1,6 +1,26 @@ #ifndef __MB862XX_H__ #define __MB862XX_H__ +struct mb862xx_l1_cfg { + unsigned short sx; + unsigned short sy; + unsigned short sw; + unsigned short sh; + unsigned short dx; + unsigned short dy; + unsigned short dw; + unsigned short dh; + int mirror; +}; + +#define MB862XX_BASE 'M' +#define MB862XX_L1_GET_CFG _IOR(MB862XX_BASE, 0, struct mb862xx_l1_cfg*) +#define MB862XX_L1_SET_CFG _IOW(MB862XX_BASE, 1, struct mb862xx_l1_cfg*) +#define MB862XX_L1_ENABLE _IOW(MB862XX_BASE, 2, int) +#define MB862XX_L1_CAP_CTL _IOW(MB862XX_BASE, 3, int) + +#ifdef __KERNEL__ + #define PCI_VENDOR_ID_FUJITSU_LIMITED 0x10cf #define PCI_DEVICE_ID_FUJITSU_CORALP 0x2019 #define PCI_DEVICE_ID_FUJITSU_CORALPA 0x201e @@ -38,6 +58,8 @@ struct mb862xxfb_par { void __iomem *mmio_base; /* remapped registers */ size_t mapped_vram; /* length of remapped vram */ size_t mmio_len; /* length of register region */ + unsigned long cap_buf; /* capture buffers offset */ + size_t cap_len; /* length of capture buffers */ void __iomem *host; /* relocatable reg. bases */ void __iomem *i2c; @@ -60,6 +82,9 @@ struct mb862xxfb_par { struct i2c_adapter *adap; /* GDC I2C bus adapter */ int i2c_rs; + struct mb862xx_l1_cfg l1_cfg; + int l1_stride; + u32 pseudo_palette[16]; }; @@ -91,4 +116,6 @@ static inline void mb862xx_i2c_exit(struct mb862xxfb_par *par) { } #define pack(a, b) (((a) << 16) | (b)) +#endif /* __KERNEL__ */ + #endif diff --git a/drivers/video/mb862xx/mb862xxfbdrv.c b/drivers/video/mb862xx/mb862xxfbdrv.c index 0cc20b4fbcb5..ea39336addfb 100644 --- a/drivers/video/mb862xx/mb862xxfbdrv.c +++ b/drivers/video/mb862xx/mb862xxfbdrv.c @@ -27,7 +27,7 @@ #define NR_PALETTE 256 #define MB862XX_MEM_SIZE 0x1000000 -#define CORALP_MEM_SIZE 0x4000000 +#define CORALP_MEM_SIZE 0x2000000 #define CARMINE_MEM_SIZE 0x8000000 #define DRV_NAME "mb862xxfb" @@ -309,6 +309,97 @@ static int mb862xxfb_blank(int mode, struct fb_info *fbi) return 0; } +static int mb862xxfb_ioctl(struct fb_info *fbi, unsigned int cmd, + unsigned long arg) +{ + struct mb862xxfb_par *par = fbi->par; + struct mb862xx_l1_cfg *l1_cfg = &par->l1_cfg; + void __user *argp = (void __user *)arg; + int *enable; + u32 l1em = 0; + + switch (cmd) { + case MB862XX_L1_GET_CFG: + if (copy_to_user(argp, l1_cfg, sizeof(*l1_cfg))) + return -EFAULT; + break; + case MB862XX_L1_SET_CFG: + if (copy_from_user(l1_cfg, argp, sizeof(*l1_cfg))) + return -EFAULT; + if ((l1_cfg->sw >= l1_cfg->dw) && (l1_cfg->sh >= l1_cfg->dh)) { + /* downscaling */ + outreg(cap, GC_CAP_CSC, + pack((l1_cfg->sh << 11) / l1_cfg->dh, + (l1_cfg->sw << 11) / l1_cfg->dw)); + l1em = inreg(disp, GC_L1EM); + l1em &= ~GC_L1EM_DM; + } else if ((l1_cfg->sw <= l1_cfg->dw) && + (l1_cfg->sh <= l1_cfg->dh)) { + /* upscaling */ + outreg(cap, GC_CAP_CSC, + pack((l1_cfg->sh << 11) / l1_cfg->dh, + (l1_cfg->sw << 11) / l1_cfg->dw)); + outreg(cap, GC_CAP_CMSS, + pack(l1_cfg->sw >> 1, l1_cfg->sh)); + outreg(cap, GC_CAP_CMDS, + pack(l1_cfg->dw >> 1, l1_cfg->dh)); + l1em = inreg(disp, GC_L1EM); + l1em |= GC_L1EM_DM; + } + + if (l1_cfg->mirror) { + outreg(cap, GC_CAP_CBM, + inreg(cap, GC_CAP_CBM) | GC_CBM_HRV); + l1em |= l1_cfg->dw * 2 - 8; + } else { + outreg(cap, GC_CAP_CBM, + inreg(cap, GC_CAP_CBM) & ~GC_CBM_HRV); + l1em &= 0xffff0000; + } + outreg(disp, GC_L1EM, l1em); + break; + case MB862XX_L1_ENABLE: + enable = (int *)arg; + if (*enable) { + outreg(disp, GC_L1DA, par->cap_buf); + outreg(cap, GC_CAP_IMG_START, + pack(l1_cfg->sy >> 1, l1_cfg->sx)); + outreg(cap, GC_CAP_IMG_END, + pack(l1_cfg->sh, l1_cfg->sw)); + outreg(disp, GC_L1M, GC_L1M_16 | GC_L1M_YC | GC_L1M_CS | + (par->l1_stride << 16)); + outreg(disp, GC_L1WY_L1WX, + pack(l1_cfg->dy, l1_cfg->dx)); + outreg(disp, GC_L1WH_L1WW, + pack(l1_cfg->dh - 1, l1_cfg->dw)); + outreg(disp, GC_DLS, 1); + outreg(cap, GC_CAP_VCM, + GC_VCM_VIE | GC_VCM_CM | GC_VCM_VS_PAL); + outreg(disp, GC_DCM1, inreg(disp, GC_DCM1) | + GC_DCM1_DEN | GC_DCM1_L1E); + } else { + outreg(cap, GC_CAP_VCM, + inreg(cap, GC_CAP_VCM) & ~GC_VCM_VIE); + outreg(disp, GC_DCM1, + inreg(disp, GC_DCM1) & ~GC_DCM1_L1E); + } + break; + case MB862XX_L1_CAP_CTL: + enable = (int *)arg; + if (*enable) { + outreg(cap, GC_CAP_VCM, + inreg(cap, GC_CAP_VCM) | GC_VCM_VIE); + } else { + outreg(cap, GC_CAP_VCM, + inreg(cap, GC_CAP_VCM) & ~GC_VCM_VIE); + } + break; + default: + return -EINVAL; + } + return 0; +} + /* framebuffer ops */ static struct fb_ops mb862xxfb_ops = { .owner = THIS_MODULE, @@ -320,6 +411,7 @@ static struct fb_ops mb862xxfb_ops = { .fb_fillrect = cfb_fillrect, .fb_copyarea = cfb_copyarea, .fb_imageblit = cfb_imageblit, + .fb_ioctl = mb862xxfb_ioctl, }; /* initialize fb_info data */ @@ -328,6 +420,7 @@ static int mb862xxfb_init_fbinfo(struct fb_info *fbi) struct mb862xxfb_par *par = fbi->par; struct mb862xx_gc_mode *mode = par->gc_mode; unsigned long reg; + int stride; fbi->fbops = &mb862xxfb_ops; fbi->pseudo_palette = par->pseudo_palette; @@ -420,6 +513,27 @@ static int mb862xxfb_init_fbinfo(struct fb_info *fbi) fbi->fix.line_length = (fbi->var.xres_virtual * fbi->var.bits_per_pixel) / 8; fbi->fix.smem_len = fbi->fix.line_length * fbi->var.yres_virtual; + + /* + * reserve space for capture buffers and two cursors + * at the end of vram: 720x576 * 2 * 2.2 + 64x64 * 16. + */ + par->cap_buf = par->mapped_vram - 0x1bd800 - 0x10000; + par->cap_len = 0x1bd800; + par->l1_cfg.sx = 0; + par->l1_cfg.sy = 0; + par->l1_cfg.sw = 720; + par->l1_cfg.sh = 576; + par->l1_cfg.dx = 0; + par->l1_cfg.dy = 0; + par->l1_cfg.dw = 720; + par->l1_cfg.dh = 576; + stride = par->l1_cfg.sw * (fbi->var.bits_per_pixel / 8); + par->l1_stride = stride / 64 + ((stride % 64) ? 1 : 0); + outreg(cap, GC_CAP_CBM, GC_CBM_OO | GC_CBM_CBST | + (par->l1_stride << 16)); + outreg(cap, GC_CAP_CBOA, par->cap_buf); + outreg(cap, GC_CAP_CBLA, par->cap_buf + par->cap_len); return 0; }