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
This commit is contained in:
Коммит
cdf5316bdb
|
@ -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):
|
||||||
"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.
|
||||||
|
|
||||||
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.
|
||||||
|
|
||||||
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 @@
|
||||||
#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 @@
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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,
|
||||||
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,
|
||||||
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)
|
||||||
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)
|
||||||
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 @@
|
||||||
#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 @@
|
||||||
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,
|
||||||
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,
|
||||||
{
|
{
|
||||||
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,
|
||||||
*/
|
*/
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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,
|
||||||
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,
|
||||||
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 @@ err_cleanup_crtc:
|
||||||
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 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#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 @@
|
||||||
#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 @@
|
||||||
#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 {
|
||||||
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 mutex_mod[DDP_COMPONENT_ID_MAX] = {
|
static const unsigned int mt2701_mutex_mod[DDP_COMPONENT_ID_MAX] = {
|
||||||
[DDP_COMPONENT_AAL] = MUTEX_MOD_DISP_AAL,
|
[DDP_COMPONENT_BLS] = MT2701_MUTEX_MOD_DISP_BLS,
|
||||||
[DDP_COMPONENT_COLOR0] = MUTEX_MOD_DISP_COLOR0,
|
[DDP_COMPONENT_COLOR0] = MT2701_MUTEX_MOD_DISP_COLOR,
|
||||||
[DDP_COMPONENT_COLOR1] = MUTEX_MOD_DISP_COLOR1,
|
[DDP_COMPONENT_OVL0] = MT2701_MUTEX_MOD_DISP_OVL,
|
||||||
[DDP_COMPONENT_GAMMA] = MUTEX_MOD_DISP_GAMMA,
|
[DDP_COMPONENT_RDMA0] = MT2701_MUTEX_MOD_DISP_RDMA0,
|
||||||
[DDP_COMPONENT_OD] = MUTEX_MOD_DISP_OD,
|
[DDP_COMPONENT_RDMA1] = MT2701_MUTEX_MOD_DISP_RDMA1,
|
||||||
[DDP_COMPONENT_OVL0] = MUTEX_MOD_DISP_OVL0,
|
[DDP_COMPONENT_WDMA0] = MT2701_MUTEX_MOD_DISP_WDMA,
|
||||||
[DDP_COMPONENT_OVL1] = MUTEX_MOD_DISP_OVL1,
|
};
|
||||||
[DDP_COMPONENT_PWM0] = MUTEX_MOD_DISP_PWM0,
|
|
||||||
[DDP_COMPONENT_PWM1] = MUTEX_MOD_DISP_PWM1,
|
static const unsigned int mt8173_mutex_mod[DDP_COMPONENT_ID_MAX] = {
|
||||||
[DDP_COMPONENT_RDMA0] = MUTEX_MOD_DISP_RDMA0,
|
[DDP_COMPONENT_AAL] = MT8173_MUTEX_MOD_DISP_AAL,
|
||||||
[DDP_COMPONENT_RDMA1] = MUTEX_MOD_DISP_RDMA1,
|
[DDP_COMPONENT_COLOR0] = MT8173_MUTEX_MOD_DISP_COLOR0,
|
||||||
[DDP_COMPONENT_RDMA2] = MUTEX_MOD_DISP_RDMA2,
|
[DDP_COMPONENT_COLOR1] = MT8173_MUTEX_MOD_DISP_COLOR1,
|
||||||
[DDP_COMPONENT_UFOE] = MUTEX_MOD_DISP_UFOE,
|
[DDP_COMPONENT_GAMMA] = MT8173_MUTEX_MOD_DISP_GAMMA,
|
||||||
[DDP_COMPONENT_WDMA0] = MUTEX_MOD_DISP_WDMA0,
|
[DDP_COMPONENT_OD] = MT8173_MUTEX_MOD_DISP_OD,
|
||||||
[DDP_COMPONENT_WDMA1] = MUTEX_MOD_DISP_WDMA1,
|
[DDP_COMPONENT_OVL0] = MT8173_MUTEX_MOD_DISP_OVL0,
|
||||||
|
[DDP_COMPONENT_OVL1] = MT8173_MUTEX_MOD_DISP_OVL1,
|
||||||
|
[DDP_COMPONENT_PWM0] = MT8173_MUTEX_MOD_DISP_PWM0,
|
||||||
|
[DDP_COMPONENT_PWM1] = MT8173_MUTEX_MOD_DISP_PWM1,
|
||||||
|
[DDP_COMPONENT_RDMA0] = MT8173_MUTEX_MOD_DISP_RDMA0,
|
||||||
|
[DDP_COMPONENT_RDMA1] = MT8173_MUTEX_MOD_DISP_RDMA1,
|
||||||
|
[DDP_COMPONENT_RDMA2] = MT8173_MUTEX_MOD_DISP_RDMA2,
|
||||||
|
[DDP_COMPONENT_UFOE] = MT8173_MUTEX_MOD_DISP_UFOE,
|
||||||
|
[DDP_COMPONENT_WDMA0] = MT8173_MUTEX_MOD_DISP_WDMA0,
|
||||||
|
[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,
|
||||||
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,
|
||||||
} 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,
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
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,
|
||||||
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 @@
|
||||||
#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 @@
|
||||||
#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,
|
||||||
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] = {
|
||||||
[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 {
|
||||||
|
|
||||||
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] = {
|
||||||
[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,
|
||||||
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,
|
||||||
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 {
|
||||||
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 = {
|
||||||
.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[] = {
|
||||||
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[] = {
|
||||||
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)
|
||||||
* 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 = {
|
||||||
};
|
};
|
||||||
|
|
||||||
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)
|
||||||
|
|
||||||
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,
|
||||||
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;
|
||||||
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 {
|
||||||
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 @@
|
||||||
#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 @@
|
||||||
#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 @@
|
||||||
#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 @@
|
||||||
#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 @@
|
||||||
|
|
||||||
#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 {
|
||||||
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)
|
||||||
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,12 +237,294 @@ 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 void mtk_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_ULPM_EN, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
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_WAKEUP_EN, LC_WAKEUP_EN);
|
||||||
|
mtk_dsi_mask(dsi, DSI_PHY_LCCON, LC_WAKEUP_EN, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
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_ULPM_EN, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
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_WAKEUP_EN, LD0_WAKEUP_EN);
|
||||||
|
mtk_dsi_mask(dsi, DSI_PHY_LD0CON, LD0_WAKEUP_EN, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool mtk_dsi_clk_hs_state(struct mtk_dsi *dsi)
|
||||||
|
{
|
||||||
|
u32 tmp_reg1;
|
||||||
|
|
||||||
|
tmp_reg1 = readl(dsi->regs + DSI_PHY_LCCON);
|
||||||
|
return ((tmp_reg1 & LC_HS_TX_EN) == 1) ? true : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mtk_dsi_clk_hs_mode(struct mtk_dsi *dsi, bool enter)
|
||||||
|
{
|
||||||
|
if (enter && !mtk_dsi_clk_hs_state(dsi))
|
||||||
|
mtk_dsi_mask(dsi, DSI_PHY_LCCON, LC_HS_TX_EN, LC_HS_TX_EN);
|
||||||
|
else if (!enter && mtk_dsi_clk_hs_state(dsi))
|
||||||
|
mtk_dsi_mask(dsi, DSI_PHY_LCCON, LC_HS_TX_EN, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mtk_dsi_set_mode(struct mtk_dsi *dsi)
|
||||||
|
{
|
||||||
|
u32 vid_mode = CMD_MODE;
|
||||||
|
|
||||||
|
if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO) {
|
||||||
|
if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_BURST)
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
u32 dsi_buf_bpp, ps_wc;
|
||||||
|
u32 ps_bpp_mode;
|
||||||
|
|
||||||
|
if (dsi->format == MIPI_DSI_FMT_RGB565)
|
||||||
|
dsi_buf_bpp = 2;
|
||||||
|
else
|
||||||
|
dsi_buf_bpp = 3;
|
||||||
|
|
||||||
|
ps_wc = vm->hactive * dsi_buf_bpp;
|
||||||
|
ps_bpp_mode = ps_wc;
|
||||||
|
|
||||||
|
switch (dsi->format) {
|
||||||
|
case MIPI_DSI_FMT_RGB888:
|
||||||
|
ps_bpp_mode |= PACKED_PS_24BIT_RGB888;
|
||||||
|
break;
|
||||||
|
case MIPI_DSI_FMT_RGB666:
|
||||||
|
ps_bpp_mode |= PACKED_PS_18BIT_RGB666;
|
||||||
|
break;
|
||||||
|
case MIPI_DSI_FMT_RGB666_PACKED:
|
||||||
|
ps_bpp_mode |= LOOSELY_PS_18BIT_RGB666;
|
||||||
|
break;
|
||||||
|
case MIPI_DSI_FMT_RGB565:
|
||||||
|
ps_bpp_mode |= PACKED_PS_16BIT_RGB565;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
writel(vm->vactive, dsi->regs + DSI_VACT_NL);
|
||||||
|
writel(ps_bpp_mode, dsi->regs + DSI_PSCTRL);
|
||||||
|
writel(ps_wc, dsi->regs + DSI_HSTX_CKL_WC);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mtk_dsi_rxtx_control(struct mtk_dsi *dsi)
|
||||||
|
{
|
||||||
|
u32 tmp_reg;
|
||||||
|
|
||||||
|
switch (dsi->lanes) {
|
||||||
|
case 1:
|
||||||
|
tmp_reg = 1 << 2;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
tmp_reg = 3 << 2;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
tmp_reg = 7 << 2;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
tmp_reg = 0xf << 2;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
tmp_reg = 0xf << 2;
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mtk_dsi_ps_control(struct mtk_dsi *dsi)
|
||||||
|
{
|
||||||
|
u32 dsi_tmp_buf_bpp;
|
||||||
|
u32 tmp_reg;
|
||||||
|
|
||||||
|
switch (dsi->format) {
|
||||||
|
case MIPI_DSI_FMT_RGB888:
|
||||||
|
tmp_reg = PACKED_PS_24BIT_RGB888;
|
||||||
|
dsi_tmp_buf_bpp = 3;
|
||||||
|
break;
|
||||||
|
case MIPI_DSI_FMT_RGB666:
|
||||||
|
tmp_reg = LOOSELY_PS_18BIT_RGB666;
|
||||||
|
dsi_tmp_buf_bpp = 3;
|
||||||
|
break;
|
||||||
|
case MIPI_DSI_FMT_RGB666_PACKED:
|
||||||
|
tmp_reg = PACKED_PS_18BIT_RGB666;
|
||||||
|
dsi_tmp_buf_bpp = 3;
|
||||||
|
break;
|
||||||
|
case MIPI_DSI_FMT_RGB565:
|
||||||
|
tmp_reg = PACKED_PS_16BIT_RGB565;
|
||||||
|
dsi_tmp_buf_bpp = 2;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
tmp_reg = PACKED_PS_24BIT_RGB888;
|
||||||
|
dsi_tmp_buf_bpp = 3;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp_reg += dsi->vm.hactive * dsi_tmp_buf_bpp & DSI_PS_WC;
|
||||||
|
writel(tmp_reg, dsi->regs + DSI_PSCTRL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mtk_dsi_config_vdo_timing(struct mtk_dsi *dsi)
|
||||||
|
{
|
||||||
|
u32 horizontal_sync_active_byte;
|
||||||
|
u32 horizontal_backporch_byte;
|
||||||
|
u32 horizontal_frontporch_byte;
|
||||||
|
u32 dsi_tmp_buf_bpp;
|
||||||
|
|
||||||
|
struct videomode *vm = &dsi->vm;
|
||||||
|
|
||||||
|
if (dsi->format == MIPI_DSI_FMT_RGB565)
|
||||||
|
dsi_tmp_buf_bpp = 2;
|
||||||
|
else
|
||||||
|
dsi_tmp_buf_bpp = 3;
|
||||||
|
|
||||||
|
writel(vm->vsync_len, dsi->regs + DSI_VSA_NL);
|
||||||
|
writel(vm->vback_porch, dsi->regs + DSI_VBP_NL);
|
||||||
|
writel(vm->vfront_porch, dsi->regs + DSI_VFP_NL);
|
||||||
|
writel(vm->vactive, dsi->regs + DSI_VACT_NL);
|
||||||
|
|
||||||
|
horizontal_sync_active_byte = (vm->hsync_len * dsi_tmp_buf_bpp - 10);
|
||||||
|
|
||||||
|
if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE)
|
||||||
|
horizontal_backporch_byte =
|
||||||
|
(vm->hback_porch * dsi_tmp_buf_bpp - 10);
|
||||||
|
else
|
||||||
|
horizontal_backporch_byte = ((vm->hback_porch + vm->hsync_len) *
|
||||||
|
dsi_tmp_buf_bpp - 10);
|
||||||
|
|
||||||
|
horizontal_frontporch_byte = (vm->hfront_porch * dsi_tmp_buf_bpp - 12);
|
||||||
|
|
||||||
|
writel(horizontal_sync_active_byte, dsi->regs + DSI_HSA_WC);
|
||||||
|
writel(horizontal_backporch_byte, dsi->regs + DSI_HBP_WC);
|
||||||
|
writel(horizontal_frontporch_byte, dsi->regs + DSI_HFP_WC);
|
||||||
|
|
||||||
|
mtk_dsi_ps_control(dsi);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mtk_dsi_start(struct mtk_dsi *dsi)
|
||||||
|
{
|
||||||
|
writel(0, 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)
|
static int mtk_dsi_poweron(struct mtk_dsi *dsi)
|
||||||
{
|
{
|
||||||
struct device *dev = dsi->dev;
|
struct device *dev = dsi->dev;
|
||||||
|
@ -267,11 +590,29 @@ static int mtk_dsi_poweron(struct mtk_dsi *dsi)
|
||||||
}
|
}
|
||||||
|
|
||||||
mtk_dsi_enable(dsi);
|
mtk_dsi_enable(dsi);
|
||||||
mtk_dsi_reset(dsi);
|
mtk_dsi_reset_engine(dsi);
|
||||||
dsi_phy_timconfig(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;
|
return 0;
|
||||||
|
err_disable_digital_clk:
|
||||||
|
clk_disable_unprepare(dsi->digital_clk);
|
||||||
err_disable_engine_clk:
|
err_disable_engine_clk:
|
||||||
clk_disable_unprepare(dsi->engine_clk);
|
clk_disable_unprepare(dsi->engine_clk);
|
||||||
err_phy_power_off:
|
err_phy_power_off:
|
||||||
|
@ -281,197 +622,6 @@ err_refcount:
|
||||||
return ret;
|
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_ULPM_EN, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void 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_WAKEUP_EN, LC_WAKEUP_EN);
|
|
||||||
mtk_dsi_mask(dsi, DSI_PHY_LCCON, LC_WAKEUP_EN, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void 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_ULPM_EN, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void 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_WAKEUP_EN, LD0_WAKEUP_EN);
|
|
||||||
mtk_dsi_mask(dsi, DSI_PHY_LD0CON, LD0_WAKEUP_EN, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool dsi_clk_hs_state(struct mtk_dsi *dsi)
|
|
||||||
{
|
|
||||||
u32 tmp_reg1;
|
|
||||||
|
|
||||||
tmp_reg1 = readl(dsi->regs + DSI_PHY_LCCON);
|
|
||||||
return ((tmp_reg1 & LC_HS_TX_EN) == 1) ? true : false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void dsi_clk_hs_mode(struct mtk_dsi *dsi, bool enter)
|
|
||||||
{
|
|
||||||
if (enter && !dsi_clk_hs_state(dsi))
|
|
||||||
mtk_dsi_mask(dsi, DSI_PHY_LCCON, LC_HS_TX_EN, LC_HS_TX_EN);
|
|
||||||
else if (!enter && dsi_clk_hs_state(dsi))
|
|
||||||
mtk_dsi_mask(dsi, DSI_PHY_LCCON, LC_HS_TX_EN, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void dsi_set_mode(struct mtk_dsi *dsi)
|
|
||||||
{
|
|
||||||
u32 vid_mode = CMD_MODE;
|
|
||||||
|
|
||||||
if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO) {
|
|
||||||
vid_mode = SYNC_PULSE_MODE;
|
|
||||||
|
|
||||||
if ((dsi->mode_flags & MIPI_DSI_MODE_VIDEO_BURST) &&
|
|
||||||
!(dsi->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE))
|
|
||||||
vid_mode = BURST_MODE;
|
|
||||||
}
|
|
||||||
|
|
||||||
writel(vid_mode, dsi->regs + DSI_MODE_CTRL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void dsi_ps_control_vact(struct mtk_dsi *dsi)
|
|
||||||
{
|
|
||||||
struct videomode *vm = &dsi->vm;
|
|
||||||
u32 dsi_buf_bpp, ps_wc;
|
|
||||||
u32 ps_bpp_mode;
|
|
||||||
|
|
||||||
if (dsi->format == MIPI_DSI_FMT_RGB565)
|
|
||||||
dsi_buf_bpp = 2;
|
|
||||||
else
|
|
||||||
dsi_buf_bpp = 3;
|
|
||||||
|
|
||||||
ps_wc = vm->hactive * dsi_buf_bpp;
|
|
||||||
ps_bpp_mode = ps_wc;
|
|
||||||
|
|
||||||
switch (dsi->format) {
|
|
||||||
case MIPI_DSI_FMT_RGB888:
|
|
||||||
ps_bpp_mode |= PACKED_PS_24BIT_RGB888;
|
|
||||||
break;
|
|
||||||
case MIPI_DSI_FMT_RGB666:
|
|
||||||
ps_bpp_mode |= PACKED_PS_18BIT_RGB666;
|
|
||||||
break;
|
|
||||||
case MIPI_DSI_FMT_RGB666_PACKED:
|
|
||||||
ps_bpp_mode |= LOOSELY_PS_18BIT_RGB666;
|
|
||||||
break;
|
|
||||||
case MIPI_DSI_FMT_RGB565:
|
|
||||||
ps_bpp_mode |= PACKED_PS_16BIT_RGB565;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
writel(vm->vactive, dsi->regs + DSI_VACT_NL);
|
|
||||||
writel(ps_bpp_mode, dsi->regs + DSI_PSCTRL);
|
|
||||||
writel(ps_wc, dsi->regs + DSI_HSTX_CKL_WC);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void dsi_rxtx_control(struct mtk_dsi *dsi)
|
|
||||||
{
|
|
||||||
u32 tmp_reg;
|
|
||||||
|
|
||||||
switch (dsi->lanes) {
|
|
||||||
case 1:
|
|
||||||
tmp_reg = 1 << 2;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
tmp_reg = 3 << 2;
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
tmp_reg = 7 << 2;
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
tmp_reg = 0xf << 2;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
tmp_reg = 0xf << 2;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
writel(tmp_reg, dsi->regs + DSI_TXRX_CTRL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void dsi_ps_control(struct mtk_dsi *dsi)
|
|
||||||
{
|
|
||||||
unsigned int dsi_tmp_buf_bpp;
|
|
||||||
u32 tmp_reg;
|
|
||||||
|
|
||||||
switch (dsi->format) {
|
|
||||||
case MIPI_DSI_FMT_RGB888:
|
|
||||||
tmp_reg = PACKED_PS_24BIT_RGB888;
|
|
||||||
dsi_tmp_buf_bpp = 3;
|
|
||||||
break;
|
|
||||||
case MIPI_DSI_FMT_RGB666:
|
|
||||||
tmp_reg = LOOSELY_PS_18BIT_RGB666;
|
|
||||||
dsi_tmp_buf_bpp = 3;
|
|
||||||
break;
|
|
||||||
case MIPI_DSI_FMT_RGB666_PACKED:
|
|
||||||
tmp_reg = PACKED_PS_18BIT_RGB666;
|
|
||||||
dsi_tmp_buf_bpp = 3;
|
|
||||||
break;
|
|
||||||
case MIPI_DSI_FMT_RGB565:
|
|
||||||
tmp_reg = PACKED_PS_16BIT_RGB565;
|
|
||||||
dsi_tmp_buf_bpp = 2;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
tmp_reg = PACKED_PS_24BIT_RGB888;
|
|
||||||
dsi_tmp_buf_bpp = 3;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
tmp_reg += dsi->vm.hactive * dsi_tmp_buf_bpp & DSI_PS_WC;
|
|
||||||
writel(tmp_reg, dsi->regs + DSI_PSCTRL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void dsi_config_vdo_timing(struct mtk_dsi *dsi)
|
|
||||||
{
|
|
||||||
unsigned int horizontal_sync_active_byte;
|
|
||||||
unsigned int horizontal_backporch_byte;
|
|
||||||
unsigned int horizontal_frontporch_byte;
|
|
||||||
unsigned int dsi_tmp_buf_bpp;
|
|
||||||
|
|
||||||
struct videomode *vm = &dsi->vm;
|
|
||||||
|
|
||||||
if (dsi->format == MIPI_DSI_FMT_RGB565)
|
|
||||||
dsi_tmp_buf_bpp = 2;
|
|
||||||
else
|
|
||||||
dsi_tmp_buf_bpp = 3;
|
|
||||||
|
|
||||||
writel(vm->vsync_len, dsi->regs + DSI_VSA_NL);
|
|
||||||
writel(vm->vback_porch, dsi->regs + DSI_VBP_NL);
|
|
||||||
writel(vm->vfront_porch, dsi->regs + DSI_VFP_NL);
|
|
||||||
writel(vm->vactive, dsi->regs + DSI_VACT_NL);
|
|
||||||
|
|
||||||
horizontal_sync_active_byte = (vm->hsync_len * dsi_tmp_buf_bpp - 10);
|
|
||||||
|
|
||||||
if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE)
|
|
||||||
horizontal_backporch_byte =
|
|
||||||
(vm->hback_porch * dsi_tmp_buf_bpp - 10);
|
|
||||||
else
|
|
||||||
horizontal_backporch_byte = ((vm->hback_porch + vm->hsync_len) *
|
|
||||||
dsi_tmp_buf_bpp - 10);
|
|
||||||
|
|
||||||
horizontal_frontporch_byte = (vm->hfront_porch * dsi_tmp_buf_bpp - 12);
|
|
||||||
|
|
||||||
writel(horizontal_sync_active_byte, dsi->regs + DSI_HSA_WC);
|
|
||||||
writel(horizontal_backporch_byte, dsi->regs + DSI_HBP_WC);
|
|
||||||
writel(horizontal_frontporch_byte, dsi->regs + DSI_HFP_WC);
|
|
||||||
|
|
||||||
dsi_ps_control(dsi);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void mtk_dsi_start(struct mtk_dsi *dsi)
|
|
||||||
{
|
|
||||||
writel(0, dsi->regs + DSI_START);
|
|
||||||
writel(1, dsi->regs + DSI_START);
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
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 @@
|
||||||
#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 @@
|
||||||
|
|
||||||
#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 @@
|
||||||
#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,
|
||||||
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)
|
||||||
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)
|
||||||
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 = {
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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 },
|
||||||
{},
|
{},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче