Commit 8edbeb6e authored by Florian Tobias Schandinat's avatar Florian Tobias Schandinat

Merge branch 'sh-mobile-lcdc' of git://linuxtv.org/pinchartl/fbdev into fbdev-next

parents d4a7dbfd 8a20974f
......@@ -1583,6 +1583,7 @@ static void __init mackerel_init(void)
sh7372_add_device_to_domain(&sh7372_a4lc, &lcdc_device);
sh7372_add_device_to_domain(&sh7372_a4lc, &hdmi_lcdc_device);
sh7372_add_device_to_domain(&sh7372_a4lc, &meram_device);
sh7372_add_device_to_domain(&sh7372_a4mp, &fsi_device);
hdmi_init_pm_clock();
......
This diff is collapsed.
......@@ -18,6 +18,13 @@ struct sh_mobile_lcdc_priv;
struct fb_info;
struct backlight_device;
/*
* struct sh_mobile_lcdc_chan - LCDC display channel
*
* @base_addr_y: Frame buffer viewport base address (luma component)
* @base_addr_c: Frame buffer viewport base address (chroma component)
* @pitch: Frame buffer line pitch
*/
struct sh_mobile_lcdc_chan {
struct sh_mobile_lcdc_priv *lcdc;
unsigned long *reg_offs;
......@@ -25,7 +32,6 @@ struct sh_mobile_lcdc_chan {
unsigned long enabled; /* ME and SE in LDCNT2R */
struct sh_mobile_lcdc_chan_cfg cfg;
u32 pseudo_palette[PALETTE_NR];
unsigned long saved_ch_regs[NR_CH_REGS];
struct fb_info *info;
struct backlight_device *bl;
dma_addr_t dma_handle;
......@@ -40,6 +46,10 @@ struct sh_mobile_lcdc_chan {
int blank_status;
struct mutex open_lock; /* protects the use counter */
int meram_enabled;
unsigned long base_addr_y;
unsigned long base_addr_c;
unsigned int pitch;
};
#endif
......@@ -12,30 +12,104 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/pm_runtime.h>
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
#include "sh_mobile_meram.h"
#include <video/sh_mobile_meram.h>
/* meram registers */
#define MExxCTL 0x0
#define MExxBSIZE 0x4
#define MExxMNCF 0x8
#define MExxSARA 0x10
#define MExxSARB 0x14
#define MExxSBSIZE 0x18
#define MERAM_MExxCTL_VAL(ctl, next_icb, addr) \
((ctl) | (((next_icb) & 0x1f) << 11) | (((addr) & 0x7ff) << 16))
#define MERAM_MExxBSIZE_VAL(a, b, c) \
(((a) << 28) | ((b) << 16) | (c))
#define MEVCR1 0x4
#define MEACTS 0x10
#define MEVCR1_RST (1 << 31)
#define MEVCR1_WD (1 << 30)
#define MEVCR1_AMD1 (1 << 29)
#define MEVCR1_AMD0 (1 << 28)
#define MEQSEL1 0x40
#define MEQSEL2 0x44
#define MExxCTL 0x400
#define MExxCTL_BV (1 << 31)
#define MExxCTL_BSZ_SHIFT 28
#define MExxCTL_MSAR_MASK (0x7ff << MExxCTL_MSAR_SHIFT)
#define MExxCTL_MSAR_SHIFT 16
#define MExxCTL_NXT_MASK (0x1f << MExxCTL_NXT_SHIFT)
#define MExxCTL_NXT_SHIFT 11
#define MExxCTL_WD1 (1 << 10)
#define MExxCTL_WD0 (1 << 9)
#define MExxCTL_WS (1 << 8)
#define MExxCTL_CB (1 << 7)
#define MExxCTL_WBF (1 << 6)
#define MExxCTL_WF (1 << 5)
#define MExxCTL_RF (1 << 4)
#define MExxCTL_CM (1 << 3)
#define MExxCTL_MD_READ (1 << 0)
#define MExxCTL_MD_WRITE (2 << 0)
#define MExxCTL_MD_ICB_WB (3 << 0)
#define MExxCTL_MD_ICB (4 << 0)
#define MExxCTL_MD_FB (7 << 0)
#define MExxCTL_MD_MASK (7 << 0)
#define MExxBSIZE 0x404
#define MExxBSIZE_RCNT_SHIFT 28
#define MExxBSIZE_YSZM1_SHIFT 16
#define MExxBSIZE_XSZM1_SHIFT 0
#define MExxMNCF 0x408
#define MExxMNCF_KWBNM_SHIFT 28
#define MExxMNCF_KRBNM_SHIFT 24
#define MExxMNCF_BNM_SHIFT 16
#define MExxMNCF_XBV (1 << 15)
#define MExxMNCF_CPL_YCBCR444 (1 << 12)
#define MExxMNCF_CPL_YCBCR420 (2 << 12)
#define MExxMNCF_CPL_YCBCR422 (3 << 12)
#define MExxMNCF_CPL_MSK (3 << 12)
#define MExxMNCF_BL (1 << 2)
#define MExxMNCF_LNM_SHIFT 0
#define MExxSARA 0x410
#define MExxSARB 0x414
#define MExxSBSIZE 0x418
#define MExxSBSIZE_HDV (1 << 31)
#define MExxSBSIZE_HSZ16 (0 << 28)
#define MExxSBSIZE_HSZ32 (1 << 28)
#define MExxSBSIZE_HSZ64 (2 << 28)
#define MExxSBSIZE_HSZ128 (3 << 28)
#define MExxSBSIZE_SBSIZZ_SHIFT 0
#define MERAM_MExxCTL_VAL(next, addr) \
((((next) << MExxCTL_NXT_SHIFT) & MExxCTL_NXT_MASK) | \
(((addr) << MExxCTL_MSAR_SHIFT) & MExxCTL_MSAR_MASK))
#define MERAM_MExxBSIZE_VAL(rcnt, yszm1, xszm1) \
(((rcnt) << MExxBSIZE_RCNT_SHIFT) | \
((yszm1) << MExxBSIZE_YSZM1_SHIFT) | \
((xszm1) << MExxBSIZE_XSZM1_SHIFT))
#define SH_MOBILE_MERAM_ICB_NUM 32
static unsigned long common_regs[] = {
MEVCR1,
MEQSEL1,
MEQSEL2,
};
#define CMN_REGS_SIZE ARRAY_SIZE(common_regs)
static unsigned long icb_regs[] = {
MExxCTL,
MExxBSIZE,
MExxMNCF,
MExxSARA,
MExxSARB,
MExxSBSIZE,
};
#define ICB_REGS_SIZE ARRAY_SIZE(icb_regs)
struct sh_mobile_meram_priv {
void __iomem *base;
struct mutex lock;
unsigned long used_icb;
int used_meram_cache_regions;
unsigned long used_meram_cache[SH_MOBILE_MERAM_ICB_NUM];
unsigned long cmn_saved_regs[CMN_REGS_SIZE];
unsigned long icb_saved_regs[ICB_REGS_SIZE * SH_MOBILE_MERAM_ICB_NUM];
};
/* settings */
#define MERAM_SEC_LINE 15
#define MERAM_LINE_WIDTH 2048
......@@ -44,8 +118,7 @@
* MERAM/ICB access functions
*/
#define MERAM_ICB_OFFSET(base, idx, off) \
((base) + (0x400 + ((idx) * 0x20) + (off)))
#define MERAM_ICB_OFFSET(base, idx, off) ((base) + (off) + (idx) * 0x20)
static inline void meram_write_icb(void __iomem *base, int idx, int off,
unsigned long val)
......@@ -280,17 +353,18 @@ static int meram_init(struct sh_mobile_meram_priv *priv,
/*
* Set MERAM for framebuffer
*
* 0x70f: WD = 0x3, WS=0x1, CM=0x1, MD=FB mode
* we also chain the cache_icb and the marker_icb.
* we also split the allocated MERAM buffer between two ICBs.
*/
meram_write_icb(priv->base, icb->cache_icb, MExxCTL,
MERAM_MExxCTL_VAL(0x70f, icb->marker_icb,
icb->meram_offset));
MERAM_MExxCTL_VAL(icb->marker_icb, icb->meram_offset) |
MExxCTL_WD1 | MExxCTL_WD0 | MExxCTL_WS | MExxCTL_CM |
MExxCTL_MD_FB);
meram_write_icb(priv->base, icb->marker_icb, MExxCTL,
MERAM_MExxCTL_VAL(0x70f, icb->cache_icb,
icb->meram_offset +
icb->meram_size / 2));
MERAM_MExxCTL_VAL(icb->cache_icb, icb->meram_offset +
icb->meram_size / 2) |
MExxCTL_WD1 | MExxCTL_WD0 | MExxCTL_WS | MExxCTL_CM |
MExxCTL_MD_FB);
return 0;
}
......@@ -337,24 +411,22 @@ static int sh_mobile_meram_register(struct sh_mobile_meram_info *pdata,
xres, yres, (!pixelformat) ? "yuv" : "rgb",
base_addr_y, base_addr_c);
mutex_lock(&priv->lock);
/* we can't handle wider than 8192px */
if (xres > 8192) {
dev_err(&pdev->dev, "width exceeding the limit (> 8192).");
error = -EINVAL;
goto err;
}
if (priv->used_meram_cache_regions + 2 > SH_MOBILE_MERAM_ICB_NUM) {
dev_err(&pdev->dev, "no more ICB available.");
error = -EINVAL;
goto err;
return -EINVAL;
}
/* do we have at least one ICB config? */
if (cfg->icb[0].marker_icb < 0 || cfg->icb[0].cache_icb < 0) {
dev_err(&pdev->dev, "at least one ICB is required.");
return -EINVAL;
}
mutex_lock(&priv->lock);
if (priv->used_meram_cache_regions + 2 > SH_MOBILE_MERAM_ICB_NUM) {
dev_err(&pdev->dev, "no more ICB available.");
error = -EINVAL;
goto err;
}
......@@ -460,6 +532,57 @@ static int sh_mobile_meram_update(struct sh_mobile_meram_info *pdata,
return 0;
}
static int sh_mobile_meram_runtime_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct sh_mobile_meram_priv *priv = platform_get_drvdata(pdev);
int k, j;
for (k = 0; k < CMN_REGS_SIZE; k++)
priv->cmn_saved_regs[k] = meram_read_reg(priv->base,
common_regs[k]);
for (j = 0; j < 32; j++) {
if (!test_bit(j, &priv->used_icb))
continue;
for (k = 0; k < ICB_REGS_SIZE; k++) {
priv->icb_saved_regs[j * ICB_REGS_SIZE + k] =
meram_read_icb(priv->base, j, icb_regs[k]);
/* Reset ICB on resume */
if (icb_regs[k] == MExxCTL)
priv->icb_saved_regs[j * ICB_REGS_SIZE + k] |=
MExxCTL_WBF | MExxCTL_WF | MExxCTL_RF;
}
}
return 0;
}
static int sh_mobile_meram_runtime_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct sh_mobile_meram_priv *priv = platform_get_drvdata(pdev);
int k, j;
for (j = 0; j < 32; j++) {
if (!test_bit(j, &priv->used_icb))
continue;
for (k = 0; k < ICB_REGS_SIZE; k++) {
meram_write_icb(priv->base, j, icb_regs[k],
priv->icb_saved_regs[j * ICB_REGS_SIZE + k]);
}
}
for (k = 0; k < CMN_REGS_SIZE; k++)
meram_write_reg(priv->base, common_regs[k],
priv->cmn_saved_regs[k]);
return 0;
}
static const struct dev_pm_ops sh_mobile_meram_dev_pm_ops = {
.runtime_suspend = sh_mobile_meram_runtime_suspend,
.runtime_resume = sh_mobile_meram_runtime_resume,
};
static struct sh_mobile_meram_ops sh_mobile_meram_ops = {
.module = THIS_MODULE,
.meram_register = sh_mobile_meram_register,
......@@ -513,7 +636,9 @@ static int __devinit sh_mobile_meram_probe(struct platform_device *pdev)
/* initialize ICB addressing mode */
if (pdata->addr_mode == SH_MOBILE_MERAM_MODE1)
meram_write_reg(priv->base, MEVCR1, 1 << 29);
meram_write_reg(priv->base, MEVCR1, MEVCR1_AMD1);
pm_runtime_enable(&pdev->dev);
dev_info(&pdev->dev, "sh_mobile_meram initialized.");
......@@ -530,6 +655,8 @@ static int sh_mobile_meram_remove(struct platform_device *pdev)
{
struct sh_mobile_meram_priv *priv = platform_get_drvdata(pdev);
pm_runtime_disable(&pdev->dev);
if (priv->base)
iounmap(priv->base);
......@@ -544,6 +671,7 @@ static struct platform_driver sh_mobile_meram_driver = {
.driver = {
.name = "sh_mobile_meram",
.owner = THIS_MODULE,
.pm = &sh_mobile_meram_dev_pm_ops,
},
.probe = sh_mobile_meram_probe,
.remove = sh_mobile_meram_remove,
......
#ifndef __sh_mobile_meram_h__
#define __sh_mobile_meram_h__
#include <linux/mutex.h>
#include <video/sh_mobile_meram.h>
/*
* MERAM private
*/
#define MERAM_ICB_Y 0x1
#define MERAM_ICB_C 0x2
/* MERAM cache size */
#define SH_MOBILE_MERAM_ICB_NUM 32
#define SH_MOBILE_MERAM_CACHE_OFFSET(p) ((p) >> 16)
#define SH_MOBILE_MERAM_CACHE_SIZE(p) ((p) & 0xffff)
struct sh_mobile_meram_priv {
void __iomem *base;
struct mutex lock;
unsigned long used_icb;
int used_meram_cache_regions;
unsigned long used_meram_cache[SH_MOBILE_MERAM_ICB_NUM];
};
int sh_mobile_meram_alloc_icb(const struct sh_mobile_meram_cfg *cfg,
int xres,
int yres,
unsigned int base_addr,
int yuv_mode,
int *marker_icb,
int *out_pitch);
void sh_mobile_meram_free_icb(int marker_icb);
#define SH_MOBILE_MERAM_START(ind, ab) \
(0xC0000000 | ((ab & 0x1) << 23) | ((ind & 0x1F) << 24))
#endif /* !__sh_mobile_meram_h__ */
......@@ -4,26 +4,123 @@
#include <linux/fb.h>
#include <video/sh_mobile_meram.h>
/* Register definitions */
#define _LDDCKR 0x410
#define LDDCKR_ICKSEL_BUS (0 << 16)
#define LDDCKR_ICKSEL_MIPI (1 << 16)
#define LDDCKR_ICKSEL_HDMI (2 << 16)
#define LDDCKR_ICKSEL_EXT (3 << 16)
#define LDDCKR_ICKSEL_MASK (7 << 16)
#define LDDCKR_MOSEL (1 << 6)
#define _LDDCKSTPR 0x414
#define _LDINTR 0x468
#define LDINTR_FE (1 << 10)
#define LDINTR_VSE (1 << 9)
#define LDINTR_VEE (1 << 8)
#define LDINTR_FS (1 << 2)
#define LDINTR_VSS (1 << 1)
#define LDINTR_VES (1 << 0)
#define LDINTR_STATUS_MASK (0xff << 0)
#define _LDSR 0x46c
#define LDSR_MSS (1 << 10)
#define LDSR_MRS (1 << 8)
#define LDSR_AS (1 << 1)
#define _LDCNT1R 0x470
#define LDCNT1R_DE (1 << 0)
#define _LDCNT2R 0x474
#define LDCNT2R_BR (1 << 8)
#define LDCNT2R_MD (1 << 3)
#define LDCNT2R_SE (1 << 2)
#define LDCNT2R_ME (1 << 1)
#define LDCNT2R_DO (1 << 0)
#define _LDRCNTR 0x478
#define LDRCNTR_SRS (1 << 17)
#define LDRCNTR_SRC (1 << 16)
#define LDRCNTR_MRS (1 << 1)
#define LDRCNTR_MRC (1 << 0)
#define _LDDDSR 0x47c
#define LDDDSR_LS (1 << 2)
#define LDDDSR_WS (1 << 1)
#define LDDDSR_BS (1 << 0)
#define LDMT1R_VPOL (1 << 28)
#define LDMT1R_HPOL (1 << 27)
#define LDMT1R_DWPOL (1 << 26)
#define LDMT1R_DIPOL (1 << 25)
#define LDMT1R_DAPOL (1 << 24)
#define LDMT1R_HSCNT (1 << 17)
#define LDMT1R_DWCNT (1 << 16)
#define LDMT1R_IFM (1 << 12)
#define LDMT1R_MIFTYP_RGB8 (0x0 << 0)
#define LDMT1R_MIFTYP_RGB9 (0x4 << 0)
#define LDMT1R_MIFTYP_RGB12A (0x5 << 0)
#define LDMT1R_MIFTYP_RGB12B (0x6 << 0)
#define LDMT1R_MIFTYP_RGB16 (0x7 << 0)
#define LDMT1R_MIFTYP_RGB18 (0xa << 0)
#define LDMT1R_MIFTYP_RGB24 (0xb << 0)
#define LDMT1R_MIFTYP_YCBCR (0xf << 0)
#define LDMT1R_MIFTYP_SYS8A (0x0 << 0)
#define LDMT1R_MIFTYP_SYS8B (0x1 << 0)
#define LDMT1R_MIFTYP_SYS8C (0x2 << 0)
#define LDMT1R_MIFTYP_SYS8D (0x3 << 0)
#define LDMT1R_MIFTYP_SYS9 (0x4 << 0)
#define LDMT1R_MIFTYP_SYS12 (0x5 << 0)
#define LDMT1R_MIFTYP_SYS16A (0x7 << 0)
#define LDMT1R_MIFTYP_SYS16B (0x8 << 0)
#define LDMT1R_MIFTYP_SYS16C (0x9 << 0)
#define LDMT1R_MIFTYP_SYS18 (0xa << 0)
#define LDMT1R_MIFTYP_SYS24 (0xb << 0)
#define LDMT1R_MIFTYP_MASK (0xf << 0)
#define LDDFR_CF1 (1 << 18)
#define LDDFR_CF0 (1 << 17)
#define LDDFR_CC (1 << 16)
#define LDDFR_YF_420 (0 << 8)
#define LDDFR_YF_422 (1 << 8)
#define LDDFR_YF_444 (2 << 8)
#define LDDFR_YF_MASK (3 << 8)
#define LDDFR_PKF_ARGB32 (0x00 << 0)
#define LDDFR_PKF_RGB16 (0x03 << 0)
#define LDDFR_PKF_RGB24 (0x0b << 0)
#define LDDFR_PKF_MASK (0x1f << 0)
#define LDSM1R_OS (1 << 0)
#define LDSM2R_OSTRG (1 << 0)
#define LDPMR_LPS (3 << 0)
#define _LDDWD0R 0x800
#define LDDWDxR_WDACT (1 << 28)
#define LDDWDxR_RSW (1 << 24)
#define _LDDRDR 0x840
#define LDDRDR_RSR (1 << 24)
#define LDDRDR_DRD_MASK (0x3ffff << 0)
#define _LDDWAR 0x900
#define LDDWAR_WA (1 << 0)
#define _LDDRAR 0x904
#define LDDRAR_RA (1 << 0)
enum {
RGB8, /* 24bpp, 8:8:8 */
RGB9, /* 18bpp, 9:9 */
RGB12A, /* 24bpp, 12:12 */
RGB12B, /* 12bpp */
RGB16, /* 16bpp */
RGB18, /* 18bpp */
RGB24, /* 24bpp */
YUV422, /* 16bpp */
SYS8A, /* 24bpp, 8:8:8 */
SYS8B, /* 18bpp, 8:8:2 */
SYS8C, /* 18bpp, 2:8:8 */
SYS8D, /* 16bpp, 8:8 */
SYS9, /* 18bpp, 9:9 */
SYS12, /* 24bpp, 12:12 */
SYS16A, /* 16bpp */
SYS16B, /* 18bpp, 16:2 */
SYS16C, /* 18bpp, 2:16 */
SYS18, /* 18bpp */
SYS24, /* 24bpp */
RGB8 = LDMT1R_MIFTYP_RGB8, /* 24bpp, 8:8:8 */
RGB9 = LDMT1R_MIFTYP_RGB9, /* 18bpp, 9:9 */
RGB12A = LDMT1R_MIFTYP_RGB12A, /* 24bpp, 12:12 */
RGB12B = LDMT1R_MIFTYP_RGB12B, /* 12bpp */
RGB16 = LDMT1R_MIFTYP_RGB16, /* 16bpp */
RGB18 = LDMT1R_MIFTYP_RGB18, /* 18bpp */
RGB24 = LDMT1R_MIFTYP_RGB24, /* 24bpp */
YUV422 = LDMT1R_MIFTYP_YCBCR, /* 16bpp */
SYS8A = LDMT1R_IFM | LDMT1R_MIFTYP_SYS8A, /* 24bpp, 8:8:8 */
SYS8B = LDMT1R_IFM | LDMT1R_MIFTYP_SYS8B, /* 18bpp, 8:8:2 */
SYS8C = LDMT1R_IFM | LDMT1R_MIFTYP_SYS8C, /* 18bpp, 2:8:8 */
SYS8D = LDMT1R_IFM | LDMT1R_MIFTYP_SYS8D, /* 16bpp, 8:8 */
SYS9 = LDMT1R_IFM | LDMT1R_MIFTYP_SYS9, /* 18bpp, 9:9 */
SYS12 = LDMT1R_IFM | LDMT1R_MIFTYP_SYS12, /* 24bpp, 12:12 */
SYS16A = LDMT1R_IFM | LDMT1R_MIFTYP_SYS16A, /* 16bpp */
SYS16B = LDMT1R_IFM | LDMT1R_MIFTYP_SYS16B, /* 18bpp, 16:2 */
SYS16C = LDMT1R_IFM | LDMT1R_MIFTYP_SYS16C, /* 18bpp, 2:16 */
SYS18 = LDMT1R_IFM | LDMT1R_MIFTYP_SYS18, /* 18bpp */
SYS24 = LDMT1R_IFM | LDMT1R_MIFTYP_SYS24, /* 24bpp */
};
enum { LCDC_CHAN_DISABLED = 0,
......
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