Commit cdf5316b authored by Dave Airlie's avatar Dave Airlie

Merge branch 'drm-next-4.12' of https://github.com/ckhu-mediatek/linux.git-tags into drm-next

This series is MT2701 DRM support.

* 'drm-next-4.12' of https://github.com/ckhu-mediatek/linux.git-tags:
  drm/mediatek: add support for Mediatek SoC MT2701
  drm/mediatek: update DSI sub driver flow for sending commands to panel
  drm/mediatek: add non-continuous clock mode and EOT packet control
  drm/mediatek: add dsi transfer function
  drm/mediatek: add dsi interrupt control
  drm/mediatek: cleaning up and refine
  drm/mediatek: update display module connections
  drm/mediatek: add BLS component
  drm/mediatek: add shadow register support
  drm/mediatek: add *driver_data for different hardware settings
  drm/mediatek: add helpers for coverting from the generic components
  dt-bindings: display: mediatek: update supported chips
parents 01687781 84a5ead1
...@@ -40,6 +40,7 @@ Required properties (all function blocks): ...@@ -40,6 +40,7 @@ Required properties (all function blocks):
"mediatek,<chip>-dpi" - DPI controller, see mediatek,dpi.txt "mediatek,<chip>-dpi" - DPI controller, see mediatek,dpi.txt
"mediatek,<chip>-disp-mutex" - display mutex "mediatek,<chip>-disp-mutex" - display mutex
"mediatek,<chip>-disp-od" - overdrive "mediatek,<chip>-disp-od" - overdrive
the supported chips are mt2701 and mt8173.
- reg: Physical base address and length of the function block register space - reg: Physical base address and length of the function block register space
- interrupts: The interrupt signal from the function block (required, except for - interrupts: The interrupt signal from the function block (required, except for
merge and split function blocks). merge and split function blocks).
...@@ -54,6 +55,7 @@ Required properties (DMA function blocks): ...@@ -54,6 +55,7 @@ Required properties (DMA function blocks):
"mediatek,<chip>-disp-ovl" "mediatek,<chip>-disp-ovl"
"mediatek,<chip>-disp-rdma" "mediatek,<chip>-disp-rdma"
"mediatek,<chip>-disp-wdma" "mediatek,<chip>-disp-wdma"
the supported chips are mt2701 and mt8173.
- larb: Should contain a phandle pointing to the local arbiter device as defined - larb: Should contain a phandle pointing to the local arbiter device as defined
in Documentation/devicetree/bindings/memory-controllers/mediatek,smi-larb.txt in Documentation/devicetree/bindings/memory-controllers/mediatek,smi-larb.txt
- iommus: Should point to the respective IOMMU block with master port as - iommus: Should point to the respective IOMMU block with master port as
......
...@@ -7,6 +7,7 @@ channel output. ...@@ -7,6 +7,7 @@ channel output.
Required properties: Required properties:
- compatible: "mediatek,<chip>-dsi" - compatible: "mediatek,<chip>-dsi"
the supported chips are mt2701 and mt8173.
- reg: Physical base address and length of the controller's registers - reg: Physical base address and length of the controller's registers
- interrupts: The interrupt signal from the function block. - interrupts: The interrupt signal from the function block.
- clocks: device clocks - clocks: device clocks
...@@ -25,6 +26,7 @@ The MIPI TX configuration module controls the MIPI D-PHY. ...@@ -25,6 +26,7 @@ The MIPI TX configuration module controls the MIPI D-PHY.
Required properties: Required properties:
- compatible: "mediatek,<chip>-mipi-tx" - compatible: "mediatek,<chip>-mipi-tx"
the supported chips are mt2701 and mt8173.
- reg: Physical base address and length of the controller's registers - reg: Physical base address and length of the controller's registers
- clocks: PLL reference clock - clocks: PLL reference clock
- clock-output-names: name of the output clock line to the DSI encoder - clock-output-names: name of the output clock line to the DSI encoder
......
...@@ -35,18 +35,28 @@ ...@@ -35,18 +35,28 @@
#define DISP_REG_OVL_PITCH(n) (0x0044 + 0x20 * (n)) #define DISP_REG_OVL_PITCH(n) (0x0044 + 0x20 * (n))
#define DISP_REG_OVL_RDMA_CTRL(n) (0x00c0 + 0x20 * (n)) #define DISP_REG_OVL_RDMA_CTRL(n) (0x00c0 + 0x20 * (n))
#define DISP_REG_OVL_RDMA_GMC(n) (0x00c8 + 0x20 * (n)) #define DISP_REG_OVL_RDMA_GMC(n) (0x00c8 + 0x20 * (n))
#define DISP_REG_OVL_ADDR(n) (0x0f40 + 0x20 * (n)) #define DISP_REG_OVL_ADDR_MT2701 0x0040
#define DISP_REG_OVL_ADDR_MT8173 0x0f40
#define DISP_REG_OVL_ADDR(ovl, n) ((ovl)->data->addr + 0x20 * (n))
#define OVL_RDMA_MEM_GMC 0x40402020 #define OVL_RDMA_MEM_GMC 0x40402020
#define OVL_CON_BYTE_SWAP BIT(24) #define OVL_CON_BYTE_SWAP BIT(24)
#define OVL_CON_CLRFMT_RGB565 (0 << 12) #define OVL_CON_CLRFMT_RGB (1 << 12)
#define OVL_CON_CLRFMT_RGB888 (1 << 12)
#define OVL_CON_CLRFMT_RGBA8888 (2 << 12) #define OVL_CON_CLRFMT_RGBA8888 (2 << 12)
#define OVL_CON_CLRFMT_ARGB8888 (3 << 12) #define OVL_CON_CLRFMT_ARGB8888 (3 << 12)
#define OVL_CON_CLRFMT_RGB565(ovl) ((ovl)->data->fmt_rgb565_is_0 ? \
0 : OVL_CON_CLRFMT_RGB)
#define OVL_CON_CLRFMT_RGB888(ovl) ((ovl)->data->fmt_rgb565_is_0 ? \
OVL_CON_CLRFMT_RGB : 0)
#define OVL_CON_AEN BIT(8) #define OVL_CON_AEN BIT(8)
#define OVL_CON_ALPHA 0xff #define OVL_CON_ALPHA 0xff
struct mtk_disp_ovl_data {
unsigned int addr;
bool fmt_rgb565_is_0;
};
/** /**
* struct mtk_disp_ovl - DISP_OVL driver structure * struct mtk_disp_ovl - DISP_OVL driver structure
* @ddp_comp - structure containing type enum and hardware resources * @ddp_comp - structure containing type enum and hardware resources
...@@ -55,8 +65,14 @@ ...@@ -55,8 +65,14 @@
struct mtk_disp_ovl { struct mtk_disp_ovl {
struct mtk_ddp_comp ddp_comp; struct mtk_ddp_comp ddp_comp;
struct drm_crtc *crtc; struct drm_crtc *crtc;
const struct mtk_disp_ovl_data *data;
}; };
static inline struct mtk_disp_ovl *comp_to_ovl(struct mtk_ddp_comp *comp)
{
return container_of(comp, struct mtk_disp_ovl, ddp_comp);
}
static irqreturn_t mtk_disp_ovl_irq_handler(int irq, void *dev_id) static irqreturn_t mtk_disp_ovl_irq_handler(int irq, void *dev_id)
{ {
struct mtk_disp_ovl *priv = dev_id; struct mtk_disp_ovl *priv = dev_id;
...@@ -76,20 +92,18 @@ static irqreturn_t mtk_disp_ovl_irq_handler(int irq, void *dev_id) ...@@ -76,20 +92,18 @@ static irqreturn_t mtk_disp_ovl_irq_handler(int irq, void *dev_id)
static void mtk_ovl_enable_vblank(struct mtk_ddp_comp *comp, static void mtk_ovl_enable_vblank(struct mtk_ddp_comp *comp,
struct drm_crtc *crtc) struct drm_crtc *crtc)
{ {
struct mtk_disp_ovl *priv = container_of(comp, struct mtk_disp_ovl, struct mtk_disp_ovl *ovl = comp_to_ovl(comp);
ddp_comp);
priv->crtc = crtc; ovl->crtc = crtc;
writel(0x0, comp->regs + DISP_REG_OVL_INTSTA); writel(0x0, comp->regs + DISP_REG_OVL_INTSTA);
writel_relaxed(OVL_FME_CPL_INT, comp->regs + DISP_REG_OVL_INTEN); writel_relaxed(OVL_FME_CPL_INT, comp->regs + DISP_REG_OVL_INTEN);
} }
static void mtk_ovl_disable_vblank(struct mtk_ddp_comp *comp) static void mtk_ovl_disable_vblank(struct mtk_ddp_comp *comp)
{ {
struct mtk_disp_ovl *priv = container_of(comp, struct mtk_disp_ovl, struct mtk_disp_ovl *ovl = comp_to_ovl(comp);
ddp_comp);
priv->crtc = NULL; ovl->crtc = NULL;
writel_relaxed(0x0, comp->regs + DISP_REG_OVL_INTEN); writel_relaxed(0x0, comp->regs + DISP_REG_OVL_INTEN);
} }
...@@ -138,18 +152,18 @@ static void mtk_ovl_layer_off(struct mtk_ddp_comp *comp, unsigned int idx) ...@@ -138,18 +152,18 @@ static void mtk_ovl_layer_off(struct mtk_ddp_comp *comp, unsigned int idx)
writel(0x0, comp->regs + DISP_REG_OVL_RDMA_CTRL(idx)); writel(0x0, comp->regs + DISP_REG_OVL_RDMA_CTRL(idx));
} }
static unsigned int ovl_fmt_convert(unsigned int fmt) static unsigned int ovl_fmt_convert(struct mtk_disp_ovl *ovl, unsigned int fmt)
{ {
switch (fmt) { switch (fmt) {
default: default:
case DRM_FORMAT_RGB565: case DRM_FORMAT_RGB565:
return OVL_CON_CLRFMT_RGB565; return OVL_CON_CLRFMT_RGB565(ovl);
case DRM_FORMAT_BGR565: case DRM_FORMAT_BGR565:
return OVL_CON_CLRFMT_RGB565 | OVL_CON_BYTE_SWAP; return OVL_CON_CLRFMT_RGB565(ovl) | OVL_CON_BYTE_SWAP;
case DRM_FORMAT_RGB888: case DRM_FORMAT_RGB888:
return OVL_CON_CLRFMT_RGB888; return OVL_CON_CLRFMT_RGB888(ovl);
case DRM_FORMAT_BGR888: case DRM_FORMAT_BGR888:
return OVL_CON_CLRFMT_RGB888 | OVL_CON_BYTE_SWAP; return OVL_CON_CLRFMT_RGB888(ovl) | OVL_CON_BYTE_SWAP;
case DRM_FORMAT_RGBX8888: case DRM_FORMAT_RGBX8888:
case DRM_FORMAT_RGBA8888: case DRM_FORMAT_RGBA8888:
return OVL_CON_CLRFMT_ARGB8888; return OVL_CON_CLRFMT_ARGB8888;
...@@ -168,6 +182,7 @@ static unsigned int ovl_fmt_convert(unsigned int fmt) ...@@ -168,6 +182,7 @@ static unsigned int ovl_fmt_convert(unsigned int fmt)
static void mtk_ovl_layer_config(struct mtk_ddp_comp *comp, unsigned int idx, static void mtk_ovl_layer_config(struct mtk_ddp_comp *comp, unsigned int idx,
struct mtk_plane_state *state) struct mtk_plane_state *state)
{ {
struct mtk_disp_ovl *ovl = comp_to_ovl(comp);
struct mtk_plane_pending_state *pending = &state->pending; struct mtk_plane_pending_state *pending = &state->pending;
unsigned int addr = pending->addr; unsigned int addr = pending->addr;
unsigned int pitch = pending->pitch & 0xffff; unsigned int pitch = pending->pitch & 0xffff;
...@@ -179,7 +194,7 @@ static void mtk_ovl_layer_config(struct mtk_ddp_comp *comp, unsigned int idx, ...@@ -179,7 +194,7 @@ static void mtk_ovl_layer_config(struct mtk_ddp_comp *comp, unsigned int idx,
if (!pending->enable) if (!pending->enable)
mtk_ovl_layer_off(comp, idx); mtk_ovl_layer_off(comp, idx);
con = ovl_fmt_convert(fmt); con = ovl_fmt_convert(ovl, fmt);
if (idx != 0) if (idx != 0)
con |= OVL_CON_AEN | OVL_CON_ALPHA; con |= OVL_CON_AEN | OVL_CON_ALPHA;
...@@ -187,7 +202,7 @@ static void mtk_ovl_layer_config(struct mtk_ddp_comp *comp, unsigned int idx, ...@@ -187,7 +202,7 @@ static void mtk_ovl_layer_config(struct mtk_ddp_comp *comp, unsigned int idx,
writel_relaxed(pitch, comp->regs + DISP_REG_OVL_PITCH(idx)); writel_relaxed(pitch, comp->regs + DISP_REG_OVL_PITCH(idx));
writel_relaxed(src_size, comp->regs + DISP_REG_OVL_SRC_SIZE(idx)); writel_relaxed(src_size, comp->regs + DISP_REG_OVL_SRC_SIZE(idx));
writel_relaxed(offset, comp->regs + DISP_REG_OVL_OFFSET(idx)); writel_relaxed(offset, comp->regs + DISP_REG_OVL_OFFSET(idx));
writel_relaxed(addr, comp->regs + DISP_REG_OVL_ADDR(idx)); writel_relaxed(addr, comp->regs + DISP_REG_OVL_ADDR(ovl, idx));
if (pending->enable) if (pending->enable)
mtk_ovl_layer_on(comp, idx); mtk_ovl_layer_on(comp, idx);
...@@ -264,6 +279,8 @@ static int mtk_disp_ovl_probe(struct platform_device *pdev) ...@@ -264,6 +279,8 @@ static int mtk_disp_ovl_probe(struct platform_device *pdev)
return ret; return ret;
} }
priv->data = of_device_get_match_data(dev);
platform_set_drvdata(pdev, priv); platform_set_drvdata(pdev, priv);
ret = devm_request_irq(dev, irq, mtk_disp_ovl_irq_handler, ret = devm_request_irq(dev, irq, mtk_disp_ovl_irq_handler,
...@@ -287,8 +304,21 @@ static int mtk_disp_ovl_remove(struct platform_device *pdev) ...@@ -287,8 +304,21 @@ static int mtk_disp_ovl_remove(struct platform_device *pdev)
return 0; return 0;
} }
static const struct mtk_disp_ovl_data mt2701_ovl_driver_data = {
.addr = DISP_REG_OVL_ADDR_MT2701,
.fmt_rgb565_is_0 = false,
};
static const struct mtk_disp_ovl_data mt8173_ovl_driver_data = {
.addr = DISP_REG_OVL_ADDR_MT8173,
.fmt_rgb565_is_0 = true,
};
static const struct of_device_id mtk_disp_ovl_driver_dt_match[] = { static const struct of_device_id mtk_disp_ovl_driver_dt_match[] = {
{ .compatible = "mediatek,mt8173-disp-ovl", }, { .compatible = "mediatek,mt2701-disp-ovl",
.data = &mt2701_ovl_driver_data},
{ .compatible = "mediatek,mt8173-disp-ovl",
.data = &mt8173_ovl_driver_data},
{}, {},
}; };
MODULE_DEVICE_TABLE(of, mtk_disp_ovl_driver_dt_match); MODULE_DEVICE_TABLE(of, mtk_disp_ovl_driver_dt_match);
......
...@@ -38,6 +38,11 @@ ...@@ -38,6 +38,11 @@
#define RDMA_FIFO_UNDERFLOW_EN BIT(31) #define RDMA_FIFO_UNDERFLOW_EN BIT(31)
#define RDMA_FIFO_PSEUDO_SIZE(bytes) (((bytes) / 16) << 16) #define RDMA_FIFO_PSEUDO_SIZE(bytes) (((bytes) / 16) << 16)
#define RDMA_OUTPUT_VALID_FIFO_THRESHOLD(bytes) ((bytes) / 16) #define RDMA_OUTPUT_VALID_FIFO_THRESHOLD(bytes) ((bytes) / 16)
#define RDMA_FIFO_SIZE(rdma) ((rdma)->data->fifo_size)
struct mtk_disp_rdma_data {
unsigned int fifo_size;
};
/** /**
* struct mtk_disp_rdma - DISP_RDMA driver structure * struct mtk_disp_rdma - DISP_RDMA driver structure
...@@ -47,8 +52,14 @@ ...@@ -47,8 +52,14 @@
struct mtk_disp_rdma { struct mtk_disp_rdma {
struct mtk_ddp_comp ddp_comp; struct mtk_ddp_comp ddp_comp;
struct drm_crtc *crtc; struct drm_crtc *crtc;
const struct mtk_disp_rdma_data *data;
}; };
static inline struct mtk_disp_rdma *comp_to_rdma(struct mtk_ddp_comp *comp)
{
return container_of(comp, struct mtk_disp_rdma, ddp_comp);
}
static irqreturn_t mtk_disp_rdma_irq_handler(int irq, void *dev_id) static irqreturn_t mtk_disp_rdma_irq_handler(int irq, void *dev_id)
{ {
struct mtk_disp_rdma *priv = dev_id; struct mtk_disp_rdma *priv = dev_id;
...@@ -77,20 +88,18 @@ static void rdma_update_bits(struct mtk_ddp_comp *comp, unsigned int reg, ...@@ -77,20 +88,18 @@ static void rdma_update_bits(struct mtk_ddp_comp *comp, unsigned int reg,
static void mtk_rdma_enable_vblank(struct mtk_ddp_comp *comp, static void mtk_rdma_enable_vblank(struct mtk_ddp_comp *comp,
struct drm_crtc *crtc) struct drm_crtc *crtc)
{ {
struct mtk_disp_rdma *priv = container_of(comp, struct mtk_disp_rdma, struct mtk_disp_rdma *rdma = comp_to_rdma(comp);
ddp_comp);
priv->crtc = crtc; rdma->crtc = crtc;
rdma_update_bits(comp, DISP_REG_RDMA_INT_ENABLE, RDMA_FRAME_END_INT, rdma_update_bits(comp, DISP_REG_RDMA_INT_ENABLE, RDMA_FRAME_END_INT,
RDMA_FRAME_END_INT); RDMA_FRAME_END_INT);
} }
static void mtk_rdma_disable_vblank(struct mtk_ddp_comp *comp) static void mtk_rdma_disable_vblank(struct mtk_ddp_comp *comp)
{ {
struct mtk_disp_rdma *priv = container_of(comp, struct mtk_disp_rdma, struct mtk_disp_rdma *rdma = comp_to_rdma(comp);
ddp_comp);
priv->crtc = NULL; rdma->crtc = NULL;
rdma_update_bits(comp, DISP_REG_RDMA_INT_ENABLE, RDMA_FRAME_END_INT, 0); rdma_update_bits(comp, DISP_REG_RDMA_INT_ENABLE, RDMA_FRAME_END_INT, 0);
} }
...@@ -111,6 +120,7 @@ static void mtk_rdma_config(struct mtk_ddp_comp *comp, unsigned int width, ...@@ -111,6 +120,7 @@ static void mtk_rdma_config(struct mtk_ddp_comp *comp, unsigned int width,
{ {
unsigned int threshold; unsigned int threshold;
unsigned int reg; unsigned int reg;
struct mtk_disp_rdma *rdma = comp_to_rdma(comp);
rdma_update_bits(comp, DISP_REG_RDMA_SIZE_CON_0, 0xfff, width); rdma_update_bits(comp, DISP_REG_RDMA_SIZE_CON_0, 0xfff, width);
rdma_update_bits(comp, DISP_REG_RDMA_SIZE_CON_1, 0xfffff, height); rdma_update_bits(comp, DISP_REG_RDMA_SIZE_CON_1, 0xfffff, height);
...@@ -123,7 +133,7 @@ static void mtk_rdma_config(struct mtk_ddp_comp *comp, unsigned int width, ...@@ -123,7 +133,7 @@ static void mtk_rdma_config(struct mtk_ddp_comp *comp, unsigned int width,
*/ */
threshold = width * height * vrefresh * 4 * 7 / 1000000; threshold = width * height * vrefresh * 4 * 7 / 1000000;
reg = RDMA_FIFO_UNDERFLOW_EN | reg = RDMA_FIFO_UNDERFLOW_EN |
RDMA_FIFO_PSEUDO_SIZE(SZ_8K) | RDMA_FIFO_PSEUDO_SIZE(RDMA_FIFO_SIZE(rdma)) |
RDMA_OUTPUT_VALID_FIFO_THRESHOLD(threshold); RDMA_OUTPUT_VALID_FIFO_THRESHOLD(threshold);
writel(reg, comp->regs + DISP_REG_RDMA_FIFO_CON); writel(reg, comp->regs + DISP_REG_RDMA_FIFO_CON);
} }
...@@ -208,6 +218,8 @@ static int mtk_disp_rdma_probe(struct platform_device *pdev) ...@@ -208,6 +218,8 @@ static int mtk_disp_rdma_probe(struct platform_device *pdev)
return ret; return ret;
} }
priv->data = of_device_get_match_data(dev);
platform_set_drvdata(pdev, priv); platform_set_drvdata(pdev, priv);
ret = component_add(dev, &mtk_disp_rdma_component_ops); ret = component_add(dev, &mtk_disp_rdma_component_ops);
...@@ -224,8 +236,19 @@ static int mtk_disp_rdma_remove(struct platform_device *pdev) ...@@ -224,8 +236,19 @@ static int mtk_disp_rdma_remove(struct platform_device *pdev)
return 0; return 0;
} }
static const struct mtk_disp_rdma_data mt2701_rdma_driver_data = {
.fifo_size = SZ_4K,
};
static const struct mtk_disp_rdma_data mt8173_rdma_driver_data = {
.fifo_size = SZ_8K,
};
static const struct of_device_id mtk_disp_rdma_driver_dt_match[] = { static const struct of_device_id mtk_disp_rdma_driver_dt_match[] = {
{ .compatible = "mediatek,mt8173-disp-rdma", }, { .compatible = "mediatek,mt2701-disp-rdma",
.data = &mt2701_rdma_driver_data},
{ .compatible = "mediatek,mt8173-disp-rdma",
.data = &mt8173_rdma_driver_data},
{}, {},
}; };
MODULE_DEVICE_TABLE(of, mtk_disp_rdma_driver_dt_match); MODULE_DEVICE_TABLE(of, mtk_disp_rdma_driver_dt_match);
......
...@@ -327,6 +327,42 @@ static void mtk_crtc_ddp_hw_fini(struct mtk_drm_crtc *mtk_crtc) ...@@ -327,6 +327,42 @@ static void mtk_crtc_ddp_hw_fini(struct mtk_drm_crtc *mtk_crtc)
pm_runtime_put(drm->dev); pm_runtime_put(drm->dev);
} }
static void mtk_crtc_ddp_config(struct drm_crtc *crtc)
{
struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc);
struct mtk_crtc_state *state = to_mtk_crtc_state(mtk_crtc->base.state);
struct mtk_ddp_comp *ovl = mtk_crtc->ddp_comp[0];
unsigned int i;
/*
* TODO: instead of updating the registers here, we should prepare
* working registers in atomic_commit and let the hardware command
* queue update module registers on vblank.
*/
if (state->pending_config) {
mtk_ddp_comp_config(ovl, state->pending_width,
state->pending_height,
state->pending_vrefresh, 0);
state->pending_config = false;
}
if (mtk_crtc->pending_planes) {
for (i = 0; i < OVL_LAYER_NR; i++) {
struct drm_plane *plane = &mtk_crtc->planes[i];
struct mtk_plane_state *plane_state;
plane_state = to_mtk_plane_state(plane->state);
if (plane_state->pending.config) {
mtk_ddp_comp_layer_config(ovl, i, plane_state);
plane_state->pending.config = false;
}
}
mtk_crtc->pending_planes = false;
}
}
static void mtk_drm_crtc_enable(struct drm_crtc *crtc) static void mtk_drm_crtc_enable(struct drm_crtc *crtc)
{ {
struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc); struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc);
...@@ -403,6 +439,7 @@ static void mtk_drm_crtc_atomic_flush(struct drm_crtc *crtc, ...@@ -403,6 +439,7 @@ static void mtk_drm_crtc_atomic_flush(struct drm_crtc *crtc,
struct drm_crtc_state *old_crtc_state) struct drm_crtc_state *old_crtc_state)
{ {
struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc); struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc);
struct mtk_drm_private *priv = crtc->dev->dev_private;
unsigned int pending_planes = 0; unsigned int pending_planes = 0;
int i; int i;
...@@ -424,6 +461,12 @@ static void mtk_drm_crtc_atomic_flush(struct drm_crtc *crtc, ...@@ -424,6 +461,12 @@ static void mtk_drm_crtc_atomic_flush(struct drm_crtc *crtc,
if (crtc->state->color_mgmt_changed) if (crtc->state->color_mgmt_changed)
for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) for (i = 0; i < mtk_crtc->ddp_comp_nr; i++)
mtk_ddp_gamma_set(mtk_crtc->ddp_comp[i], crtc->state); mtk_ddp_gamma_set(mtk_crtc->ddp_comp[i], crtc->state);
if (priv->data->shadow_register) {
mtk_disp_mutex_acquire(mtk_crtc->mutex);
mtk_crtc_ddp_config(crtc);
mtk_disp_mutex_release(mtk_crtc->mutex);
}
} }
static const struct drm_crtc_funcs mtk_crtc_funcs = { static const struct drm_crtc_funcs mtk_crtc_funcs = {
...@@ -471,36 +514,10 @@ static int mtk_drm_crtc_init(struct drm_device *drm, ...@@ -471,36 +514,10 @@ static int mtk_drm_crtc_init(struct drm_device *drm,
void mtk_crtc_ddp_irq(struct drm_crtc *crtc, struct mtk_ddp_comp *ovl) void mtk_crtc_ddp_irq(struct drm_crtc *crtc, struct mtk_ddp_comp *ovl)
{ {
struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc); struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc);
struct mtk_crtc_state *state = to_mtk_crtc_state(mtk_crtc->base.state); struct mtk_drm_private *priv = crtc->dev->dev_private;
unsigned int i;
/* if (!priv->data->shadow_register)
* TODO: instead of updating the registers here, we should prepare mtk_crtc_ddp_config(crtc);
* working registers in atomic_commit and let the hardware command
* queue update module registers on vblank.
*/
if (state->pending_config) {
mtk_ddp_comp_config(ovl, state->pending_width,
state->pending_height,
state->pending_vrefresh, 0);
state->pending_config = false;
}
if (mtk_crtc->pending_planes) {
for (i = 0; i < OVL_LAYER_NR; i++) {
struct drm_plane *plane = &mtk_crtc->planes[i];
struct mtk_plane_state *plane_state;
plane_state = to_mtk_plane_state(plane->state);
if (plane_state->pending.config) {
mtk_ddp_comp_layer_config(ovl, i, plane_state);
plane_state->pending.config = false;
}
}
mtk_crtc->pending_planes = false;
}
mtk_drm_finish_page_flip(mtk_crtc); mtk_drm_finish_page_flip(mtk_crtc);
} }
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
*/ */
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/iopoll.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
...@@ -31,26 +32,40 @@ ...@@ -31,26 +32,40 @@
#define DISP_REG_CONFIG_DISP_RDMA1_MOUT_EN 0x0c8 #define DISP_REG_CONFIG_DISP_RDMA1_MOUT_EN 0x0c8
#define DISP_REG_CONFIG_MMSYS_CG_CON0 0x100 #define DISP_REG_CONFIG_MMSYS_CG_CON0 0x100
#define DISP_REG_CONFIG_DISP_OVL_MOUT_EN 0x030
#define DISP_REG_CONFIG_OUT_SEL 0x04c
#define DISP_REG_CONFIG_DSI_SEL 0x050
#define DISP_REG_MUTEX_EN(n) (0x20 + 0x20 * (n)) #define DISP_REG_MUTEX_EN(n) (0x20 + 0x20 * (n))
#define DISP_REG_MUTEX(n) (0x24 + 0x20 * (n))
#define DISP_REG_MUTEX_RST(n) (0x28 + 0x20 * (n)) #define DISP_REG_MUTEX_RST(n) (0x28 + 0x20 * (n))
#define DISP_REG_MUTEX_MOD(n) (0x2c + 0x20 * (n)) #define DISP_REG_MUTEX_MOD(n) (0x2c + 0x20 * (n))
#define DISP_REG_MUTEX_SOF(n) (0x30 + 0x20 * (n)) #define DISP_REG_MUTEX_SOF(n) (0x30 + 0x20 * (n))
#define MUTEX_MOD_DISP_OVL0 BIT(11) #define INT_MUTEX BIT(1)
#define MUTEX_MOD_DISP_OVL1 BIT(12)
#define MUTEX_MOD_DISP_RDMA0 BIT(13) #define MT8173_MUTEX_MOD_DISP_OVL0 BIT(11)
#define MUTEX_MOD_DISP_RDMA1 BIT(14) #define MT8173_MUTEX_MOD_DISP_OVL1 BIT(12)
#define MUTEX_MOD_DISP_RDMA2 BIT(15) #define MT8173_MUTEX_MOD_DISP_RDMA0 BIT(13)
#define MUTEX_MOD_DISP_WDMA0 BIT(16) #define MT8173_MUTEX_MOD_DISP_RDMA1 BIT(14)
#define MUTEX_MOD_DISP_WDMA1 BIT(17) #define MT8173_MUTEX_MOD_DISP_RDMA2 BIT(15)
#define MUTEX_MOD_DISP_COLOR0 BIT(18) #define MT8173_MUTEX_MOD_DISP_WDMA0 BIT(16)
#define MUTEX_MOD_DISP_COLOR1 BIT(19) #define MT8173_MUTEX_MOD_DISP_WDMA1 BIT(17)
#define MUTEX_MOD_DISP_AAL BIT(20) #define MT8173_MUTEX_MOD_DISP_COLOR0 BIT(18)
#define MUTEX_MOD_DISP_GAMMA BIT(21) #define MT8173_MUTEX_MOD_DISP_COLOR1 BIT(19)
#define MUTEX_MOD_DISP_UFOE BIT(22) #define MT8173_MUTEX_MOD_DISP_AAL BIT(20)
#define MUTEX_MOD_DISP_PWM0 BIT(23) #define MT8173_MUTEX_MOD_DISP_GAMMA BIT(21)
#define MUTEX_MOD_DISP_PWM1 BIT(24) #define MT8173_MUTEX_MOD_DISP_UFOE BIT(22)
#define MUTEX_MOD_DISP_OD BIT(25) #define MT8173_MUTEX_MOD_DISP_PWM0 BIT(23)
#define MT8173_MUTEX_MOD_DISP_PWM1 BIT(24)
#define MT8173_MUTEX_MOD_DISP_OD BIT(25)
#define MT2701_MUTEX_MOD_DISP_OVL BIT(3)
#define MT2701_MUTEX_MOD_DISP_WDMA BIT(6)
#define MT2701_MUTEX_MOD_DISP_COLOR BIT(7)
#define MT2701_MUTEX_MOD_DISP_BLS BIT(9)
#define MT2701_MUTEX_MOD_DISP_RDMA0 BIT(10)
#define MT2701_MUTEX_MOD_DISP_RDMA1 BIT(12)
#define MUTEX_SOF_SINGLE_MODE 0 #define MUTEX_SOF_SINGLE_MODE 0
#define MUTEX_SOF_DSI0 1 #define MUTEX_SOF_DSI0 1
...@@ -67,6 +82,10 @@ ...@@ -67,6 +82,10 @@
#define DPI0_SEL_IN_RDMA1 0x1 #define DPI0_SEL_IN_RDMA1 0x1
#define COLOR1_SEL_IN_OVL1 0x1 #define COLOR1_SEL_IN_OVL1 0x1
#define OVL_MOUT_EN_RDMA 0x1
#define BLS_TO_DSI_RDMA1_TO_DPI1 0x8
#define DSI_SEL_IN_BLS 0x0
struct mtk_disp_mutex { struct mtk_disp_mutex {
int id; int id;
bool claimed; bool claimed;
...@@ -77,24 +96,34 @@ struct mtk_ddp { ...@@ -77,24 +96,34 @@ struct mtk_ddp {
struct clk *clk; struct clk *clk;
void __iomem *regs; void __iomem *regs;
struct mtk_disp_mutex mutex[10]; struct mtk_disp_mutex mutex[10];
const unsigned int *mutex_mod;
};
static const unsigned int mt2701_mutex_mod[DDP_COMPONENT_ID_MAX] = {
[DDP_COMPONENT_BLS] = MT2701_MUTEX_MOD_DISP_BLS,
[DDP_COMPONENT_COLOR0] = MT2701_MUTEX_MOD_DISP_COLOR,
[DDP_COMPONENT_OVL0] = MT2701_MUTEX_MOD_DISP_OVL,
[DDP_COMPONENT_RDMA0] = MT2701_MUTEX_MOD_DISP_RDMA0,
[DDP_COMPONENT_RDMA1] = MT2701_MUTEX_MOD_DISP_RDMA1,
[DDP_COMPONENT_WDMA0] = MT2701_MUTEX_MOD_DISP_WDMA,
}; };
static const unsigned int mutex_mod[DDP_COMPONENT_ID_MAX] = { static const unsigned int mt8173_mutex_mod[DDP_COMPONENT_ID_MAX] = {
[DDP_COMPONENT_AAL] = MUTEX_MOD_DISP_AAL, [DDP_COMPONENT_AAL] = MT8173_MUTEX_MOD_DISP_AAL,
[DDP_COMPONENT_COLOR0] = MUTEX_MOD_DISP_COLOR0, [DDP_COMPONENT_COLOR0] = MT8173_MUTEX_MOD_DISP_COLOR0,
[DDP_COMPONENT_COLOR1] = MUTEX_MOD_DISP_COLOR1, [DDP_COMPONENT_COLOR1] = MT8173_MUTEX_MOD_DISP_COLOR1,
[DDP_COMPONENT_GAMMA] = MUTEX_MOD_DISP_GAMMA, [DDP_COMPONENT_GAMMA] = MT8173_MUTEX_MOD_DISP_GAMMA,
[DDP_COMPONENT_OD] = MUTEX_MOD_DISP_OD, [DDP_COMPONENT_OD] = MT8173_MUTEX_MOD_DISP_OD,
[DDP_COMPONENT_OVL0] = MUTEX_MOD_DISP_OVL0, [DDP_COMPONENT_OVL0] = MT8173_MUTEX_MOD_DISP_OVL0,
[DDP_COMPONENT_OVL1] = MUTEX_MOD_DISP_OVL1, [DDP_COMPONENT_OVL1] = MT8173_MUTEX_MOD_DISP_OVL1,
[DDP_COMPONENT_PWM0] = MUTEX_MOD_DISP_PWM0, [DDP_COMPONENT_PWM0] = MT8173_MUTEX_MOD_DISP_PWM0,
[DDP_COMPONENT_PWM1] = MUTEX_MOD_DISP_PWM1, [DDP_COMPONENT_PWM1] = MT8173_MUTEX_MOD_DISP_PWM1,
[DDP_COMPONENT_RDMA0] = MUTEX_MOD_DISP_RDMA0, [DDP_COMPONENT_RDMA0] = MT8173_MUTEX_MOD_DISP_RDMA0,
[DDP_COMPONENT_RDMA1] = MUTEX_MOD_DISP_RDMA1, [DDP_COMPONENT_RDMA1] = MT8173_MUTEX_MOD_DISP_RDMA1,
[DDP_COMPONENT_RDMA2] = MUTEX_MOD_DISP_RDMA2, [DDP_COMPONENT_RDMA2] = MT8173_MUTEX_MOD_DISP_RDMA2,
[DDP_COMPONENT_UFOE] = MUTEX_MOD_DISP_UFOE, [DDP_COMPONENT_UFOE] = MT8173_MUTEX_MOD_DISP_UFOE,
[DDP_COMPONENT_WDMA0] = MUTEX_MOD_DISP_WDMA0, [DDP_COMPONENT_WDMA0] = MT8173_MUTEX_MOD_DISP_WDMA0,
[DDP_COMPONENT_WDMA1] = MUTEX_MOD_DISP_WDMA1, [DDP_COMPONENT_WDMA1] = MT8173_MUTEX_MOD_DISP_WDMA1,
}; };
static unsigned int mtk_ddp_mout_en(enum mtk_ddp_comp_id cur, static unsigned int mtk_ddp_mout_en(enum mtk_ddp_comp_id cur,
...@@ -106,6 +135,9 @@ static unsigned int mtk_ddp_mout_en(enum mtk_ddp_comp_id cur, ...@@ -106,6 +135,9 @@ static unsigned int mtk_ddp_mout_en(enum mtk_ddp_comp_id cur,
if (cur == DDP_COMPONENT_OVL0 && next == DDP_COMPONENT_COLOR0) { if (cur == DDP_COMPONENT_OVL0 && next == DDP_COMPONENT_COLOR0) {
*addr = DISP_REG_CONFIG_DISP_OVL0_MOUT_EN; *addr = DISP_REG_CONFIG_DISP_OVL0_MOUT_EN;
value = OVL0_MOUT_EN_COLOR0; value = OVL0_MOUT_EN_COLOR0;
} else if (cur == DDP_COMPONENT_OVL0 && next == DDP_COMPONENT_RDMA0) {
*addr = DISP_REG_CONFIG_DISP_OVL_MOUT_EN;
value = OVL_MOUT_EN_RDMA;
} else if (cur == DDP_COMPONENT_OD && next == DDP_COMPONENT_RDMA0) { } else if (cur == DDP_COMPONENT_OD && next == DDP_COMPONENT_RDMA0) {
*addr = DISP_REG_CONFIG_DISP_OD_MOUT_EN; *addr = DISP_REG_CONFIG_DISP_OD_MOUT_EN;
value = OD_MOUT_EN_RDMA0; value = OD_MOUT_EN_RDMA0;
...@@ -143,6 +175,9 @@ static unsigned int mtk_ddp_sel_in(enum mtk_ddp_comp_id cur, ...@@ -143,6 +175,9 @@ static unsigned int mtk_ddp_sel_in(enum mtk_ddp_comp_id cur,
} else if (cur == DDP_COMPONENT_OVL1 && next == DDP_COMPONENT_COLOR1) { } else if (cur == DDP_COMPONENT_OVL1 && next == DDP_COMPONENT_COLOR1) {
*addr = DISP_REG_CONFIG_DISP_COLOR1_SEL_IN; *addr = DISP_REG_CONFIG_DISP_COLOR1_SEL_IN;
value = COLOR1_SEL_IN_OVL1; value = COLOR1_SEL_IN_OVL1;
} else if (cur == DDP_COMPONENT_BLS && next == DDP_COMPONENT_DSI0) {
*addr = DISP_REG_CONFIG_DSI_SEL;
value = DSI_SEL_IN_BLS;
} else { } else {
value = 0; value = 0;
} }
...@@ -150,6 +185,15 @@ static unsigned int mtk_ddp_sel_in(enum mtk_ddp_comp_id cur, ...@@ -150,6 +185,15 @@ static unsigned int mtk_ddp_sel_in(enum mtk_ddp_comp_id cur,
return value; return value;
} }
static void mtk_ddp_sout_sel(void __iomem *config_regs,
enum mtk_ddp_comp_id cur,
enum mtk_ddp_comp_id next)
{
if (cur == DDP_COMPONENT_BLS && next == DDP_COMPONENT_DSI0)
writel_relaxed(BLS_TO_DSI_RDMA1_TO_DPI1,
config_regs + DISP_REG_CONFIG_OUT_SEL);
}
void mtk_ddp_add_comp_to_path(void __iomem *config_regs, void mtk_ddp_add_comp_to_path(void __iomem *config_regs,
enum mtk_ddp_comp_id cur, enum mtk_ddp_comp_id cur,
enum mtk_ddp_comp_id next) enum mtk_ddp_comp_id next)
...@@ -162,6 +206,8 @@ void mtk_ddp_add_comp_to_path(void __iomem *config_regs, ...@@ -162,6 +206,8 @@ void mtk_ddp_add_comp_to_path(void __iomem *config_regs,
writel_relaxed(reg, config_regs + addr); writel_relaxed(reg, config_regs + addr);
} }
mtk_ddp_sout_sel(config_regs, cur, next);
value = mtk_ddp_sel_in(cur, next, &addr); value = mtk_ddp_sel_in(cur, next, &addr);
if (value) { if (value) {
reg = readl_relaxed(config_regs + addr) | value; reg = readl_relaxed(config_regs + addr) | value;
...@@ -247,7 +293,7 @@ void mtk_disp_mutex_add_comp(struct mtk_disp_mutex *mutex, ...@@ -247,7 +293,7 @@ void mtk_disp_mutex_add_comp(struct mtk_disp_mutex *mutex,
break; break;
default: default:
reg = readl_relaxed(ddp->regs + DISP_REG_MUTEX_MOD(mutex->id)); reg = readl_relaxed(ddp->regs + DISP_REG_MUTEX_MOD(mutex->id));
reg |= mutex_mod[id]; reg |= ddp->mutex_mod[id];
writel_relaxed(reg, ddp->regs + DISP_REG_MUTEX_MOD(mutex->id)); writel_relaxed(reg, ddp->regs + DISP_REG_MUTEX_MOD(mutex->id));
return; return;
} }
...@@ -273,7 +319,7 @@ void mtk_disp_mutex_remove_comp(struct mtk_disp_mutex *mutex, ...@@ -273,7 +319,7 @@ void mtk_disp_mutex_remove_comp(struct mtk_disp_mutex *mutex,
break; break;
default: default:
reg = readl_relaxed(ddp->regs + DISP_REG_MUTEX_MOD(mutex->id)); reg = readl_relaxed(ddp->regs + DISP_REG_MUTEX_MOD(mutex->id));
reg &= ~mutex_mod[id]; reg &= ~(ddp->mutex_mod[id]);
writel_relaxed(reg, ddp->regs + DISP_REG_MUTEX_MOD(mutex->id)); writel_relaxed(reg, ddp->regs + DISP_REG_MUTEX_MOD(mutex->id));
break; break;
} }
...@@ -299,6 +345,27 @@ void mtk_disp_mutex_disable(struct mtk_disp_mutex *mutex) ...@@ -299,6 +345,27 @@ void mtk_disp_mutex_disable(struct mtk_disp_mutex *mutex)
writel(0, ddp->regs + DISP_REG_MUTEX_EN(mutex->id)); writel(0, ddp->regs + DISP_REG_MUTEX_EN(mutex->id));
} }
void mtk_disp_mutex_acquire(struct mtk_disp_mutex *mutex)
{
struct mtk_ddp *ddp = container_of(mutex, struct mtk_ddp,
mutex[mutex->id]);
u32 tmp;
writel(1, ddp->regs + DISP_REG_MUTEX_EN(mutex->id));
writel(1, ddp->regs + DISP_REG_MUTEX(mutex->id));
if (readl_poll_timeout_atomic(ddp->regs + DISP_REG_MUTEX(mutex->id),
tmp, tmp & INT_MUTEX, 1, 10000))
pr_err("could not acquire mutex %d\n", mutex->id);
}
void mtk_disp_mutex_release(struct mtk_disp_mutex *mutex)
{
struct mtk_ddp *ddp = container_of(mutex, struct mtk_ddp,
mutex[mutex->id]);
writel(0, ddp->regs + DISP_REG_MUTEX(mutex->id));
}
static int mtk_ddp_probe(struct platform_device *pdev) static int mtk_ddp_probe(struct platform_device *pdev)
{ {
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
...@@ -326,6 +393,8 @@ static int mtk_ddp_probe(struct platform_device *pdev) ...@@ -326,6 +393,8 @@ static int mtk_ddp_probe(struct platform_device *pdev)
return PTR_ERR(ddp->regs); return PTR_ERR(ddp->regs);
} }
ddp->mutex_mod = of_device_get_match_data(dev);
platform_set_drvdata(pdev, ddp); platform_set_drvdata(pdev, ddp);
return 0; return 0;
...@@ -337,7 +406,8 @@ static int mtk_ddp_remove(struct platform_device *pdev) ...@@ -337,7 +406,8 @@ static int mtk_ddp_remove(struct platform_device *pdev)
} }
static const struct of_device_id ddp_driver_dt_match[] = { static const struct of_device_id ddp_driver_dt_match[] = {
{ .compatible = "mediatek,mt8173-disp-mutex" }, { .compatible = "mediatek,mt2701-disp-mutex", .data = mt2701_mutex_mod},
{ .compatible = "mediatek,mt8173-disp-mutex", .data = mt8173_mutex_mod},
{}, {},
}; };
MODULE_DEVICE_TABLE(of, ddp_driver_dt_match); MODULE_DEVICE_TABLE(of, ddp_driver_dt_match);
......
...@@ -37,5 +37,7 @@ void mtk_disp_mutex_remove_comp(struct mtk_disp_mutex *mutex, ...@@ -37,5 +37,7 @@ void mtk_disp_mutex_remove_comp(struct mtk_disp_mutex *mutex,
enum mtk_ddp_comp_id id); enum mtk_ddp_comp_id id);
void mtk_disp_mutex_unprepare(struct mtk_disp_mutex *mutex); void mtk_disp_mutex_unprepare(struct mtk_disp_mutex *mutex);
void mtk_disp_mutex_put(struct mtk_disp_mutex *mutex); void mtk_disp_mutex_put(struct mtk_disp_mutex *mutex);
void mtk_disp_mutex_acquire(struct mtk_disp_mutex *mutex);
void mtk_disp_mutex_release(struct mtk_disp_mutex *mutex);
#endif /* MTK_DRM_DDP_H */ #endif /* MTK_DRM_DDP_H */
...@@ -39,9 +39,11 @@ ...@@ -39,9 +39,11 @@
#define DISP_REG_UFO_START 0x0000 #define DISP_REG_UFO_START 0x0000
#define DISP_COLOR_CFG_MAIN 0x0400 #define DISP_COLOR_CFG_MAIN 0x0400
#define DISP_COLOR_START 0x0c00 #define DISP_COLOR_START_MT2701 0x0f00
#define DISP_COLOR_WIDTH 0x0c50 #define DISP_COLOR_START_MT8173 0x0c00
#define DISP_COLOR_HEIGHT 0x0c54 #define DISP_COLOR_START(comp) ((comp)->data->color_offset)
#define DISP_COLOR_WIDTH(comp) (DISP_COLOR_START(comp) + 0x50)
#define DISP_COLOR_HEIGHT(comp) (DISP_COLOR_START(comp) + 0x54)
#define DISP_AAL_EN 0x0000 #define DISP_AAL_EN 0x0000
#define DISP_AAL_SIZE 0x0030 #define DISP_AAL_SIZE 0x0030
...@@ -80,6 +82,20 @@ ...@@ -80,6 +82,20 @@
#define DITHER_ADD_LSHIFT_G(x) (((x) & 0x7) << 4) #define DITHER_ADD_LSHIFT_G(x) (((x) & 0x7) << 4)
#define DITHER_ADD_RSHIFT_G(x) (((x) & 0x7) << 0) #define DITHER_ADD_RSHIFT_G(x) (((x) & 0x7) << 0)
struct mtk_disp_color_data {
unsigned int color_offset;
};
struct mtk_disp_color {
struct mtk_ddp_comp ddp_comp;
const struct mtk_disp_color_data *data;
};
static inline struct mtk_disp_color *comp_to_color(struct mtk_ddp_comp *comp)
{
return container_of(comp, struct mtk_disp_color, ddp_comp);
}
void mtk_dither_set(struct mtk_ddp_comp *comp, unsigned int bpc, void mtk_dither_set(struct mtk_ddp_comp *comp, unsigned int bpc,
unsigned int CFG) unsigned int CFG)
{ {
...@@ -107,15 +123,19 @@ static void mtk_color_config(struct mtk_ddp_comp *comp, unsigned int w, ...@@ -107,15 +123,19 @@ static void mtk_color_config(struct mtk_ddp_comp *comp, unsigned int w,
unsigned int h, unsigned int vrefresh, unsigned int h, unsigned int vrefresh,
unsigned int bpc) unsigned int bpc)
{ {
writel(w, comp->regs + DISP_COLOR_WIDTH); struct mtk_disp_color *color = comp_to_color(comp);
writel(h, comp->regs + DISP_COLOR_HEIGHT);
writel(w, comp->regs + DISP_COLOR_WIDTH(color));
writel(h, comp->regs + DISP_COLOR_HEIGHT(color));
} }
static void mtk_color_start(struct mtk_ddp_comp *comp) static void mtk_color_start(struct mtk_ddp_comp *comp)
{ {
struct mtk_disp_color *color = comp_to_color(comp);
writel(COLOR_BYPASS_ALL | COLOR_SEQ_SEL, writel(COLOR_BYPASS_ALL | COLOR_SEQ_SEL,
comp->regs + DISP_COLOR_CFG_MAIN); comp->regs + DISP_COLOR_CFG_MAIN);
writel(0x1, comp->regs + DISP_COLOR_START); writel(0x1, comp->regs + DISP_COLOR_START(color));
} }
static void mtk_od_config(struct mtk_ddp_comp *comp, unsigned int w, static void mtk_od_config(struct mtk_ddp_comp *comp, unsigned int w,
...@@ -236,6 +256,7 @@ static const char * const mtk_ddp_comp_stem[MTK_DDP_COMP_TYPE_MAX] = { ...@@ -236,6 +256,7 @@ static const char * const mtk_ddp_comp_stem[MTK_DDP_COMP_TYPE_MAX] = {
[MTK_DISP_PWM] = "pwm", [MTK_DISP_PWM] = "pwm",
[MTK_DISP_MUTEX] = "mutex", [MTK_DISP_MUTEX] = "mutex",
[MTK_DISP_OD] = "od", [MTK_DISP_OD] = "od",
[MTK_DISP_BLS] = "bls",
}; };
struct mtk_ddp_comp_match { struct mtk_ddp_comp_match {
...@@ -246,6 +267,7 @@ struct mtk_ddp_comp_match { ...@@ -246,6 +267,7 @@ struct mtk_ddp_comp_match {
static const struct mtk_ddp_comp_match mtk_ddp_matches[DDP_COMPONENT_ID_MAX] = { static const struct mtk_ddp_comp_match mtk_ddp_matches[DDP_COMPONENT_ID_MAX] = {
[DDP_COMPONENT_AAL] = { MTK_DISP_AAL, 0, &ddp_aal }, [DDP_COMPONENT_AAL] = { MTK_DISP_AAL, 0, &ddp_aal },
[DDP_COMPONENT_BLS] = { MTK_DISP_BLS, 0, NULL },
[DDP_COMPONENT_COLOR0] = { MTK_DISP_COLOR, 0, &ddp_color }, [DDP_COMPONENT_COLOR0] = { MTK_DISP_COLOR, 0, &ddp_color },
[DDP_COMPONENT_COLOR1] = { MTK_DISP_COLOR, 1, &ddp_color }, [DDP_COMPONENT_COLOR1] = { MTK_DISP_COLOR, 1, &ddp_color },
[DDP_COMPONENT_DPI0] = { MTK_DPI, 0, NULL }, [DDP_COMPONENT_DPI0] = { MTK_DPI, 0, NULL },
...@@ -264,6 +286,22 @@ static const struct mtk_ddp_comp_match mtk_ddp_matches[DDP_COMPONENT_ID_MAX] = { ...@@ -264,6 +286,22 @@ static const struct mtk_ddp_comp_match mtk_ddp_matches[DDP_COMPONENT_ID_MAX] = {
[DDP_COMPONENT_WDMA1] = { MTK_DISP_WDMA, 1, NULL }, [DDP_COMPONENT_WDMA1] = { MTK_DISP_WDMA, 1, NULL },
}; };
static const struct mtk_disp_color_data mt2701_color_driver_data = {
.color_offset = DISP_COLOR_START_MT2701,
};
static const struct mtk_disp_color_data mt8173_color_driver_data = {
.color_offset = DISP_COLOR_START_MT8173,
};
static const struct of_device_id mtk_disp_color_driver_dt_match[] = {
{ .compatible = "mediatek,mt2701-disp-color",
.data = &mt2701_color_driver_data},
{ .compatible = "mediatek,mt8173-disp-color",
.data = &mt8173_color_driver_data},
{},
};
int mtk_ddp_comp_get_id(struct device_node *node, int mtk_ddp_comp_get_id(struct device_node *node,
enum mtk_ddp_comp_type comp_type) enum mtk_ddp_comp_type comp_type)
{ {
...@@ -286,14 +324,29 @@ int mtk_ddp_comp_init(struct device *dev, struct device_node *node, ...@@ -286,14 +324,29 @@ int mtk_ddp_comp_init(struct device *dev, struct device_node *node,
enum mtk_ddp_comp_type type; enum mtk_ddp_comp_type type;
struct device_node *larb_node; struct device_node *larb_node;
struct platform_device *larb_pdev; struct platform_device *larb_pdev;
const struct of_device_id *match;
struct mtk_disp_color *color;
if (comp_id < 0 || comp_id >= DDP_COMPONENT_ID_MAX) if (comp_id < 0 || comp_id >= DDP_COMPONENT_ID_MAX)
return -EINVAL; return -EINVAL;
type = mtk_ddp_matches[comp_id].type;
if (type == MTK_DISP_COLOR) {
devm_kfree(dev, comp);
color = devm_kzalloc(dev, sizeof(*color), GFP_KERNEL);
if (!color)
return -ENOMEM;
match = of_match_node(mtk_disp_color_driver_dt_match, node);
color->data = match->data;
comp = &color->ddp_comp;
}
comp->id = comp_id; comp->id = comp_id;
comp->funcs = funcs ?: mtk_ddp_matches[comp_id].funcs; comp->funcs = funcs ?: mtk_ddp_matches[comp_id].funcs;
if (comp_id == DDP_COMPONENT_DPI0 || if (comp_id == DDP_COMPONENT_BLS ||
comp_id == DDP_COMPONENT_DPI0 ||
comp_id == DDP_COMPONENT_DSI0 || comp_id == DDP_COMPONENT_DSI0 ||
comp_id == DDP_COMPONENT_PWM0) { comp_id == DDP_COMPONENT_PWM0) {
comp->regs = NULL; comp->regs = NULL;
...@@ -308,8 +361,6 @@ int mtk_ddp_comp_init(struct device *dev, struct device_node *node, ...@@ -308,8 +361,6 @@ int mtk_ddp_comp_init(struct device *dev, struct device_node *node,
if (IS_ERR(comp->clk)) if (IS_ERR(comp->clk))
comp->clk = NULL; comp->clk = NULL;
type = mtk_ddp_matches[comp_id].type;
/* Only DMA capable components need the LARB property */ /* Only DMA capable components need the LARB property */
comp->larb_dev = NULL; comp->larb_dev = NULL;
if (type != MTK_DISP_OVL && if (type != MTK_DISP_OVL &&
......
...@@ -36,11 +36,13 @@ enum mtk_ddp_comp_type { ...@@ -36,11 +36,13 @@ enum mtk_ddp_comp_type {
MTK_DISP_PWM, MTK_DISP_PWM,
MTK_DISP_MUTEX, MTK_DISP_MUTEX,
MTK_DISP_OD, MTK_DISP_OD,
MTK_DISP_BLS,
MTK_DDP_COMP_TYPE_MAX, MTK_DDP_COMP_TYPE_MAX,
}; };
enum mtk_ddp_comp_id { enum mtk_ddp_comp_id {
DDP_COMPONENT_AAL, DDP_COMPONENT_AAL,
DDP_COMPONENT_BLS,
DDP_COMPONENT_COLOR0, DDP_COMPONENT_COLOR0,
DDP_COMPONENT_COLOR1, DDP_COMPONENT_COLOR1,
DDP_COMPONENT_DPI0, DDP_COMPONENT_DPI0,
......
...@@ -128,7 +128,20 @@ static const struct drm_mode_config_funcs mtk_drm_mode_config_funcs = { ...@@ -128,7 +128,20 @@ static const struct drm_mode_config_funcs mtk_drm_mode_config_funcs = {
.atomic_commit = mtk_atomic_commit, .atomic_commit = mtk_atomic_commit,
}; };
static const enum mtk_ddp_comp_id mtk_ddp_main[] = { static const enum mtk_ddp_comp_id mt2701_mtk_ddp_main[] = {
DDP_COMPONENT_OVL0,
DDP_COMPONENT_RDMA0,
DDP_COMPONENT_COLOR0,
DDP_COMPONENT_BLS,
DDP_COMPONENT_DSI0,
};
static const enum mtk_ddp_comp_id mt2701_mtk_ddp_ext[] = {
DDP_COMPONENT_RDMA1,
DDP_COMPONENT_DPI0,
};
static const enum mtk_ddp_comp_id mt8173_mtk_ddp_main[] = {
DDP_COMPONENT_OVL0, DDP_COMPONENT_OVL0,
DDP_COMPONENT_COLOR0, DDP_COMPONENT_COLOR0,
DDP_COMPONENT_AAL, DDP_COMPONENT_AAL,
...@@ -139,7 +152,7 @@ static const enum mtk_ddp_comp_id mtk_ddp_main[] = { ...@@ -139,7 +152,7 @@ static const enum mtk_ddp_comp_id mtk_ddp_main[] = {
DDP_COMPONENT_PWM0, DDP_COMPONENT_PWM0,
}; };
static const enum mtk_ddp_comp_id mtk_ddp_ext[] = { static const enum mtk_ddp_comp_id mt8173_mtk_ddp_ext[] = {
DDP_COMPONENT_OVL1, DDP_COMPONENT_OVL1,
DDP_COMPONENT_COLOR1, DDP_COMPONENT_COLOR1,
DDP_COMPONENT_GAMMA, DDP_COMPONENT_GAMMA,
...@@ -147,6 +160,21 @@ static const enum mtk_ddp_comp_id mtk_ddp_ext[] = { ...@@ -147,6 +160,21 @@ static const enum mtk_ddp_comp_id mtk_ddp_ext[] = {
DDP_COMPONENT_DPI0, DDP_COMPONENT_DPI0,
}; };
static const struct mtk_mmsys_driver_data mt2701_mmsys_driver_data = {
.main_path = mt2701_mtk_ddp_main,
.main_len = ARRAY_SIZE(mt2701_mtk_ddp_main),
.ext_path = mt2701_mtk_ddp_ext,
.ext_len = ARRAY_SIZE(mt2701_mtk_ddp_ext),
.shadow_register = true,
};
static const struct mtk_mmsys_driver_data mt8173_mmsys_driver_data = {
.main_path = mt8173_mtk_ddp_main,
.main_len = ARRAY_SIZE(mt8173_mtk_ddp_main),
.ext_path = mt8173_mtk_ddp_ext,
.ext_len = ARRAY_SIZE(mt8173_mtk_ddp_ext),
};
static int mtk_drm_kms_init(struct drm_device *drm) static int mtk_drm_kms_init(struct drm_device *drm)
{ {
struct mtk_drm_private *private = drm->dev_private; struct mtk_drm_private *private = drm->dev_private;
...@@ -189,17 +217,19 @@ static int mtk_drm_kms_init(struct drm_device *drm) ...@@ -189,17 +217,19 @@ static int mtk_drm_kms_init(struct drm_device *drm)
* and each statically assigned to a crtc: * and each statically assigned to a crtc:
* OVL0 -> COLOR0 -> AAL -> OD -> RDMA0 -> UFOE -> DSI0 ... * OVL0 -> COLOR0 -> AAL -> OD -> RDMA0 -> UFOE -> DSI0 ...
*/ */
ret = mtk_drm_crtc_create(drm, mtk_ddp_main, ARRAY_SIZE(mtk_ddp_main)); ret = mtk_drm_crtc_create(drm, private->data->main_path,
private->data->main_len);
if (ret < 0) if (ret < 0)
goto err_component_unbind; goto err_component_unbind;
/* ... and OVL1 -> COLOR1 -> GAMMA -> RDMA1 -> DPI0. */ /* ... and OVL1 -> COLOR1 -> GAMMA -> RDMA1 -> DPI0. */
ret = mtk_drm_crtc_create(drm, mtk_ddp_ext, ARRAY_SIZE(mtk_ddp_ext)); ret = mtk_drm_crtc_create(drm, private->data->ext_path,
private->data->ext_len);
if (ret < 0) if (ret < 0)
goto err_component_unbind; goto err_component_unbind;
/* Use OVL device for all DMA memory allocations */ /* Use OVL device for all DMA memory allocations */
np = private->comp_node[mtk_ddp_main[0]] ?: np = private->comp_node[private->data->main_path[0]] ?:
private->comp_node[mtk_ddp_ext[0]]; private->comp_node[private->data->ext_path[0]];
pdev = of_find_device_by_node(np); pdev = of_find_device_by_node(np);
if (!pdev) { if (!pdev) {
ret = -ENODEV; ret = -ENODEV;
...@@ -328,16 +358,22 @@ static const struct component_master_ops mtk_drm_ops = { ...@@ -328,16 +358,22 @@ static const struct component_master_ops mtk_drm_ops = {
}; };
static const struct of_device_id mtk_ddp_comp_dt_ids[] = { static const struct of_device_id mtk_ddp_comp_dt_ids[] = {
{ .compatible = "mediatek,mt2701-disp-ovl", .data = (void *)MTK_DISP_OVL },
{ .compatible = "mediatek,mt8173-disp-ovl", .data = (void *)MTK_DISP_OVL }, { .compatible = "mediatek,mt8173-disp-ovl", .data = (void *)MTK_DISP_OVL },
{ .compatible = "mediatek,mt2701-disp-rdma", .data = (void *)MTK_DISP_RDMA },
{ .compatible = "mediatek,mt8173-disp-rdma", .data = (void *)MTK_DISP_RDMA }, { .compatible = "mediatek,mt8173-disp-rdma", .data = (void *)MTK_DISP_RDMA },
{ .compatible = "mediatek,mt8173-disp-wdma", .data = (void *)MTK_DISP_WDMA }, { .compatible = "mediatek,mt8173-disp-wdma", .data = (void *)MTK_DISP_WDMA },
{ .compatible = "mediatek,mt2701-disp-color", .data = (void *)MTK_DISP_COLOR },
{ .compatible = "mediatek,mt8173-disp-color", .data = (void *)MTK_DISP_COLOR }, { .compatible = "mediatek,mt8173-disp-color", .data = (void *)MTK_DISP_COLOR },
{ .compatible = "mediatek,mt8173-disp-aal", .data = (void *)MTK_DISP_AAL}, { .compatible = "mediatek,mt8173-disp-aal", .data = (void *)MTK_DISP_AAL},
{ .compatible = "mediatek,mt8173-disp-gamma", .data = (void *)MTK_DISP_GAMMA, }, { .compatible = "mediatek,mt8173-disp-gamma", .data = (void *)MTK_DISP_GAMMA, },
{ .compatible = "mediatek,mt8173-disp-ufoe", .data = (void *)MTK_DISP_UFOE }, { .compatible = "mediatek,mt8173-disp-ufoe", .data = (void *)MTK_DISP_UFOE },
{ .compatible = "mediatek,mt2701-dsi", .data = (void *)MTK_DSI },
{ .compatible = "mediatek,mt8173-dsi", .data = (void *)MTK_DSI }, { .compatible = "mediatek,mt8173-dsi", .data = (void *)MTK_DSI },
{ .compatible = "mediatek,mt8173-dpi", .data = (void *)MTK_DPI }, { .compatible = "mediatek,mt8173-dpi", .data = (void *)MTK_DPI },
{ .compatible = "mediatek,mt2701-disp-mutex", .data = (void *)MTK_DISP_MUTEX },
{ .compatible = "mediatek,mt8173-disp-mutex", .data = (void *)MTK_DISP_MUTEX }, { .compatible = "mediatek,mt8173-disp-mutex", .data = (void *)MTK_DISP_MUTEX },
{ .compatible = "mediatek,mt2701-disp-pwm", .data = (void *)MTK_DISP_BLS },
{ .compatible = "mediatek,mt8173-disp-pwm", .data = (void *)MTK_DISP_PWM }, { .compatible = "mediatek,mt8173-disp-pwm", .data = (void *)MTK_DISP_PWM },
{ .compatible = "mediatek,mt8173-disp-od", .data = (void *)MTK_DISP_OD }, { .compatible = "mediatek,mt8173-disp-od", .data = (void *)MTK_DISP_OD },
{ } { }
...@@ -359,6 +395,7 @@ static int mtk_drm_probe(struct platform_device *pdev) ...@@ -359,6 +395,7 @@ static int mtk_drm_probe(struct platform_device *pdev)
mutex_init(&private->commit.lock); mutex_init(&private->commit.lock);
INIT_WORK(&private->commit.work, mtk_atomic_work); INIT_WORK(&private->commit.work, mtk_atomic_work);
private->data = of_device_get_match_data(dev);
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
private->config_regs = devm_ioremap_resource(dev, mem); private->config_regs = devm_ioremap_resource(dev, mem);
...@@ -510,7 +547,10 @@ static SIMPLE_DEV_PM_OPS(mtk_drm_pm_ops, mtk_drm_sys_suspend, ...@@ -510,7 +547,10 @@ static SIMPLE_DEV_PM_OPS(mtk_drm_pm_ops, mtk_drm_sys_suspend,
mtk_drm_sys_resume); mtk_drm_sys_resume);
static const struct of_device_id mtk_drm_of_ids[] = { static const struct of_device_id mtk_drm_of_ids[] = {
{ .compatible = "mediatek,mt8173-mmsys", }, { .compatible = "mediatek,mt2701-mmsys",
.data = &mt2701_mmsys_driver_data},
{ .compatible = "mediatek,mt8173-mmsys",
.data = &mt8173_mmsys_driver_data},
{ } { }
}; };
......
...@@ -28,6 +28,14 @@ struct drm_fb_helper; ...@@ -28,6 +28,14 @@ struct drm_fb_helper;
struct drm_property; struct drm_property;
struct regmap; struct regmap;
struct mtk_mmsys_driver_data {
const enum mtk_ddp_comp_id *main_path;
unsigned int main_len;
const enum mtk_ddp_comp_id *ext_path;
unsigned int ext_len;
bool shadow_register;
};
struct mtk_drm_private { struct mtk_drm_private {
struct drm_device *drm; struct drm_device *drm;
struct device *dma_dev; struct device *dma_dev;
...@@ -39,6 +47,7 @@ struct mtk_drm_private { ...@@ -39,6 +47,7 @@ struct mtk_drm_private {
void __iomem *config_regs; void __iomem *config_regs;
struct device_node *comp_node[DDP_COMPONENT_ID_MAX]; struct device_node *comp_node[DDP_COMPONENT_ID_MAX];
struct mtk_ddp_comp *ddp_comp[DDP_COMPONENT_ID_MAX]; struct mtk_ddp_comp *ddp_comp[DDP_COMPONENT_ID_MAX];
const struct mtk_mmsys_driver_data *data;
struct { struct {
struct drm_atomic_state *state; struct drm_atomic_state *state;
......
...@@ -18,20 +18,29 @@ ...@@ -18,20 +18,29 @@
#include <drm/drm_panel.h> #include <drm/drm_panel.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/component.h> #include <linux/component.h>
#include <linux/irq.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_platform.h> #include <linux/of_platform.h>
#include <linux/of_graph.h> #include <linux/of_graph.h>
#include <linux/phy/phy.h> #include <linux/phy/phy.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <video/mipi_display.h>
#include <video/videomode.h> #include <video/videomode.h>
#include "mtk_drm_ddp_comp.h" #include "mtk_drm_ddp_comp.h"
#define DSI_VIDEO_FIFO_DEPTH (1920 / 4)
#define DSI_HOST_FIFO_DEPTH 64
#define DSI_START 0x00 #define DSI_START 0x00
#define DSI_INTEN 0x08
#define DSI_INTSTA 0x0c
#define LPRX_RD_RDY_INT_FLAG BIT(0)
#define CMD_DONE_INT_FLAG BIT(1)
#define TE_RDY_INT_FLAG BIT(2)
#define VM_DONE_INT_FLAG BIT(3)
#define EXT_TE_RDY_INT_FLAG BIT(4)
#define DSI_BUSY BIT(31)
#define DSI_CON_CTRL 0x10 #define DSI_CON_CTRL 0x10
#define DSI_RESET BIT(0) #define DSI_RESET BIT(0)
#define DSI_EN BIT(1) #define DSI_EN BIT(1)
...@@ -46,7 +55,7 @@ ...@@ -46,7 +55,7 @@
#define MIX_MODE BIT(17) #define MIX_MODE BIT(17)
#define DSI_TXRX_CTRL 0x18 #define DSI_TXRX_CTRL 0x18
#define VC_NUM (2 << 0) #define VC_NUM BIT(1)
#define LANE_NUM (0xf << 2) #define LANE_NUM (0xf << 2)
#define DIS_EOT BIT(6) #define DIS_EOT BIT(6)
#define NULL_EN BIT(7) #define NULL_EN BIT(7)
...@@ -72,8 +81,19 @@ ...@@ -72,8 +81,19 @@
#define DSI_HBP_WC 0x54 #define DSI_HBP_WC 0x54
#define DSI_HFP_WC 0x58 #define DSI_HFP_WC 0x58
#define DSI_CMDQ_SIZE 0x60
#define CMDQ_SIZE 0x3f
#define DSI_HSTX_CKL_WC 0x64 #define DSI_HSTX_CKL_WC 0x64
#define DSI_RX_DATA0 0x74
#define DSI_RX_DATA1 0x78
#define DSI_RX_DATA2 0x7c
#define DSI_RX_DATA3 0x80
#define DSI_RACK 0x84
#define RACK BIT(0)
#define DSI_PHY_LCCON 0x104 #define DSI_PHY_LCCON 0x104
#define LC_HS_TX_EN BIT(0) #define LC_HS_TX_EN BIT(0)
#define LC_ULPM_EN BIT(1) #define LC_ULPM_EN BIT(1)
...@@ -106,6 +126,19 @@ ...@@ -106,6 +126,19 @@
#define CLK_HS_POST (0xff << 8) #define CLK_HS_POST (0xff << 8)
#define CLK_HS_EXIT (0xff << 16) #define CLK_HS_EXIT (0xff << 16)
#define DSI_VM_CMD_CON 0x130
#define VM_CMD_EN BIT(0)
#define TS_VFP_EN BIT(5)
#define DSI_CMDQ0 0x180
#define CONFIG (0xff << 0)
#define SHORT_PACKET 0
#define LONG_PACKET 2
#define BTA BIT(2)
#define DATA_ID (0xff << 8)
#define DATA_0 (0xff << 16)
#define DATA_1 (0xff << 24)
#define T_LPX 5 #define T_LPX 5
#define T_HS_PREP 6 #define T_HS_PREP 6
#define T_HS_TRAIL 8 #define T_HS_TRAIL 8
...@@ -114,6 +147,12 @@ ...@@ -114,6 +147,12 @@
#define NS_TO_CYCLE(n, c) ((n) / (c) + (((n) % (c)) ? 1 : 0)) #define NS_TO_CYCLE(n, c) ((n) / (c) + (((n) % (c)) ? 1 : 0))
#define MTK_DSI_HOST_IS_READ(type) \
((type == MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM) || \
(type == MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM) || \
(type == MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM) || \
(type == MIPI_DSI_DCS_READ))
struct phy; struct phy;
struct mtk_dsi { struct mtk_dsi {
...@@ -140,6 +179,8 @@ struct mtk_dsi { ...@@ -140,6 +179,8 @@ struct mtk_dsi {
struct videomode vm; struct videomode vm;
int refcount; int refcount;
bool enabled; bool enabled;
u32 irq_data;
wait_queue_head_t irq_wait_queue;
}; };
static inline struct mtk_dsi *encoder_to_dsi(struct drm_encoder *e) static inline struct mtk_dsi *encoder_to_dsi(struct drm_encoder *e)
...@@ -164,7 +205,7 @@ static void mtk_dsi_mask(struct mtk_dsi *dsi, u32 offset, u32 mask, u32 data) ...@@ -164,7 +205,7 @@ static void mtk_dsi_mask(struct mtk_dsi *dsi, u32 offset, u32 mask, u32 data)
writel((temp & ~mask) | (data & mask), dsi->regs + offset); writel((temp & ~mask) | (data & mask), dsi->regs + offset);
} }
static void dsi_phy_timconfig(struct mtk_dsi *dsi) static void mtk_dsi_phy_timconfig(struct mtk_dsi *dsi)
{ {
u32 timcon0, timcon1, timcon2, timcon3; u32 timcon0, timcon1, timcon2, timcon3;
u32 ui, cycle_time; u32 ui, cycle_time;
...@@ -196,118 +237,39 @@ static void mtk_dsi_disable(struct mtk_dsi *dsi) ...@@ -196,118 +237,39 @@ static void mtk_dsi_disable(struct mtk_dsi *dsi)
mtk_dsi_mask(dsi, DSI_CON_CTRL, DSI_EN, 0); mtk_dsi_mask(dsi, DSI_CON_CTRL, DSI_EN, 0);
} }
static void mtk_dsi_reset(struct mtk_dsi *dsi) static void mtk_dsi_reset_engine(struct mtk_dsi *dsi)
{ {
mtk_dsi_mask(dsi, DSI_CON_CTRL, DSI_RESET, DSI_RESET); mtk_dsi_mask(dsi, DSI_CON_CTRL, DSI_RESET, DSI_RESET);
mtk_dsi_mask(dsi, DSI_CON_CTRL, DSI_RESET, 0); mtk_dsi_mask(dsi, DSI_CON_CTRL, DSI_RESET, 0);
} }
static int mtk_dsi_poweron(struct mtk_dsi *dsi) static void mtk_dsi_clk_ulp_mode_enter(struct mtk_dsi *dsi)
{
struct device *dev = dsi->dev;
int ret;
u64 pixel_clock, total_bits;
u32 htotal, htotal_bits, bit_per_pixel, overhead_cycles, overhead_bits;
if (++dsi->refcount != 1)
return 0;
switch (dsi->format) {
case MIPI_DSI_FMT_RGB565:
bit_per_pixel = 16;
break;
case MIPI_DSI_FMT_RGB666_PACKED:
bit_per_pixel = 18;
break;
case MIPI_DSI_FMT_RGB666:
case MIPI_DSI_FMT_RGB888:
default:
bit_per_pixel = 24;
break;
}
/**
* vm.pixelclock is in kHz, pixel_clock unit is Hz, so multiply by 1000
* htotal_time = htotal * byte_per_pixel / num_lanes
* overhead_time = lpx + hs_prepare + hs_zero + hs_trail + hs_exit
* mipi_ratio = (htotal_time + overhead_time) / htotal_time
* data_rate = pixel_clock * bit_per_pixel * mipi_ratio / num_lanes;
*/
pixel_clock = dsi->vm.pixelclock * 1000;
htotal = dsi->vm.hactive + dsi->vm.hback_porch + dsi->vm.hfront_porch +
dsi->vm.hsync_len;
htotal_bits = htotal * bit_per_pixel;
overhead_cycles = T_LPX + T_HS_PREP + T_HS_ZERO + T_HS_TRAIL +
T_HS_EXIT;
overhead_bits = overhead_cycles * dsi->lanes * 8;
total_bits = htotal_bits + overhead_bits;
dsi->data_rate = DIV_ROUND_UP_ULL(pixel_clock * total_bits,
htotal * dsi->lanes);
ret = clk_set_rate(dsi->hs_clk, dsi->data_rate);
if (ret < 0) {
dev_err(dev, "Failed to set data rate: %d\n", ret);
goto err_refcount;
}
phy_power_on(dsi->phy);
ret = clk_prepare_enable(dsi->engine_clk);
if (ret < 0) {
dev_err(dev, "Failed to enable engine clock: %d\n", ret);
goto err_phy_power_off;
}
ret = clk_prepare_enable(dsi->digital_clk);
if (ret < 0) {
dev_err(dev, "Failed to enable digital clock: %d\n", ret);
goto err_disable_engine_clk;
}
mtk_dsi_enable(dsi);
mtk_dsi_reset(dsi);
dsi_phy_timconfig(dsi);
return 0;
err_disable_engine_clk:
clk_disable_unprepare(dsi->engine_clk);
err_phy_power_off:
phy_power_off(dsi->phy);
err_refcount:
dsi->refcount--;
return ret;
}
static void dsi_clk_ulp_mode_enter(struct mtk_dsi *dsi)
{ {
mtk_dsi_mask(dsi, DSI_PHY_LCCON, LC_HS_TX_EN, 0); mtk_dsi_mask(dsi, DSI_PHY_LCCON, LC_HS_TX_EN, 0);
mtk_dsi_mask(dsi, DSI_PHY_LCCON, LC_ULPM_EN, 0); mtk_dsi_mask(dsi, DSI_PHY_LCCON, LC_ULPM_EN, 0);
} }
static void dsi_clk_ulp_mode_leave(struct mtk_dsi *dsi) static void mtk_dsi_clk_ulp_mode_leave(struct mtk_dsi *dsi)
{ {
mtk_dsi_mask(dsi, DSI_PHY_LCCON, LC_ULPM_EN, 0); mtk_dsi_mask(dsi, DSI_PHY_LCCON, LC_ULPM_EN, 0);
mtk_dsi_mask(dsi, DSI_PHY_LCCON, LC_WAKEUP_EN, LC_WAKEUP_EN); mtk_dsi_mask(dsi, DSI_PHY_LCCON, LC_WAKEUP_EN, LC_WAKEUP_EN);
mtk_dsi_mask(dsi, DSI_PHY_LCCON, LC_WAKEUP_EN, 0); mtk_dsi_mask(dsi, DSI_PHY_LCCON, LC_WAKEUP_EN, 0);
} }
static void dsi_lane0_ulp_mode_enter(struct mtk_dsi *dsi) static void mtk_dsi_lane0_ulp_mode_enter(struct mtk_dsi *dsi)
{ {
mtk_dsi_mask(dsi, DSI_PHY_LD0CON, LD0_HS_TX_EN, 0); mtk_dsi_mask(dsi, DSI_PHY_LD0CON, LD0_HS_TX_EN, 0);
mtk_dsi_mask(dsi, DSI_PHY_LD0CON, LD0_ULPM_EN, 0); mtk_dsi_mask(dsi, DSI_PHY_LD0CON, LD0_ULPM_EN, 0);
} }
static void dsi_lane0_ulp_mode_leave(struct mtk_dsi *dsi) static void mtk_dsi_lane0_ulp_mode_leave(struct mtk_dsi *dsi)
{ {
mtk_dsi_mask(dsi, DSI_PHY_LD0CON, LD0_ULPM_EN, 0); mtk_dsi_mask(dsi, DSI_PHY_LD0CON, LD0_ULPM_EN, 0);
mtk_dsi_mask(dsi, DSI_PHY_LD0CON, LD0_WAKEUP_EN, LD0_WAKEUP_EN); mtk_dsi_mask(dsi, DSI_PHY_LD0CON, LD0_WAKEUP_EN, LD0_WAKEUP_EN);
mtk_dsi_mask(dsi, DSI_PHY_LD0CON, LD0_WAKEUP_EN, 0); mtk_dsi_mask(dsi, DSI_PHY_LD0CON, LD0_WAKEUP_EN, 0);
} }
static bool dsi_clk_hs_state(struct mtk_dsi *dsi) static bool mtk_dsi_clk_hs_state(struct mtk_dsi *dsi)
{ {
u32 tmp_reg1; u32 tmp_reg1;
...@@ -315,30 +277,37 @@ static bool dsi_clk_hs_state(struct mtk_dsi *dsi) ...@@ -315,30 +277,37 @@ static bool dsi_clk_hs_state(struct mtk_dsi *dsi)
return ((tmp_reg1 & LC_HS_TX_EN) == 1) ? true : false; return ((tmp_reg1 & LC_HS_TX_EN) == 1) ? true : false;
} }
static void dsi_clk_hs_mode(struct mtk_dsi *dsi, bool enter) static void mtk_dsi_clk_hs_mode(struct mtk_dsi *dsi, bool enter)
{ {
if (enter && !dsi_clk_hs_state(dsi)) if (enter && !mtk_dsi_clk_hs_state(dsi))
mtk_dsi_mask(dsi, DSI_PHY_LCCON, LC_HS_TX_EN, LC_HS_TX_EN); mtk_dsi_mask(dsi, DSI_PHY_LCCON, LC_HS_TX_EN, LC_HS_TX_EN);
else if (!enter && dsi_clk_hs_state(dsi)) else if (!enter && mtk_dsi_clk_hs_state(dsi))
mtk_dsi_mask(dsi, DSI_PHY_LCCON, LC_HS_TX_EN, 0); mtk_dsi_mask(dsi, DSI_PHY_LCCON, LC_HS_TX_EN, 0);
} }
static void dsi_set_mode(struct mtk_dsi *dsi) static void mtk_dsi_set_mode(struct mtk_dsi *dsi)
{ {
u32 vid_mode = CMD_MODE; u32 vid_mode = CMD_MODE;
if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO) { if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO) {
vid_mode = SYNC_PULSE_MODE; if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_BURST)
if ((dsi->mode_flags & MIPI_DSI_MODE_VIDEO_BURST) &&
!(dsi->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE))
vid_mode = BURST_MODE; vid_mode = BURST_MODE;
else if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE)
vid_mode = SYNC_PULSE_MODE;
else
vid_mode = SYNC_EVENT_MODE;
} }
writel(vid_mode, dsi->regs + DSI_MODE_CTRL); writel(vid_mode, dsi->regs + DSI_MODE_CTRL);
} }
static void dsi_ps_control_vact(struct mtk_dsi *dsi) static void mtk_dsi_set_vm_cmd(struct mtk_dsi *dsi)
{
mtk_dsi_mask(dsi, DSI_VM_CMD_CON, VM_CMD_EN, VM_CMD_EN);
mtk_dsi_mask(dsi, DSI_VM_CMD_CON, TS_VFP_EN, TS_VFP_EN);
}
static void mtk_dsi_ps_control_vact(struct mtk_dsi *dsi)
{ {
struct videomode *vm = &dsi->vm; struct videomode *vm = &dsi->vm;
u32 dsi_buf_bpp, ps_wc; u32 dsi_buf_bpp, ps_wc;
...@@ -372,7 +341,7 @@ static void dsi_ps_control_vact(struct mtk_dsi *dsi) ...@@ -372,7 +341,7 @@ static void dsi_ps_control_vact(struct mtk_dsi *dsi)
writel(ps_wc, dsi->regs + DSI_HSTX_CKL_WC); writel(ps_wc, dsi->regs + DSI_HSTX_CKL_WC);
} }
static void dsi_rxtx_control(struct mtk_dsi *dsi) static void mtk_dsi_rxtx_control(struct mtk_dsi *dsi)
{ {
u32 tmp_reg; u32 tmp_reg;
...@@ -394,12 +363,15 @@ static void dsi_rxtx_control(struct mtk_dsi *dsi) ...@@ -394,12 +363,15 @@ static void dsi_rxtx_control(struct mtk_dsi *dsi)
break; break;
} }
tmp_reg |= (dsi->mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS) << 6;
tmp_reg |= (dsi->mode_flags & MIPI_DSI_MODE_EOT_PACKET) >> 3;
writel(tmp_reg, dsi->regs + DSI_TXRX_CTRL); writel(tmp_reg, dsi->regs + DSI_TXRX_CTRL);
} }
static void dsi_ps_control(struct mtk_dsi *dsi) static void mtk_dsi_ps_control(struct mtk_dsi *dsi)
{ {
unsigned int dsi_tmp_buf_bpp; u32 dsi_tmp_buf_bpp;
u32 tmp_reg; u32 tmp_reg;
switch (dsi->format) { switch (dsi->format) {
...@@ -429,12 +401,12 @@ static void dsi_ps_control(struct mtk_dsi *dsi) ...@@ -429,12 +401,12 @@ static void dsi_ps_control(struct mtk_dsi *dsi)
writel(tmp_reg, dsi->regs + DSI_PSCTRL); writel(tmp_reg, dsi->regs + DSI_PSCTRL);
} }
static void dsi_config_vdo_timing(struct mtk_dsi *dsi) static void mtk_dsi_config_vdo_timing(struct mtk_dsi *dsi)
{ {
unsigned int horizontal_sync_active_byte; u32 horizontal_sync_active_byte;
unsigned int horizontal_backporch_byte; u32 horizontal_backporch_byte;
unsigned int horizontal_frontporch_byte; u32 horizontal_frontporch_byte;
unsigned int dsi_tmp_buf_bpp; u32 dsi_tmp_buf_bpp;
struct videomode *vm = &dsi->vm; struct videomode *vm = &dsi->vm;
...@@ -463,7 +435,7 @@ static void dsi_config_vdo_timing(struct mtk_dsi *dsi) ...@@ -463,7 +435,7 @@ static void dsi_config_vdo_timing(struct mtk_dsi *dsi)
writel(horizontal_backporch_byte, dsi->regs + DSI_HBP_WC); writel(horizontal_backporch_byte, dsi->regs + DSI_HBP_WC);
writel(horizontal_frontporch_byte, dsi->regs + DSI_HFP_WC); writel(horizontal_frontporch_byte, dsi->regs + DSI_HFP_WC);
dsi_ps_control(dsi); mtk_dsi_ps_control(dsi);
} }
static void mtk_dsi_start(struct mtk_dsi *dsi) static void mtk_dsi_start(struct mtk_dsi *dsi)
...@@ -472,6 +444,184 @@ static void mtk_dsi_start(struct mtk_dsi *dsi) ...@@ -472,6 +444,184 @@ static void mtk_dsi_start(struct mtk_dsi *dsi)
writel(1, dsi->regs + DSI_START); writel(1, dsi->regs + DSI_START);
} }
static void mtk_dsi_stop(struct mtk_dsi *dsi)
{
writel(0, dsi->regs + DSI_START);
}
static void mtk_dsi_set_cmd_mode(struct mtk_dsi *dsi)
{
writel(CMD_MODE, dsi->regs + DSI_MODE_CTRL);
}
static void mtk_dsi_set_interrupt_enable(struct mtk_dsi *dsi)
{
u32 inten = LPRX_RD_RDY_INT_FLAG | CMD_DONE_INT_FLAG | VM_DONE_INT_FLAG;
writel(inten, dsi->regs + DSI_INTEN);
}
static void mtk_dsi_irq_data_set(struct mtk_dsi *dsi, u32 irq_bit)
{
dsi->irq_data |= irq_bit;
}
static void mtk_dsi_irq_data_clear(struct mtk_dsi *dsi, u32 irq_bit)
{
dsi->irq_data &= ~irq_bit;
}
static s32 mtk_dsi_wait_for_irq_done(struct mtk_dsi *dsi, u32 irq_flag,
unsigned int timeout)
{
s32 ret = 0;
unsigned long jiffies = msecs_to_jiffies(timeout);
ret = wait_event_interruptible_timeout(dsi->irq_wait_queue,
dsi->irq_data & irq_flag,
jiffies);
if (ret == 0) {
DRM_WARN("Wait DSI IRQ(0x%08x) Timeout\n", irq_flag);
mtk_dsi_enable(dsi);
mtk_dsi_reset_engine(dsi);
}
return ret;
}
static irqreturn_t mtk_dsi_irq(int irq, void *dev_id)
{
struct mtk_dsi *dsi = dev_id;
u32 status, tmp;
u32 flag = LPRX_RD_RDY_INT_FLAG | CMD_DONE_INT_FLAG | VM_DONE_INT_FLAG;
status = readl(dsi->regs + DSI_INTSTA) & flag;
if (status) {
do {
mtk_dsi_mask(dsi, DSI_RACK, RACK, RACK);
tmp = readl(dsi->regs + DSI_INTSTA);
} while (tmp & DSI_BUSY);
mtk_dsi_mask(dsi, DSI_INTSTA, status, 0);
mtk_dsi_irq_data_set(dsi, status);
wake_up_interruptible(&dsi->irq_wait_queue);
}
return IRQ_HANDLED;
}
static s32 mtk_dsi_switch_to_cmd_mode(struct mtk_dsi *dsi, u8 irq_flag, u32 t)
{
mtk_dsi_irq_data_clear(dsi, irq_flag);
mtk_dsi_set_cmd_mode(dsi);
if (!mtk_dsi_wait_for_irq_done(dsi, irq_flag, t)) {
DRM_ERROR("failed to switch cmd mode\n");
return -ETIME;
} else {
return 0;
}
}
static int mtk_dsi_poweron(struct mtk_dsi *dsi)
{
struct device *dev = dsi->dev;
int ret;
u64 pixel_clock, total_bits;
u32 htotal, htotal_bits, bit_per_pixel, overhead_cycles, overhead_bits;
if (++dsi->refcount != 1)
return 0;
switch (dsi->format) {
case MIPI_DSI_FMT_RGB565:
bit_per_pixel = 16;
break;
case MIPI_DSI_FMT_RGB666_PACKED:
bit_per_pixel = 18;
break;
case MIPI_DSI_FMT_RGB666:
case MIPI_DSI_FMT_RGB888:
default:
bit_per_pixel = 24;
break;
}
/**
* vm.pixelclock is in kHz, pixel_clock unit is Hz, so multiply by 1000
* htotal_time = htotal * byte_per_pixel / num_lanes
* overhead_time = lpx + hs_prepare + hs_zero + hs_trail + hs_exit
* mipi_ratio = (htotal_time + overhead_time) / htotal_time
* data_rate = pixel_clock * bit_per_pixel * mipi_ratio / num_lanes;
*/
pixel_clock = dsi->vm.pixelclock * 1000;
htotal = dsi->vm.hactive + dsi->vm.hback_porch + dsi->vm.hfront_porch +
dsi->vm.hsync_len;
htotal_bits = htotal * bit_per_pixel;
overhead_cycles = T_LPX + T_HS_PREP + T_HS_ZERO + T_HS_TRAIL +
T_HS_EXIT;
overhead_bits = overhead_cycles * dsi->lanes * 8;
total_bits = htotal_bits + overhead_bits;
dsi->data_rate = DIV_ROUND_UP_ULL(pixel_clock * total_bits,
htotal * dsi->lanes);
ret = clk_set_rate(dsi->hs_clk, dsi->data_rate);
if (ret < 0) {
dev_err(dev, "Failed to set data rate: %d\n", ret);
goto err_refcount;
}
phy_power_on(dsi->phy);
ret = clk_prepare_enable(dsi->engine_clk);
if (ret < 0) {
dev_err(dev, "Failed to enable engine clock: %d\n", ret);
goto err_phy_power_off;
}
ret = clk_prepare_enable(dsi->digital_clk);
if (ret < 0) {
dev_err(dev, "Failed to enable digital clock: %d\n", ret);
goto err_disable_engine_clk;
}
mtk_dsi_enable(dsi);
mtk_dsi_reset_engine(dsi);
mtk_dsi_phy_timconfig(dsi);
mtk_dsi_rxtx_control(dsi);
mtk_dsi_ps_control_vact(dsi);
mtk_dsi_set_vm_cmd(dsi);
mtk_dsi_config_vdo_timing(dsi);
mtk_dsi_set_interrupt_enable(dsi);
mtk_dsi_clk_ulp_mode_leave(dsi);
mtk_dsi_lane0_ulp_mode_leave(dsi);
mtk_dsi_clk_hs_mode(dsi, 0);
if (dsi->panel) {
if (drm_panel_prepare(dsi->panel)) {
DRM_ERROR("failed to prepare the panel\n");
goto err_disable_digital_clk;
}
}
return 0;
err_disable_digital_clk:
clk_disable_unprepare(dsi->digital_clk);
err_disable_engine_clk:
clk_disable_unprepare(dsi->engine_clk);
err_phy_power_off:
phy_power_off(dsi->phy);
err_refcount:
dsi->refcount--;
return ret;
}
static void mtk_dsi_poweroff(struct mtk_dsi *dsi) static void mtk_dsi_poweroff(struct mtk_dsi *dsi)
{ {
if (WARN_ON(dsi->refcount == 0)) if (WARN_ON(dsi->refcount == 0))
...@@ -480,8 +630,18 @@ static void mtk_dsi_poweroff(struct mtk_dsi *dsi) ...@@ -480,8 +630,18 @@ static void mtk_dsi_poweroff(struct mtk_dsi *dsi)
if (--dsi->refcount != 0) if (--dsi->refcount != 0)
return; return;
dsi_lane0_ulp_mode_enter(dsi); if (!mtk_dsi_switch_to_cmd_mode(dsi, VM_DONE_INT_FLAG, 500)) {
dsi_clk_ulp_mode_enter(dsi); if (dsi->panel) {
if (drm_panel_unprepare(dsi->panel)) {
DRM_ERROR("failed to unprepare the panel\n");
return;
}
}
}
mtk_dsi_reset_engine(dsi);
mtk_dsi_lane0_ulp_mode_enter(dsi);
mtk_dsi_clk_ulp_mode_enter(dsi);
mtk_dsi_disable(dsi); mtk_dsi_disable(dsi);
...@@ -498,35 +658,30 @@ static void mtk_output_dsi_enable(struct mtk_dsi *dsi) ...@@ -498,35 +658,30 @@ static void mtk_output_dsi_enable(struct mtk_dsi *dsi)
if (dsi->enabled) if (dsi->enabled)
return; return;
if (dsi->panel) {
if (drm_panel_prepare(dsi->panel)) {
DRM_ERROR("failed to setup the panel\n");
return;
}
}
ret = mtk_dsi_poweron(dsi); ret = mtk_dsi_poweron(dsi);
if (ret < 0) { if (ret < 0) {
DRM_ERROR("failed to power on dsi\n"); DRM_ERROR("failed to power on dsi\n");
return; return;
} }
dsi_rxtx_control(dsi); mtk_dsi_set_mode(dsi);
mtk_dsi_clk_hs_mode(dsi, 1);
dsi_clk_ulp_mode_leave(dsi);
dsi_lane0_ulp_mode_leave(dsi);
dsi_clk_hs_mode(dsi, 0);
dsi_set_mode(dsi);
dsi_ps_control_vact(dsi);
dsi_config_vdo_timing(dsi);
dsi_set_mode(dsi);
dsi_clk_hs_mode(dsi, 1);
mtk_dsi_start(dsi); mtk_dsi_start(dsi);
if (dsi->panel) {
if (drm_panel_enable(dsi->panel)) {
DRM_ERROR("failed to enable the panel\n");
goto err_dsi_power_off;
}
}
dsi->enabled = true; dsi->enabled = true;
return;
err_dsi_power_off:
mtk_dsi_stop(dsi);
mtk_dsi_poweroff(dsi);
} }
static void mtk_output_dsi_disable(struct mtk_dsi *dsi) static void mtk_output_dsi_disable(struct mtk_dsi *dsi)
...@@ -541,6 +696,7 @@ static void mtk_output_dsi_disable(struct mtk_dsi *dsi) ...@@ -541,6 +696,7 @@ static void mtk_output_dsi_disable(struct mtk_dsi *dsi)
} }
} }
mtk_dsi_stop(dsi);
mtk_dsi_poweroff(dsi); mtk_dsi_poweroff(dsi);
dsi->enabled = false; dsi->enabled = false;
...@@ -742,9 +898,149 @@ static int mtk_dsi_host_detach(struct mipi_dsi_host *host, ...@@ -742,9 +898,149 @@ static int mtk_dsi_host_detach(struct mipi_dsi_host *host,
return 0; return 0;
} }
static void mtk_dsi_wait_for_idle(struct mtk_dsi *dsi)
{
u32 timeout_ms = 500000; /* total 1s ~ 2s timeout */
while (timeout_ms--) {
if (!(readl(dsi->regs + DSI_INTSTA) & DSI_BUSY))
break;
usleep_range(2, 4);
}
if (timeout_ms == 0) {
DRM_WARN("polling dsi wait not busy timeout!\n");
mtk_dsi_enable(dsi);
mtk_dsi_reset_engine(dsi);
}
}
static u32 mtk_dsi_recv_cnt(u8 type, u8 *read_data)
{
switch (type) {
case MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_1BYTE:
case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_1BYTE:
return 1;
case MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_2BYTE:
case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_2BYTE:
return 2;
case MIPI_DSI_RX_GENERIC_LONG_READ_RESPONSE:
case MIPI_DSI_RX_DCS_LONG_READ_RESPONSE:
return read_data[1] + read_data[2] * 16;
case MIPI_DSI_RX_ACKNOWLEDGE_AND_ERROR_REPORT:
DRM_INFO("type is 0x02, try again\n");
break;
default:
DRM_INFO("type(0x%x) cannot be non-recognite\n", type);
break;
}
return 0;
}
static void mtk_dsi_cmdq(struct mtk_dsi *dsi, const struct mipi_dsi_msg *msg)
{
const char *tx_buf = msg->tx_buf;
u8 config, cmdq_size, cmdq_off, type = msg->type;
u32 reg_val, cmdq_mask, i;
if (MTK_DSI_HOST_IS_READ(type))
config = BTA;
else
config = (msg->tx_len > 2) ? LONG_PACKET : SHORT_PACKET;
if (msg->tx_len > 2) {
cmdq_size = 1 + (msg->tx_len + 3) / 4;
cmdq_off = 4;
cmdq_mask = CONFIG | DATA_ID | DATA_0 | DATA_1;
reg_val = (msg->tx_len << 16) | (type << 8) | config;
} else {
cmdq_size = 1;
cmdq_off = 2;
cmdq_mask = CONFIG | DATA_ID;
reg_val = (type << 8) | config;
}
for (i = 0; i < msg->tx_len; i++)
writeb(tx_buf[i], dsi->regs + DSI_CMDQ0 + cmdq_off + i);
mtk_dsi_mask(dsi, DSI_CMDQ0, cmdq_mask, reg_val);
mtk_dsi_mask(dsi, DSI_CMDQ_SIZE, CMDQ_SIZE, cmdq_size);
}
static ssize_t mtk_dsi_host_send_cmd(struct mtk_dsi *dsi,
const struct mipi_dsi_msg *msg, u8 flag)
{
mtk_dsi_wait_for_idle(dsi);
mtk_dsi_irq_data_clear(dsi, flag);
mtk_dsi_cmdq(dsi, msg);
mtk_dsi_start(dsi);
if (!mtk_dsi_wait_for_irq_done(dsi, flag, 2000))
return -ETIME;
else
return 0;
}
static ssize_t mtk_dsi_host_transfer(struct mipi_dsi_host *host,
const struct mipi_dsi_msg *msg)
{
struct mtk_dsi *dsi = host_to_dsi(host);
u32 recv_cnt, i;
u8 read_data[16];
void *src_addr;
u8 irq_flag = CMD_DONE_INT_FLAG;
if (readl(dsi->regs + DSI_MODE_CTRL) & MODE) {
DRM_ERROR("dsi engine is not command mode\n");
return -EINVAL;
}
if (MTK_DSI_HOST_IS_READ(msg->type))
irq_flag |= LPRX_RD_RDY_INT_FLAG;
if (mtk_dsi_host_send_cmd(dsi, msg, irq_flag) < 0)
return -ETIME;
if (!MTK_DSI_HOST_IS_READ(msg->type))
return 0;
if (!msg->rx_buf) {
DRM_ERROR("dsi receive buffer size may be NULL\n");
return -EINVAL;
}
for (i = 0; i < 16; i++)
*(read_data + i) = readb(dsi->regs + DSI_RX_DATA0 + i);
recv_cnt = mtk_dsi_recv_cnt(read_data[0], read_data);
if (recv_cnt > 2)
src_addr = &read_data[4];
else
src_addr = &read_data[1];
if (recv_cnt > 10)
recv_cnt = 10;
if (recv_cnt > msg->rx_len)
recv_cnt = msg->rx_len;
if (recv_cnt)
memcpy(msg->rx_buf, src_addr, recv_cnt);
DRM_INFO("dsi get %d byte data from the panel address(0x%x)\n",
recv_cnt, *((u8 *)(msg->tx_buf)));
return recv_cnt;
}
static const struct mipi_dsi_host_ops mtk_dsi_ops = { static const struct mipi_dsi_host_ops mtk_dsi_ops = {
.attach = mtk_dsi_host_attach, .attach = mtk_dsi_host_attach,
.detach = mtk_dsi_host_detach, .detach = mtk_dsi_host_detach,
.transfer = mtk_dsi_host_transfer,
}; };
static int mtk_dsi_bind(struct device *dev, struct device *master, void *data) static int mtk_dsi_bind(struct device *dev, struct device *master, void *data)
...@@ -803,6 +1099,7 @@ static int mtk_dsi_probe(struct platform_device *pdev) ...@@ -803,6 +1099,7 @@ static int mtk_dsi_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct device_node *remote_node, *endpoint; struct device_node *remote_node, *endpoint;
struct resource *regs; struct resource *regs;
int irq_num;
int comp_id; int comp_id;
int ret; int ret;
...@@ -879,6 +1176,22 @@ static int mtk_dsi_probe(struct platform_device *pdev) ...@@ -879,6 +1176,22 @@ static int mtk_dsi_probe(struct platform_device *pdev)
return ret; return ret;
} }
irq_num = platform_get_irq(pdev, 0);
if (irq_num < 0) {
dev_err(&pdev->dev, "failed to request dsi irq resource\n");
return -EPROBE_DEFER;
}
irq_set_status_flags(irq_num, IRQ_TYPE_LEVEL_LOW);
ret = devm_request_irq(&pdev->dev, irq_num, mtk_dsi_irq,
IRQF_TRIGGER_LOW, dev_name(&pdev->dev), dsi);
if (ret) {
dev_err(&pdev->dev, "failed to request mediatek dsi irq\n");
return -EPROBE_DEFER;
}
init_waitqueue_head(&dsi->irq_wait_queue);
platform_set_drvdata(pdev, dsi); platform_set_drvdata(pdev, dsi);
return component_add(&pdev->dev, &mtk_dsi_component_ops); return component_add(&pdev->dev, &mtk_dsi_component_ops);
...@@ -895,6 +1208,7 @@ static int mtk_dsi_remove(struct platform_device *pdev) ...@@ -895,6 +1208,7 @@ static int mtk_dsi_remove(struct platform_device *pdev)
} }
static const struct of_device_id mtk_dsi_of_match[] = { static const struct of_device_id mtk_dsi_of_match[] = {
{ .compatible = "mediatek,mt2701-dsi" },
{ .compatible = "mediatek,mt8173-dsi" }, { .compatible = "mediatek,mt8173-dsi" },
{ }, { },
}; };
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of_device.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/phy/phy.h> #include <linux/phy/phy.h>
...@@ -87,6 +88,9 @@ ...@@ -87,6 +88,9 @@
#define MIPITX_DSI_PLL_CON2 0x58 #define MIPITX_DSI_PLL_CON2 0x58
#define MIPITX_DSI_PLL_TOP 0x64
#define RG_DSI_MPPLL_PRESERVE (0xff << 8)
#define MIPITX_DSI_PLL_PWR 0x68 #define MIPITX_DSI_PLL_PWR 0x68
#define RG_DSI_MPPLL_SDM_PWR_ON BIT(0) #define RG_DSI_MPPLL_SDM_PWR_ON BIT(0)
#define RG_DSI_MPPLL_SDM_ISO_EN BIT(1) #define RG_DSI_MPPLL_SDM_ISO_EN BIT(1)
...@@ -123,10 +127,15 @@ ...@@ -123,10 +127,15 @@
#define SW_LNT2_HSTX_PRE_OE BIT(24) #define SW_LNT2_HSTX_PRE_OE BIT(24)
#define SW_LNT2_HSTX_OE BIT(25) #define SW_LNT2_HSTX_OE BIT(25)
struct mtk_mipitx_data {
const u32 mppll_preserve;
};
struct mtk_mipi_tx { struct mtk_mipi_tx {
struct device *dev; struct device *dev;
void __iomem *regs; void __iomem *regs;
unsigned int data_rate; u32 data_rate;
const struct mtk_mipitx_data *driver_data;
struct clk_hw pll_hw; struct clk_hw pll_hw;
struct clk *pll; struct clk *pll;
}; };
...@@ -163,7 +172,7 @@ static void mtk_mipi_tx_update_bits(struct mtk_mipi_tx *mipi_tx, u32 offset, ...@@ -163,7 +172,7 @@ static void mtk_mipi_tx_update_bits(struct mtk_mipi_tx *mipi_tx, u32 offset,
static int mtk_mipi_tx_pll_prepare(struct clk_hw *hw) static int mtk_mipi_tx_pll_prepare(struct clk_hw *hw)
{ {
struct mtk_mipi_tx *mipi_tx = mtk_mipi_tx_from_clk_hw(hw); struct mtk_mipi_tx *mipi_tx = mtk_mipi_tx_from_clk_hw(hw);
unsigned int txdiv, txdiv0, txdiv1; u8 txdiv, txdiv0, txdiv1;
u64 pcw; u64 pcw;
dev_dbg(mipi_tx->dev, "prepare: %u Hz\n", mipi_tx->data_rate); dev_dbg(mipi_tx->dev, "prepare: %u Hz\n", mipi_tx->data_rate);
...@@ -243,6 +252,10 @@ static int mtk_mipi_tx_pll_prepare(struct clk_hw *hw) ...@@ -243,6 +252,10 @@ static int mtk_mipi_tx_pll_prepare(struct clk_hw *hw)
mtk_mipi_tx_clear_bits(mipi_tx, MIPITX_DSI_PLL_CON1, mtk_mipi_tx_clear_bits(mipi_tx, MIPITX_DSI_PLL_CON1,
RG_DSI_MPPLL_SDM_SSC_EN); RG_DSI_MPPLL_SDM_SSC_EN);
mtk_mipi_tx_update_bits(mipi_tx, MIPITX_DSI_PLL_TOP,
RG_DSI_MPPLL_PRESERVE,
mipi_tx->driver_data->mppll_preserve);
return 0; return 0;
} }
...@@ -255,6 +268,9 @@ static void mtk_mipi_tx_pll_unprepare(struct clk_hw *hw) ...@@ -255,6 +268,9 @@ static void mtk_mipi_tx_pll_unprepare(struct clk_hw *hw)
mtk_mipi_tx_clear_bits(mipi_tx, MIPITX_DSI_PLL_CON0, mtk_mipi_tx_clear_bits(mipi_tx, MIPITX_DSI_PLL_CON0,
RG_DSI_MPPLL_PLL_EN); RG_DSI_MPPLL_PLL_EN);
mtk_mipi_tx_update_bits(mipi_tx, MIPITX_DSI_PLL_TOP,
RG_DSI_MPPLL_PRESERVE, 0);
mtk_mipi_tx_update_bits(mipi_tx, MIPITX_DSI_PLL_PWR, mtk_mipi_tx_update_bits(mipi_tx, MIPITX_DSI_PLL_PWR,
RG_DSI_MPPLL_SDM_ISO_EN | RG_DSI_MPPLL_SDM_ISO_EN |
RG_DSI_MPPLL_SDM_PWR_ON, RG_DSI_MPPLL_SDM_PWR_ON,
...@@ -310,7 +326,7 @@ static const struct clk_ops mtk_mipi_tx_pll_ops = { ...@@ -310,7 +326,7 @@ static const struct clk_ops mtk_mipi_tx_pll_ops = {
static int mtk_mipi_tx_power_on_signal(struct phy *phy) static int mtk_mipi_tx_power_on_signal(struct phy *phy)
{ {
struct mtk_mipi_tx *mipi_tx = phy_get_drvdata(phy); struct mtk_mipi_tx *mipi_tx = phy_get_drvdata(phy);
unsigned int reg; u32 reg;
for (reg = MIPITX_DSI_CLOCK_LANE; for (reg = MIPITX_DSI_CLOCK_LANE;
reg <= MIPITX_DSI_DATA_LANE3; reg += 4) reg <= MIPITX_DSI_DATA_LANE3; reg += 4)
...@@ -341,7 +357,7 @@ static int mtk_mipi_tx_power_on(struct phy *phy) ...@@ -341,7 +357,7 @@ static int mtk_mipi_tx_power_on(struct phy *phy)
static void mtk_mipi_tx_power_off_signal(struct phy *phy) static void mtk_mipi_tx_power_off_signal(struct phy *phy)
{ {
struct mtk_mipi_tx *mipi_tx = phy_get_drvdata(phy); struct mtk_mipi_tx *mipi_tx = phy_get_drvdata(phy);
unsigned int reg; u32 reg;
mtk_mipi_tx_set_bits(mipi_tx, MIPITX_DSI_TOP_CON, mtk_mipi_tx_set_bits(mipi_tx, MIPITX_DSI_TOP_CON,
RG_DSI_PAD_TIE_LOW_EN); RG_DSI_PAD_TIE_LOW_EN);
...@@ -391,6 +407,7 @@ static int mtk_mipi_tx_probe(struct platform_device *pdev) ...@@ -391,6 +407,7 @@ static int mtk_mipi_tx_probe(struct platform_device *pdev)
if (!mipi_tx) if (!mipi_tx)
return -ENOMEM; return -ENOMEM;
mipi_tx->driver_data = of_device_get_match_data(dev);
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
mipi_tx->regs = devm_ioremap_resource(dev, mem); mipi_tx->regs = devm_ioremap_resource(dev, mem);
if (IS_ERR(mipi_tx->regs)) { if (IS_ERR(mipi_tx->regs)) {
...@@ -448,8 +465,19 @@ static int mtk_mipi_tx_remove(struct platform_device *pdev) ...@@ -448,8 +465,19 @@ static int mtk_mipi_tx_remove(struct platform_device *pdev)
return 0; return 0;
} }
static const struct mtk_mipitx_data mt2701_mipitx_data = {
.mppll_preserve = (3 << 8)
};
static const struct mtk_mipitx_data mt8173_mipitx_data = {
.mppll_preserve = (0 << 8)
};
static const struct of_device_id mtk_mipi_tx_match[] = { static const struct of_device_id mtk_mipi_tx_match[] = {
{ .compatible = "mediatek,mt8173-mipi-tx", }, { .compatible = "mediatek,mt2701-mipi-tx",
.data = &mt2701_mipitx_data },
{ .compatible = "mediatek,mt8173-mipi-tx",
.data = &mt8173_mipitx_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