Commit 00c1beab authored by Dave Airlie's avatar Dave Airlie

Merge branch 'exynos-drm-next' of...

Merge branch 'exynos-drm-next' of git://git.kernel.org/pub/scm/linux/kernel/git/daeinki/drm-exynos into drm-next

Summary:
 - Support for pipeline clock between KMS drivers.
   . Exynos SoC is required to control clocks across KMS drivers
     according to Exynos SoC version. So this patch refactos
     some relevant codes and provides generic solution for it.
 - Add Exynos5433 SoC support to HDMI parts - HDMI and DECON-TV.
 - Add HW trigger mode support to CRTC drivers.
   . In case of using i80 Panel, some Exynos SoC supports HW trigger
     mode so this patch makes trigger mode - HW or SW trigger - to be
     set according to SoC version properly.
 - And some cleanups and regression fixups.

* 'exynos-drm-next' of git://git.kernel.org/pub/scm/linux/kernel/git/daeinki/drm-exynos: (39 commits)
  drm/exynos: clean up register definions for fimd and decon
  drm/exynos: decon: clean up interface type
  drm/exynos: fimd: add HW trigger support
  drm/exynos: clean up wait_for_vblank
  drm/exynos: mixer: use generic of_device_get_match_data helper
  drm/exynos: mixer: remove support for non-dt platforms
  drm/exynos: hdmi: use generic of_device_get_match_data helper
  drm/exynos: rotator: use generic of_device_get_match_data helper
  drm/exynos: fimd: use generic of_device_get_match_data helper
  drm/exynos: dsi: use generic of_device_get_match_data helper
  drm/exynos: exynos5433_decon: use generic of_device_get_match_data helper
  drm/exynos: convert clock_enable crtc callback to pipeline clock
  drm/exynos/mixer: enable HDMI-PHY before configuring MIXER
  drm/exynos/decon5433: enable HDMI-PHY before configuring DECON
  drm/exynos: add support for pipeline clock to the framework
  drm/exynos: add helper to get crtc from pipe
  drm/exynos/decon5433: do not protect window in plane disable
  drm/exynos/decon5433: reset decon on start
  drm/exynos/decon5433: fix DECON standalone update
  drm/exynos/hdmi: remove registry dump
  ...
parents acff058f b5bf0f1e
......@@ -5,7 +5,8 @@ Exynos series of SoCs which transfers the image data from a video memory
buffer to an external LCD interface.
Required properties:
- compatible: value should be "samsung,exynos5433-decon";
- compatible: value should be one of:
"samsung,exynos5433-decon", "samsung,exynos5433-decon-tv";
- reg: physical base address and length of the DECON registers set.
- interrupts: should contain a list of all DECON IP block interrupts in the
order: VSYNC, LCD_SYSTEM. The interrupt specifier format
......@@ -16,7 +17,7 @@ Required properties:
- clocks: must include clock specifiers corresponding to entries in the
clock-names property.
- clock-names: list of clock names sorted in the same order as the clocks
property. Must contain "aclk_decon", "aclk_smmu_decon0x",
property. Must contain "pclk", "aclk_decon", "aclk_smmu_decon0x",
"aclk_xiu_decon0x", "pclk_smmu_decon0x", clk_decon_vclk",
"sclk_decon_eclk"
- ports: contains a port which is connected to mic node. address-cells and
......
......@@ -5,6 +5,7 @@ Required properties:
1) "samsung,exynos4210-hdmi"
2) "samsung,exynos4212-hdmi"
3) "samsung,exynos5420-hdmi"
4) "samsung,exynos5433-hdmi"
- reg: physical base address of the hdmi and length of memory mapped
region.
- interrupts: interrupt number to the cpu.
......@@ -12,6 +13,11 @@ Required properties:
a) phandle of the gpio controller node.
b) pin number within the gpio controller.
c) optional flags and pull up/down.
- ddc: phandle to the hdmi ddc node
- phy: phandle to the hdmi phy node
- samsung,syscon-phandle: phandle for system controller node for PMU.
Required properties for Exynos 4210, 4212, 5420 and 5433:
- clocks: list of clock IDs from SoC clock driver.
a) hdmi: Gate of HDMI IP bus clock.
b) sclk_hdmi: Gate of HDMI special clock.
......@@ -25,9 +31,24 @@ Required properties:
sclk_pixel.
- clock-names: aliases as per driver requirements for above clock IDs:
"hdmi", "sclk_hdmi", "sclk_pixel", "sclk_hdmiphy" and "mout_hdmi".
- ddc: phandle to the hdmi ddc node
- phy: phandle to the hdmi phy node
- samsung,syscon-phandle: phandle for system controller node for PMU.
Required properties for Exynos 5433:
- clocks: list of clock specifiers according to common clock bindings.
a) hdmi_pclk: Gate of HDMI IP APB bus.
b) hdmi_i_pclk: Gate of HDMI-PHY IP APB bus.
d) i_tmds_clk: Gate of HDMI TMDS clock.
e) i_pixel_clk: Gate of HDMI pixel clock.
f) i_spdif_clk: Gate of HDMI SPDIF clock.
g) oscclk: Oscillator clock, used as parent of following *_user clocks
in case HDMI-PHY is not operational.
h) tmds_clko: TMDS clock generated by HDMI-PHY.
i) tmds_clko_user: MUX used to switch between oscclk and tmds_clko,
respectively if HDMI-PHY is off and operational.
j) pixel_clko: Pixel clock generated by HDMI-PHY.
k) pixel_clko_user: MUX used to switch between oscclk and pixel_clko,
respectively if HDMI-PHY is off and operational.
- clock-names: aliases for above clock specfiers.
- samsung,sysreg: handle to syscon used to control the system registers.
Example:
......
......@@ -95,7 +95,7 @@ comment "Sub-drivers"
config DRM_EXYNOS_G2D
bool "G2D"
depends on !VIDEO_SAMSUNG_S5P_G2D
depends on VIDEO_SAMSUNG_S5P_G2D=n
select FRAME_VECTOR
help
Choose this option if you want to use Exynos G2D for DRM.
......
......@@ -2,10 +2,10 @@
# Makefile for the drm device driver. This driver provides support for the
# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
exynosdrm-y := exynos_drm_drv.o exynos_drm_crtc.o exynos_drm_fbdev.o \
exynos_drm_fb.o exynos_drm_gem.o exynos_drm_core.o \
exynos_drm_plane.o
exynosdrm-y := exynos_drm_drv.o exynos_drm_crtc.o exynos_drm_fb.o \
exynos_drm_gem.o exynos_drm_core.o exynos_drm_plane.o
exynosdrm-$(CONFIG_DRM_FBDEV_EMULATION) += exynos_drm_fbdev.o
exynosdrm-$(CONFIG_DRM_EXYNOS_IOMMU) += exynos_drm_iommu.o
exynosdrm-$(CONFIG_DRM_EXYNOS_FIMD) += exynos_drm_fimd.o
exynosdrm-$(CONFIG_DRM_EXYNOS5433_DECON) += exynos5433_drm_decon.o
......
......@@ -28,6 +28,10 @@
#define WINDOWS_NR 3
#define MIN_FB_WIDTH_FOR_16WORD_BURST 128
#define IFTYPE_I80 (1 << 0)
#define I80_HW_TRG (1 << 1)
#define IFTYPE_HDMI (1 << 2)
static const char * const decon_clks_name[] = {
"pclk",
"aclk_decon",
......@@ -38,12 +42,6 @@ static const char * const decon_clks_name[] = {
"sclk_decon_eclk",
};
enum decon_iftype {
IFTYPE_RGB,
IFTYPE_I80,
IFTYPE_HDMI
};
enum decon_flag_bits {
BIT_CLKS_ENABLED,
BIT_IRQS_ENABLED,
......@@ -61,7 +59,7 @@ struct decon_context {
struct clk *clks[ARRAY_SIZE(decon_clks_name)];
int pipe;
unsigned long flags;
enum decon_iftype out_type;
unsigned long out_type;
int first_win;
};
......@@ -95,7 +93,7 @@ static int decon_enable_vblank(struct exynos_drm_crtc *crtc)
if (!test_and_set_bit(BIT_IRQS_ENABLED, &ctx->flags)) {
val = VIDINTCON0_INTEN;
if (ctx->out_type == IFTYPE_I80)
if (ctx->out_type & IFTYPE_I80)
val |= VIDINTCON0_FRAMEDONE;
else
val |= VIDINTCON0_INTFRMEN;
......@@ -119,11 +117,11 @@ static void decon_disable_vblank(struct exynos_drm_crtc *crtc)
static void decon_setup_trigger(struct decon_context *ctx)
{
u32 val = (ctx->out_type != IFTYPE_HDMI)
u32 val = !(ctx->out_type & I80_HW_TRG)
? TRIGCON_TRIGEN_PER_F | TRIGCON_TRIGEN_F |
TRIGCON_TE_AUTO_MASK | TRIGCON_SWTRIGEN
: TRIGCON_TRIGEN_PER_F | TRIGCON_TRIGEN_F |
TRIGCON_HWTRIGMASK_I80_RGB | TRIGCON_HWTRIGEN_I80_RGB;
TRIGCON_HWTRIGMASK | TRIGCON_HWTRIGEN;
writel(val, ctx->addr + DECON_TRIGCON);
}
......@@ -136,7 +134,7 @@ static void decon_commit(struct exynos_drm_crtc *crtc)
if (test_bit(BIT_SUSPENDED, &ctx->flags))
return;
if (ctx->out_type == IFTYPE_HDMI) {
if (ctx->out_type & IFTYPE_HDMI) {
m->crtc_hsync_start = m->crtc_hdisplay + 10;
m->crtc_hsync_end = m->crtc_htotal - 92;
m->crtc_vsync_start = m->crtc_vdisplay + 1;
......@@ -151,17 +149,20 @@ static void decon_commit(struct exynos_drm_crtc *crtc)
/* lcd on and use command if */
val = VIDOUT_LCD_ON;
if (ctx->out_type == IFTYPE_I80)
if (ctx->out_type & IFTYPE_I80) {
val |= VIDOUT_COMMAND_IF;
else
decon_setup_trigger(ctx);
} else {
val |= VIDOUT_RGB_IF;
}
writel(val, ctx->addr + DECON_VIDOUTCON0);
val = VIDTCON2_LINEVAL(m->vdisplay - 1) |
VIDTCON2_HOZVAL(m->hdisplay - 1);
writel(val, ctx->addr + DECON_VIDTCON2);
if (ctx->out_type != IFTYPE_I80) {
if (!(ctx->out_type & IFTYPE_I80)) {
val = VIDTCON00_VBPD_F(
m->crtc_vtotal - m->crtc_vsync_end - 1) |
VIDTCON00_VFPD_F(
......@@ -183,10 +184,10 @@ static void decon_commit(struct exynos_drm_crtc *crtc)
writel(val, ctx->addr + DECON_VIDTCON11);
}
decon_setup_trigger(ctx);
/* enable output and display signal */
decon_set_bits(ctx, DECON_VIDCON0, VIDCON0_ENVID | VIDCON0_ENVID_F, ~0);
decon_set_bits(ctx, DECON_UPDATE, STANDALONE_UPDATE_F, ~0);
}
static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win,
......@@ -300,7 +301,7 @@ static void decon_update_plane(struct exynos_drm_crtc *crtc,
val = dma_addr + pitch * state->src.h;
writel(val, ctx->addr + DECON_VIDW0xADD1B0(win));
if (ctx->out_type != IFTYPE_HDMI)
if (!(ctx->out_type & IFTYPE_HDMI))
val = BIT_VAL(pitch - state->crtc.w * bpp, 27, 14)
| BIT_VAL(state->crtc.w * bpp, 13, 0);
else
......@@ -312,9 +313,6 @@ static void decon_update_plane(struct exynos_drm_crtc *crtc,
/* window enable */
decon_set_bits(ctx, DECON_WINCONx(win), WINCONx_ENWIN_F, ~0);
/* standalone update */
decon_set_bits(ctx, DECON_UPDATE, STANDALONE_UPDATE_F, ~0);
}
static void decon_disable_plane(struct exynos_drm_crtc *crtc,
......@@ -326,15 +324,7 @@ static void decon_disable_plane(struct exynos_drm_crtc *crtc,
if (test_bit(BIT_SUSPENDED, &ctx->flags))
return;
decon_shadow_protect_win(ctx, win, true);
/* window disable */
decon_set_bits(ctx, DECON_WINCONx(win), WINCONx_ENWIN_F, 0);
decon_shadow_protect_win(ctx, win, false);
/* standalone update */
decon_set_bits(ctx, DECON_UPDATE, STANDALONE_UPDATE_F, ~0);
}
static void decon_atomic_flush(struct exynos_drm_crtc *crtc)
......@@ -348,7 +338,10 @@ static void decon_atomic_flush(struct exynos_drm_crtc *crtc)
for (i = ctx->first_win; i < WINDOWS_NR; i++)
decon_shadow_protect_win(ctx, i, false);
if (ctx->out_type == IFTYPE_I80)
/* standalone update */
decon_set_bits(ctx, DECON_UPDATE, STANDALONE_UPDATE_F, ~0);
if (ctx->out_type & IFTYPE_I80)
set_bit(BIT_WIN_UPDATED, &ctx->flags);
}
......@@ -374,7 +367,7 @@ static void decon_swreset(struct decon_context *ctx)
WARN(tries == 0, "failed to software reset DECON\n");
if (ctx->out_type != IFTYPE_HDMI)
if (!(ctx->out_type & IFTYPE_HDMI))
return;
writel(VIDCON0_CLKVALUP | VIDCON0_VLCKFREE, ctx->addr + DECON_VIDCON0);
......@@ -383,6 +376,8 @@ static void decon_swreset(struct decon_context *ctx)
writel(VIDCON1_VCLK_RUN_VDEN_DISABLE, ctx->addr + DECON_VIDCON1);
writel(CRCCTRL_CRCEN | CRCCTRL_CRCSTART_F | CRCCTRL_CRCCLKEN,
ctx->addr + DECON_CRCCTRL);
if (ctx->out_type & IFTYPE_I80)
decon_setup_trigger(ctx);
}
......@@ -395,8 +390,12 @@ static void decon_enable(struct exynos_drm_crtc *crtc)
pm_runtime_get_sync(ctx->dev);
exynos_drm_pipe_clk_enable(crtc, true);
set_bit(BIT_CLKS_ENABLED, &ctx->flags);
decon_swreset(ctx);
/* if vblank was enabled status, enable it again. */
if (test_and_clear_bit(BIT_IRQS_ENABLED, &ctx->flags))
decon_enable_vblank(ctx->crtc);
......@@ -424,6 +423,8 @@ static void decon_disable(struct exynos_drm_crtc *crtc)
clear_bit(BIT_CLKS_ENABLED, &ctx->flags);
exynos_drm_pipe_clk_enable(crtc, false);
pm_runtime_put_sync(ctx->dev);
set_bit(BIT_SUSPENDED, &ctx->flags);
......@@ -459,8 +460,10 @@ static void decon_clear_channels(struct exynos_drm_crtc *crtc)
decon_shadow_protect_win(ctx, win, true);
decon_set_bits(ctx, DECON_WINCONx(win), WINCONx_ENWIN_F, 0);
decon_shadow_protect_win(ctx, win, false);
decon_set_bits(ctx, DECON_UPDATE, STANDALONE_UPDATE_F, ~0);
}
decon_set_bits(ctx, DECON_UPDATE, STANDALONE_UPDATE_F, ~0);
/* TODO: wait for possible vsync */
msleep(50);
......@@ -509,7 +512,7 @@ static int decon_bind(struct device *dev, struct device *master, void *data)
}
exynos_plane = &ctx->planes[ctx->first_win];
out_type = (ctx->out_type == IFTYPE_HDMI) ? EXYNOS_DISPLAY_TYPE_HDMI
out_type = (ctx->out_type & IFTYPE_HDMI) ? EXYNOS_DISPLAY_TYPE_HDMI
: EXYNOS_DISPLAY_TYPE_LCD;
ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base,
ctx->pipe, out_type,
......@@ -617,11 +620,11 @@ static const struct dev_pm_ops exynos5433_decon_pm_ops = {
static const struct of_device_id exynos5433_decon_driver_dt_match[] = {
{
.compatible = "samsung,exynos5433-decon",
.data = (void *)IFTYPE_RGB
.data = (void *)I80_HW_TRG
},
{
.compatible = "samsung,exynos5433-decon-tv",
.data = (void *)IFTYPE_HDMI
.data = (void *)(I80_HW_TRG | IFTYPE_HDMI)
},
{},
};
......@@ -629,7 +632,6 @@ MODULE_DEVICE_TABLE(of, exynos5433_decon_driver_dt_match);
static int exynos5433_decon_probe(struct platform_device *pdev)
{
const struct of_device_id *of_id;
struct device *dev = &pdev->dev;
struct decon_context *ctx;
struct resource *res;
......@@ -642,14 +644,14 @@ static int exynos5433_decon_probe(struct platform_device *pdev)
__set_bit(BIT_SUSPENDED, &ctx->flags);
ctx->dev = dev;
ctx->out_type = (unsigned long)of_device_get_match_data(dev);
of_id = of_match_device(exynos5433_decon_driver_dt_match, &pdev->dev);
ctx->out_type = (enum decon_iftype)of_id->data;
if (ctx->out_type == IFTYPE_HDMI)
if (ctx->out_type & IFTYPE_HDMI) {
ctx->first_win = 1;
else if (of_get_child_by_name(dev->of_node, "i80-if-timings"))
ctx->out_type = IFTYPE_I80;
} else if (of_get_child_by_name(dev->of_node, "i80-if-timings")) {
ctx->out_type = IFTYPE_I80;
}
for (i = 0; i < ARRAY_SIZE(decon_clks_name); i++) {
struct clk *clk;
......@@ -674,7 +676,7 @@ static int exynos5433_decon_probe(struct platform_device *pdev)
}
res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
(ctx->out_type == IFTYPE_I80) ? "lcd_sys" : "vsync");
(ctx->out_type & IFTYPE_I80) ? "lcd_sys" : "vsync");
if (!res) {
dev_err(dev, "cannot find IRQ resource\n");
return -ENXIO;
......
......@@ -593,7 +593,6 @@ static const struct exynos_drm_crtc_ops decon_crtc_ops = {
.commit = decon_commit,
.enable_vblank = decon_enable_vblank,
.disable_vblank = decon_disable_vblank,
.wait_for_vblank = decon_wait_for_vblank,
.atomic_begin = decon_atomic_begin,
.update_plane = decon_update_plane,
.disable_plane = decon_disable_plane,
......
......@@ -48,14 +48,11 @@ int exynos_dp_crtc_clock_enable(struct analogix_dp_plat_data *plat_data,
{
struct exynos_dp_device *dp = to_dp(plat_data);
struct drm_encoder *encoder = &dp->encoder;
struct exynos_drm_crtc *crtc;
if (!encoder)
return -1;
if (!encoder->crtc)
return -EPERM;
crtc = to_exynos_crtc(encoder->crtc);
if (crtc && crtc->ops && crtc->ops->clock_enable)
crtc->ops->clock_enable(crtc, enable);
exynos_drm_pipe_clk_enable(to_exynos_crtc(encoder->crtc), enable);
return 0;
}
......
......@@ -101,7 +101,7 @@ int exynos_drm_subdrv_open(struct drm_device *dev, struct drm_file *file)
return 0;
err:
list_for_each_entry_reverse(subdrv, &subdrv->list, list) {
list_for_each_entry_continue_reverse(subdrv, &exynos_drm_subdrv_list, list) {
if (subdrv->close)
subdrv->close(dev, subdrv->dev, file);
}
......
......@@ -157,9 +157,8 @@ struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev,
int exynos_drm_crtc_enable_vblank(struct drm_device *dev, unsigned int pipe)
{
struct exynos_drm_private *private = dev->dev_private;
struct exynos_drm_crtc *exynos_crtc =
to_exynos_crtc(private->crtc[pipe]);
struct exynos_drm_crtc *exynos_crtc = exynos_drm_crtc_from_pipe(dev,
pipe);
if (exynos_crtc->ops->enable_vblank)
return exynos_crtc->ops->enable_vblank(exynos_crtc);
......@@ -169,9 +168,8 @@ int exynos_drm_crtc_enable_vblank(struct drm_device *dev, unsigned int pipe)
void exynos_drm_crtc_disable_vblank(struct drm_device *dev, unsigned int pipe)
{
struct exynos_drm_private *private = dev->dev_private;
struct exynos_drm_crtc *exynos_crtc =
to_exynos_crtc(private->crtc[pipe]);
struct exynos_drm_crtc *exynos_crtc = exynos_drm_crtc_from_pipe(dev,
pipe);
if (exynos_crtc->ops->disable_vblank)
exynos_crtc->ops->disable_vblank(exynos_crtc);
......
......@@ -120,8 +120,6 @@ struct exynos_drm_plane_config {
* @commit: set current hw specific display mode to hw.
* @enable_vblank: specific driver callback for enabling vblank interrupt.
* @disable_vblank: specific driver callback for disabling vblank interrupt.
* @wait_for_vblank: wait for vblank interrupt to make sure that
* hardware overlay is updated.
* @atomic_check: validate state
* @atomic_begin: prepare device to receive an update
* @atomic_flush: mark the end of device update
......@@ -129,10 +127,6 @@ struct exynos_drm_plane_config {
* @disable_plane: disable hardware specific overlay.
* @te_handler: trigger to transfer video image at the tearing effect
* synchronization signal if there is a page flip request.
* @clock_enable: optional function enabling/disabling display domain clock,
* called from exynos-dp driver before powering up (with
* 'enable' argument as true) and after powering down (with
* 'enable' as false).
*/
struct exynos_drm_crtc;
struct exynos_drm_crtc_ops {
......@@ -141,7 +135,6 @@ struct exynos_drm_crtc_ops {
void (*commit)(struct exynos_drm_crtc *crtc);
int (*enable_vblank)(struct exynos_drm_crtc *crtc);
void (*disable_vblank)(struct exynos_drm_crtc *crtc);
void (*wait_for_vblank)(struct exynos_drm_crtc *crtc);
int (*atomic_check)(struct exynos_drm_crtc *crtc,
struct drm_crtc_state *state);
void (*atomic_begin)(struct exynos_drm_crtc *crtc);
......@@ -151,7 +144,10 @@ struct exynos_drm_crtc_ops {
struct exynos_drm_plane *plane);
void (*atomic_flush)(struct exynos_drm_crtc *crtc);
void (*te_handler)(struct exynos_drm_crtc *crtc);
void (*clock_enable)(struct exynos_drm_crtc *crtc, bool enable);
};
struct exynos_drm_clk {
void (*enable)(struct exynos_drm_clk *clk, bool enable);
};
/*
......@@ -182,8 +178,16 @@ struct exynos_drm_crtc {
atomic_t pending_update;
const struct exynos_drm_crtc_ops *ops;
void *ctx;
struct exynos_drm_clk *pipe_clk;
};
static inline void exynos_drm_pipe_clk_enable(struct exynos_drm_crtc *crtc,
bool enable)
{
if (crtc->pipe_clk)
crtc->pipe_clk->enable(crtc->pipe_clk, enable);
}
struct exynos_drm_g2d_private {
struct device *dev;
struct list_head inuse_cmdlist;
......@@ -232,6 +236,14 @@ struct exynos_drm_private {
wait_queue_head_t wait;
};
static inline struct exynos_drm_crtc *
exynos_drm_crtc_from_pipe(struct drm_device *dev, int pipe)
{
struct exynos_drm_private *private = dev->dev_private;
return to_exynos_crtc(private->crtc[pipe]);
}
static inline struct device *to_dma_dev(struct drm_device *dev)
{
struct exynos_drm_private *priv = dev->dev_private;
......
......@@ -280,7 +280,7 @@ struct exynos_dsi {
spinlock_t transfer_lock; /* protects transfer_list */
struct list_head transfer_list;
struct exynos_dsi_driver_data *driver_data;
const struct exynos_dsi_driver_data *driver_data;
struct device_node *bridge_node;
};
......@@ -532,15 +532,6 @@ static const struct of_device_id exynos_dsi_of_match[] = {
{ }
};
static inline struct exynos_dsi_driver_data *exynos_dsi_get_driver_data(
struct platform_device *pdev)
{
const struct of_device_id *of_id =
of_match_device(exynos_dsi_of_match, &pdev->dev);
return (struct exynos_dsi_driver_data *)of_id->data;
}
static void exynos_dsi_wait_for_reset(struct exynos_dsi *dsi)
{
if (wait_for_completion_timeout(&dsi->completed, msecs_to_jiffies(300)))
......@@ -564,7 +555,7 @@ static void exynos_dsi_reset(struct exynos_dsi *dsi)
static unsigned long exynos_dsi_pll_find_pms(struct exynos_dsi *dsi,
unsigned long fin, unsigned long fout, u8 *p, u16 *m, u8 *s)
{
struct exynos_dsi_driver_data *driver_data = dsi->driver_data;
const struct exynos_dsi_driver_data *driver_data = dsi->driver_data;
unsigned long best_freq = 0;
u32 min_delta = 0xffffffff;
u8 p_min, p_max;
......@@ -618,7 +609,7 @@ static unsigned long exynos_dsi_pll_find_pms(struct exynos_dsi *dsi,
static unsigned long exynos_dsi_set_pll(struct exynos_dsi *dsi,
unsigned long freq)
{
struct exynos_dsi_driver_data *driver_data = dsi->driver_data;
const struct exynos_dsi_driver_data *driver_data = dsi->driver_data;
unsigned long fin, fout;
int timeout;
u8 p, s;
......@@ -712,7 +703,7 @@ static int exynos_dsi_enable_clock(struct exynos_dsi *dsi)
static void exynos_dsi_set_phy_ctrl(struct exynos_dsi *dsi)
{
struct exynos_dsi_driver_data *driver_data = dsi->driver_data;
const struct exynos_dsi_driver_data *driver_data = dsi->driver_data;
const unsigned int *reg_values = driver_data->reg_values;
u32 reg;
......@@ -790,7 +781,7 @@ static void exynos_dsi_enable_lane(struct exynos_dsi *dsi, u32 lane)
static int exynos_dsi_init_link(struct exynos_dsi *dsi)
{
struct exynos_dsi_driver_data *driver_data = dsi->driver_data;
const struct exynos_dsi_driver_data *driver_data = dsi->driver_data;
int timeout;
u32 reg;
u32 lanes_mask;
......@@ -1334,7 +1325,7 @@ static void exynos_dsi_disable_irq(struct exynos_dsi *dsi)
static int exynos_dsi_init(struct exynos_dsi *dsi)
{
struct exynos_dsi_driver_data *driver_data = dsi->driver_data;
const struct exynos_dsi_driver_data *driver_data = dsi->driver_data;
exynos_dsi_reset(dsi);
exynos_dsi_enable_irq(dsi);
......@@ -1833,7 +1824,7 @@ static int exynos_dsi_probe(struct platform_device *pdev)
dsi->dsi_host.dev = dev;
dsi->dev = dev;
dsi->driver_data = exynos_dsi_get_driver_data(pdev);
dsi->driver_data = of_device_get_match_data(dev);
ret = exynos_dsi_parse_dt(dsi);
if (ret)
......@@ -1917,7 +1908,7 @@ static int __maybe_unused exynos_dsi_suspend(struct device *dev)
{
struct drm_encoder *encoder = dev_get_drvdata(dev);
struct exynos_dsi *dsi = encoder_to_dsi(encoder);
struct exynos_dsi_driver_data *driver_data = dsi->driver_data;
const struct exynos_dsi_driver_data *driver_data = dsi->driver_data;
int ret, i;
usleep_range(10000, 20000);
......@@ -1948,7 +1939,7 @@ static int __maybe_unused exynos_dsi_resume(struct device *dev)
{
struct drm_encoder *encoder = dev_get_drvdata(dev);
struct exynos_dsi *dsi = encoder_to_dsi(encoder);
struct exynos_dsi_driver_data *driver_data = dsi->driver_data;
const struct exynos_dsi_driver_data *driver_data = dsi->driver_data;
int ret, i;
ret = regulator_bulk_enable(ARRAY_SIZE(dsi->supplies), dsi->supplies);
......
......@@ -199,17 +199,6 @@ dma_addr_t exynos_drm_fb_dma_addr(struct drm_framebuffer *fb, int index)
return exynos_fb->dma_addr[index];
}
static void exynos_drm_output_poll_changed(struct drm_device *dev)
{
struct exynos_drm_private *private = dev->dev_private;
struct drm_fb_helper *fb_helper = private->fb_helper;
if (fb_helper)
drm_fb_helper_hotplug_event(fb_helper);
else
exynos_drm_fbdev_init(dev);
}
static const struct drm_mode_config_funcs exynos_drm_mode_config_funcs = {
.fb_create = exynos_user_fb_create,
.output_poll_changed = exynos_drm_output_poll_changed,
......
......@@ -311,3 +311,14 @@ void exynos_drm_fbdev_restore_mode(struct drm_device *dev)
drm_fb_helper_restore_fbdev_mode_unlocked(private->fb_helper);
}
void exynos_drm_output_poll_changed(struct drm_device *dev)
{
struct exynos_drm_private *private = dev->dev_private;
struct drm_fb_helper *fb_helper = private->fb_helper;
if (fb_helper)
drm_fb_helper_hotplug_event(fb_helper);
else
exynos_drm_fbdev_init(dev);
}
......@@ -15,9 +15,30 @@
#ifndef _EXYNOS_DRM_FBDEV_H_
#define _EXYNOS_DRM_FBDEV_H_
#ifdef CONFIG_DRM_FBDEV_EMULATION
int exynos_drm_fbdev_init(struct drm_device *dev);
int exynos_drm_fbdev_reinit(struct drm_device *dev);
void exynos_drm_fbdev_fini(struct drm_device *dev);
void exynos_drm_fbdev_restore_mode(struct drm_device *dev);
void exynos_drm_output_poll_changed(struct drm_device *dev);
#else
static inline int exynos_drm_fbdev_init(struct drm_device *dev)
{
return 0;
}
static inline void exynos_drm_fbdev_fini(struct drm_device *dev)
{
}
static inline void exynos_drm_fbdev_restore_mode(struct drm_device *dev)
{
}
#define exynos_drm_output_poll_changed (NULL)
#endif
#endif
......@@ -68,10 +68,15 @@
/* color key value register for hardware window 1 ~ 4. */
#define WKEYCON1_BASE(x) ((WKEYCON1 + 0x140) + ((x - 1) * 8))
/* I80 / RGB trigger control register */
/* I80 trigger control register */
#define TRIGCON 0x1A4
#define TRGMODE_I80_RGB_ENABLE_I80 (1 << 0)
#define SWTRGCMD_I80_RGB_ENABLE (1 << 1)
#define TRGMODE_ENABLE (1 << 0)
#define SWTRGCMD_ENABLE (1 << 1)
/* Exynos3250, 3472, 4415, 5260 5410, 5420 and 5422 only supported. */
#define HWTRGEN_ENABLE (1 << 3)
#define HWTRGMASK_ENABLE (1 << 4)
/* Exynos3250, 3472, 4415, 5260, 5420 and 5422 only supported. */
#define HWTRIGEN_PER_ENABLE (1 << 31)
/* display mode change control register except exynos4 */
#define VIDOUT_CON 0x000
......@@ -89,12 +94,16 @@
/* FIMD has totally five hardware windows. */
#define WINDOWS_NR 5
/* HW trigger flag on i80 panel. */
#define I80_HW_TRG (1 << 1)
struct fimd_driver_data {
unsigned int timing_base;
unsigned int lcdblk_offset;
unsigned int lcdblk_vt_shift;
unsigned int lcdblk_bypass_shift;
unsigned int lcdblk_mic_bypass_shift;
unsigned int trg_type;
unsigned int has_shadowcon:1;
unsigned int has_clksel:1;
......@@ -102,20 +111,26 @@ struct fimd_driver_data {
unsigned int has_vidoutcon:1;
unsigned int has_vtsel:1;
unsigned int has_mic_bypass:1;
unsigned int has_dp_clk:1;
unsigned int has_hw_trigger:1;
unsigned int has_trigger_per_te:1;
};
static struct fimd_driver_data s3c64xx_fimd_driver_data = {
.timing_base = 0x0,
.has_clksel = 1,
.has_limited_fmt = 1,
.has_hw_trigger = 1,
};
static struct fimd_driver_data exynos3_fimd_driver_data = {
.timing_base = 0x20000,
.lcdblk_offset = 0x210,
.lcdblk_bypass_shift = 1,
.trg_type = I80_HW_TRG,
.has_shadowcon = 1,
.has_vidoutcon = 1,
.has_trigger_per_te = 1,
};
static struct fimd_driver_data exynos4_fimd_driver_data = {
......@@ -132,9 +147,11 @@ static struct fimd_driver_data exynos4415_fimd_driver_data = {
.lcdblk_offset = 0x210,
.lcdblk_vt_shift = 10,
.lcdblk_bypass_shift = 1,
.trg_type = I80_HW_TRG,
.has_shadowcon = 1,
.has_vidoutcon = 1,
.has_vtsel = 1,
.has_trigger_per_te = 1,
};
static struct fimd_driver_data exynos5_fimd_driver_data = {
......@@ -145,6 +162,7 @@ static struct fimd_driver_data exynos5_fimd_driver_data = {
.has_shadowcon = 1,
.has_vidoutcon = 1,
.has_vtsel = 1,
.has_dp_clk = 1,
};
static struct fimd_driver_data exynos5420_fimd_driver_data = {
......@@ -153,10 +171,14 @@ static struct fimd_driver_data exynos5420_fimd_driver_data = {
.lcdblk_vt_shift = 24,
.lcdblk_bypass_shift = 15,
.lcdblk_mic_bypass_shift = 11,
.trg_type = I80_HW_TRG,
.has_shadowcon = 1,
.has_vidoutcon = 1,
.has_vtsel = 1,
.has_mic_bypass = 1,
.has_dp_clk = 1,
.has_hw_trigger = 1,
.has_trigger_per_te = 1,
};
struct fimd_context {
......@@ -182,8 +204,9 @@ struct fimd_context {
atomic_t win_updated;
atomic_t triggering;
struct fimd_driver_data *driver_data;
const struct fimd_driver_data *driver_data;
struct drm_encoder *encoder;
struct exynos_drm_clk dp_clk;
};
static const struct of_device_id fimd_driver_dt_match[] = {
......@@ -219,15 +242,6 @@ static const uint32_t fimd_formats[] = {
DRM_FORMAT_ARGB8888,
};
static inline struct fimd_driver_data *drm_fimd_get_driver_data(
struct platform_device *pdev)
{
const struct of_device_id *of_id =
of_match_device(fimd_driver_dt_match, &pdev->dev);
return (struct fimd_driver_data *)of_id->data;
}
static int fimd_enable_vblank(struct exynos_drm_crtc *crtc)
{
struct fimd_context *ctx = crtc->ctx;
......@@ -400,11 +414,31 @@ static u32 fimd_calc_clkdiv(struct fimd_context *ctx,
return (clkdiv < 0x100) ? clkdiv : 0xff;
}
static void fimd_setup_trigger(struct fimd_context *ctx)
{
void __iomem *timing_base = ctx->regs + ctx->driver_data->timing_base;
u32 trg_type = ctx->driver_data->trg_type;
u32 val = readl(timing_base + TRIGCON);
val &= ~(TRGMODE_ENABLE);
if (trg_type == I80_HW_TRG) {
if (ctx->driver_data->has_hw_trigger)
val |= HWTRGEN_ENABLE | HWTRGMASK_ENABLE;
if (ctx->driver_data->has_trigger_per_te)
val |= HWTRIGEN_PER_ENABLE;
} else {
val |= TRGMODE_ENABLE;
}
writel(val, timing_base + TRIGCON);
}
static void fimd_commit(struct exynos_drm_crtc *crtc)
{
struct fimd_context *ctx = crtc->ctx;
struct drm_display_mode *mode = &crtc->base.state->adjusted_mode;
struct fimd_driver_data *driver_data = ctx->driver_data;
const struct fimd_driver_data *driver_data = ctx->driver_data;
void *timing_base = ctx->regs + driver_data->timing_base;
u32 val, clkdiv;
......@@ -495,6 +529,8 @@ static void fimd_commit(struct exynos_drm_crtc *crtc)
VIDTCON2_HOZVAL_E(mode->hdisplay - 1);
writel(val, ctx->regs + driver_data->timing_base + VIDTCON2);
fimd_setup_trigger(ctx);
/*
* fields of register with prefix '_F' would be updated
* at vsync(same as dma start)
......@@ -827,7 +863,7 @@ static void fimd_disable(struct exynos_drm_crtc *crtc)
static void fimd_trigger(struct device *dev)
{
struct fimd_context *ctx = dev_get_drvdata(dev);
struct fimd_driver_data *driver_data = ctx->driver_data;
const struct fimd_driver_data *driver_data = ctx->driver_data;
void *timing_base = ctx->regs + driver_data->timing_base;
u32 reg;
......@@ -842,7 +878,7 @@ static void fimd_trigger(struct device *dev)
atomic_set(&ctx->triggering, 1);
reg = readl(timing_base + TRIGCON);
reg |= (TRGMODE_I80_RGB_ENABLE_I80 | SWTRGCMD_I80_RGB_ENABLE);
reg |= (TRGMODE_ENABLE | SWTRGCMD_ENABLE);
writel(reg, timing_base + TRIGCON);
/*
......@@ -856,11 +892,15 @@ static void fimd_trigger(struct device *dev)
static void fimd_te_handler(struct exynos_drm_crtc *crtc)
{
struct fimd_context *ctx = crtc->ctx;
u32 trg_type = ctx->driver_data->trg_type;
/* Checks the crtc is detached already from encoder */
if (ctx->pipe < 0 || !ctx->drm_dev)
return;
if (trg_type == I80_HW_TRG)
goto out;
/*
* If there is a page flip request, triggers and handles the page flip
* event so that current fb can be updated into panel GRAM.
......@@ -868,6 +908,7 @@ static void fimd_te_handler(struct exynos_drm_crtc *crtc)
if (atomic_add_unless(&ctx->win_updated, -1, 0))
fimd_trigger(ctx->dev);
out:
/* Wakes up vsync event queue */
if (atomic_read(&ctx->wait_vsync_event)) {
atomic_set(&ctx->wait_vsync_event, 0);
......@@ -878,21 +919,12 @@ static void fimd_te_handler(struct exynos_drm_crtc *crtc)
drm_crtc_handle_vblank(&ctx->crtc->base);
}
static void fimd_dp_clock_enable(struct exynos_drm_crtc *crtc, bool enable)
static void fimd_dp_clock_enable(struct exynos_drm_clk *clk, bool enable)
{
struct fimd_context *ctx = crtc->ctx;
u32 val;
struct fimd_context *ctx = container_of(clk, struct fimd_context,
dp_clk);
u32 val = enable ? DP_MIE_CLK_DP_ENABLE : DP_MIE_CLK_DISABLE;
/*
* Only Exynos 5250, 5260, 5410 and 542x requires enabling DP/MIE
* clock. On these SoCs the bootloader may enable it but any
* power domain off/on will reset it to disable state.
*/
if (ctx->driver_data != &exynos5_fimd_driver_data ||
ctx->driver_data != &exynos5420_fimd_driver_data)
return;
val = enable ? DP_MIE_CLK_DP_ENABLE : DP_MIE_CLK_DISABLE;
writel(val, ctx->regs + DP_MIE_CLKCON);
}
......@@ -902,13 +934,11 @@ static const struct exynos_drm_crtc_ops fimd_crtc_ops = {
.commit = fimd_commit,
.enable_vblank = fimd_enable_vblank,
.disable_vblank = fimd_disable_vblank,
.wait_for_vblank = fimd_wait_for_vblank,
.atomic_begin = fimd_atomic_begin,
.update_plane = fimd_update_plane,
.disable_plane = fimd_disable_plane,
.atomic_flush = fimd_atomic_flush,
.te_handler = fimd_te_handler,
.clock_enable = fimd_dp_clock_enable,
};
static irqreturn_t fimd_irq_handler(int irq, void *dev_id)
......@@ -987,6 +1017,11 @@ static int fimd_bind(struct device *dev, struct device *master, void *data)
if (IS_ERR(ctx->crtc))
return PTR_ERR(ctx->crtc);
if (ctx->driver_data->has_dp_clk) {
ctx->dp_clk.enable = fimd_dp_clock_enable;
ctx->crtc->pipe_clk = &ctx->dp_clk;
}
if (ctx->encoder)
exynos_dpi_bind(drm_dev, ctx->encoder);
......@@ -1035,7 +1070,7 @@ static int fimd_probe(struct platform_device *pdev)
ctx->dev = dev;
ctx->suspended = true;
ctx->driver_data = drm_fimd_get_driver_data(pdev);
ctx->driver_data = of_device_get_match_data(dev);
if (of_property_read_bool(dev->of_node, "samsung,invert-vden"))
ctx->vidcon1 |= VIDCON1_INV_VDEN;
......
......@@ -129,7 +129,7 @@ static void mic_set_path(struct exynos_mic *mic, bool enable)
} else
val &= ~(MIC0_RGB_MUX | MIC0_I80_MUX | MIC0_ON_MUX);
regmap_write(mic->sysreg, DSD_CFG_MUX, val);
ret = regmap_write(mic->sysreg, DSD_CFG_MUX, val);
if (ret)
DRM_ERROR("mic: Failed to read system register\n");
}
......@@ -457,6 +457,7 @@ static int exynos_mic_probe(struct platform_device *pdev)
"samsung,disp-syscon");
if (IS_ERR(mic->sysreg)) {
DRM_ERROR("mic: Failed to get system register.\n");
ret = PTR_ERR(mic->sysreg);
goto err;
}
......
......@@ -11,9 +11,10 @@
#include <drm/drmP.h>
#include <drm/exynos_drm.h>
#include <drm/drm_plane_helper.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_plane_helper.h>
#include <drm/exynos_drm.h>
#include "exynos_drm_drv.h"
#include "exynos_drm_crtc.h"
#include "exynos_drm_fb.h"
......@@ -57,11 +58,12 @@ static int exynos_plane_get_size(int start, unsigned length, unsigned last)
}
static void exynos_plane_mode_set(struct exynos_drm_plane_state *exynos_state)
{
struct drm_plane_state *state = &exynos_state->base;
struct drm_crtc *crtc = exynos_state->base.crtc;
struct drm_display_mode *mode = &crtc->state->adjusted_mode;
struct drm_crtc *crtc = state->crtc;
struct drm_crtc_state *crtc_state =
drm_atomic_get_existing_crtc_state(state->state, crtc);
struct drm_display_mode *mode = &crtc_state->adjusted_mode;
int crtc_x, crtc_y;
unsigned int crtc_w, crtc_h;
unsigned int src_x, src_y;
......
......@@ -15,6 +15,7 @@
#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/of_device.h>
#include <linux/pm_runtime.h>
#include <drm/drmP.h>
......@@ -696,7 +697,6 @@ static int rotator_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct rot_context *rot;
struct exynos_drm_ippdrv *ippdrv;
const struct of_device_id *match;
int ret;
if (!dev->of_node) {
......@@ -708,13 +708,8 @@ static int rotator_probe(struct platform_device *pdev)
if (!rot)
return -ENOMEM;
match = of_match_node(exynos_rotator_match, dev->of_node);
if (!match) {
dev_err(dev, "failed to match node\n");
return -ENODEV;
}
rot->limit_tbl = (struct rot_limit_table *)match->data;
rot->limit_tbl = (struct rot_limit_table *)
of_device_get_match_data(dev);
rot->regs_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
rot->regs = devm_ioremap_resource(dev, rot->regs_res);
if (IS_ERR(rot->regs))
......
......@@ -49,14 +49,16 @@
/* AVI header and aspect ratio */
#define HDMI_AVI_VERSION 0x02
#define HDMI_AVI_LENGTH 0x0D
#define HDMI_AVI_LENGTH 0x0d
/* AUI header info */
#define HDMI_AUI_VERSION 0x01
#define HDMI_AUI_LENGTH 0x0A
#define AVI_SAME_AS_PIC_ASPECT_RATIO 0x8
#define AVI_4_3_CENTER_RATIO 0x9
#define AVI_16_9_CENTER_RATIO 0xa
#define HDMI_AUI_LENGTH 0x0a
/* AVI active format aspect ratio */
#define AVI_SAME_AS_PIC_ASPECT_RATIO 0x08
#define AVI_4_3_CENTER_RATIO 0x09
#define AVI_16_9_CENTER_RATIO 0x0a
enum hdmi_type {
HDMI_TYPE13,
......@@ -90,11 +92,34 @@ static const char * const supply[] = {
"vdd_pll",
};
struct hdmiphy_config {
int pixel_clock;
u8 conf[32];
};
struct hdmiphy_configs {
int count;
const struct hdmiphy_config *data;
};
struct string_array_spec {
int count;
const char * const *data;
};
#define INIT_ARRAY_SPEC(a) { .count = ARRAY_SIZE(a), .data = a }
struct hdmi_driver_data {
unsigned int type;
const struct hdmiphy_config *phy_confs;
unsigned int phy_conf_count;
unsigned int is_apb_phy:1;
unsigned int has_sysreg:1;
struct hdmiphy_configs phy_confs;
struct string_array_spec clk_gates;
/*
* Array of triplets (p_off, p_on, clock), where p_off and p_on are
* required parents of clock when HDMI-PHY is respectively off or on.
*/
struct string_array_spec clk_muxes;
};
struct hdmi_context {
......@@ -116,11 +141,9 @@ struct hdmi_context {
struct gpio_desc *hpd_gpio;
int irq;
struct regmap *pmureg;
struct clk *hdmi;
struct clk *sclk_hdmi;
struct clk *sclk_pixel;
struct clk *sclk_hdmiphy;
struct clk *mout_hdmi;
struct regmap *sysreg;
struct clk **clk_gates;
struct clk **clk_muxes;
struct regulator_bulk_data regul_bulk[ARRAY_SIZE(supply)];
struct regulator *reg_hdmi_en;
};
......@@ -135,12 +158,6 @@ static inline struct hdmi_context *connector_to_hdmi(struct drm_connector *c)
return container_of(c, struct hdmi_context, connector);
}
struct hdmiphy_config {
int pixel_clock;
u8 conf[32];
};
/* list of phy config settings */
static const struct hdmiphy_config hdmiphy_v13_configs[] = {
{
.pixel_clock = 27000000,
......@@ -501,25 +518,136 @@ static const struct hdmiphy_config hdmiphy_5420_configs[] = {
},
};
static struct hdmi_driver_data exynos5420_hdmi_driver_data = {
static const struct hdmiphy_config hdmiphy_5433_configs[] = {
{
.pixel_clock = 27000000,
.conf = {
0x01, 0x51, 0x22, 0x51, 0x08, 0xfc, 0x88, 0x46,
0x72, 0x50, 0x24, 0x0c, 0x24, 0x0f, 0x7c, 0xa5,
0xd4, 0x2b, 0x87, 0x00, 0x00, 0x04, 0x00, 0x30,
0x08, 0x10, 0x01, 0x01, 0x48, 0x40, 0x00, 0x40,
},
},
{
.pixel_clock = 27027000,
.conf = {
0x01, 0x51, 0x2d, 0x72, 0x64, 0x09, 0x88, 0xc3,
0x71, 0x50, 0x24, 0x14, 0x24, 0x0f, 0x7c, 0xa5,
0xd4, 0x2b, 0x87, 0x00, 0x00, 0x04, 0x00, 0x30,
0x28, 0x10, 0x01, 0x01, 0x48, 0x40, 0x00, 0x40,
},
},
{
.pixel_clock = 40000000,
.conf = {
0x01, 0x51, 0x32, 0x55, 0x01, 0x00, 0x88, 0x02,
0x4d, 0x50, 0x44, 0x8C, 0x27, 0x00, 0x7C, 0xAC,
0xD6, 0x2B, 0x67, 0x00, 0x00, 0x04, 0x00, 0x30,
0x08, 0x10, 0x01, 0x01, 0x48, 0x40, 0x00, 0x40,
},
},
{
.pixel_clock = 50000000,
.conf = {
0x01, 0x51, 0x34, 0x40, 0x64, 0x09, 0x88, 0xc3,
0x3d, 0x50, 0x44, 0x8C, 0x27, 0x00, 0x7C, 0xAC,
0xD6, 0x2B, 0x67, 0x00, 0x00, 0x04, 0x00, 0x30,
0x08, 0x10, 0x01, 0x01, 0x48, 0x40, 0x00, 0x40,
},
},
{
.pixel_clock = 65000000,
.conf = {
0x01, 0x51, 0x36, 0x31, 0x40, 0x10, 0x04, 0xc6,
0x2e, 0xe8, 0x44, 0x8C, 0x27, 0x00, 0x7C, 0xAC,
0xD6, 0x2B, 0x67, 0x00, 0x00, 0x04, 0x00, 0x30,
0x08, 0x10, 0x01, 0x01, 0x48, 0x40, 0x00, 0x40,
},
},
{
.pixel_clock = 74176000,
.conf = {
0x01, 0x51, 0x3E, 0x35, 0x5B, 0xDE, 0x88, 0x42,
0x53, 0x51, 0x44, 0x8C, 0x27, 0x00, 0x7C, 0xAC,
0xD6, 0x2B, 0x67, 0x00, 0x00, 0x04, 0x00, 0x30,
0x08, 0x10, 0x01, 0x01, 0x48, 0x40, 0x00, 0x40,
},
},
{
.pixel_clock = 74250000,
.conf = {
0x01, 0x51, 0x3E, 0x35, 0x40, 0xF0, 0x88, 0xC2,
0x52, 0x51, 0x44, 0x8C, 0x27, 0x00, 0x7C, 0xAC,
0xD6, 0x2B, 0x67, 0x00, 0x00, 0x04, 0x00, 0x30,
0x08, 0x10, 0x01, 0x01, 0x48, 0x40, 0x00, 0x40,
},
},
{
.pixel_clock = 108000000,
.conf = {
0x01, 0x51, 0x2d, 0x15, 0x01, 0x00, 0x88, 0x02,
0x72, 0x52, 0x44, 0x8C, 0x27, 0x00, 0x7C, 0xAC,
0xD6, 0x2B, 0x67, 0x00, 0x00, 0x04, 0x00, 0x30,
0x08, 0x10, 0x01, 0x01, 0x48, 0x40, 0x00, 0x40,
},
},
{
.pixel_clock = 148500000,
.conf = {
0x01, 0x51, 0x1f, 0x00, 0x40, 0xf8, 0x88, 0xc1,
0x52, 0x52, 0x24, 0x0c, 0x24, 0x0f, 0x7c, 0xa5,
0xd4, 0x2b, 0x87, 0x00, 0x00, 0x04, 0x00, 0x30,
0x08, 0x10, 0x01, 0x01, 0x48, 0x4a, 0x00, 0x40,
},
},
};
static const char * const hdmi_clk_gates4[] = {
"hdmi", "sclk_hdmi"
};
static const char * const hdmi_clk_muxes4[] = {
"sclk_pixel", "sclk_hdmiphy", "mout_hdmi"
};
static const char * const hdmi_clk_gates5433[] = {
"hdmi_pclk", "hdmi_i_pclk", "i_tmds_clk", "i_pixel_clk", "i_spdif_clk"
};
static const char * const hdmi_clk_muxes5433[] = {
"oscclk", "tmds_clko", "tmds_clko_user",
"oscclk", "pixel_clko", "pixel_clko_user"
};
static const struct hdmi_driver_data exynos4210_hdmi_driver_data = {
.type = HDMI_TYPE13,
.phy_confs = INIT_ARRAY_SPEC(hdmiphy_v13_configs),
.clk_gates = INIT_ARRAY_SPEC(hdmi_clk_gates4),
.clk_muxes = INIT_ARRAY_SPEC(hdmi_clk_muxes4),
};
static const struct hdmi_driver_data exynos4212_hdmi_driver_data = {
.type = HDMI_TYPE14,
.phy_confs = hdmiphy_5420_configs,
.phy_conf_count = ARRAY_SIZE(hdmiphy_5420_configs),
.is_apb_phy = 1,
.phy_confs = INIT_ARRAY_SPEC(hdmiphy_v14_configs),
.clk_gates = INIT_ARRAY_SPEC(hdmi_clk_gates4),
.clk_muxes = INIT_ARRAY_SPEC(hdmi_clk_muxes4),
};
static struct hdmi_driver_data exynos4212_hdmi_driver_data = {
static const struct hdmi_driver_data exynos5420_hdmi_driver_data = {
.type = HDMI_TYPE14,
.phy_confs = hdmiphy_v14_configs,
.phy_conf_count = ARRAY_SIZE(hdmiphy_v14_configs),
.is_apb_phy = 0,
.is_apb_phy = 1,
.phy_confs = INIT_ARRAY_SPEC(hdmiphy_5420_configs),
.clk_gates = INIT_ARRAY_SPEC(hdmi_clk_gates4),
.clk_muxes = INIT_ARRAY_SPEC(hdmi_clk_muxes4),
};
static struct hdmi_driver_data exynos4210_hdmi_driver_data = {
.type = HDMI_TYPE13,
.phy_confs = hdmiphy_v13_configs,
.phy_conf_count = ARRAY_SIZE(hdmiphy_v13_configs),
.is_apb_phy = 0,
static const struct hdmi_driver_data exynos5433_hdmi_driver_data = {
.type = HDMI_TYPE14,
.is_apb_phy = 1,
.has_sysreg = 1,
.phy_confs = INIT_ARRAY_SPEC(hdmiphy_5433_configs),
.clk_gates = INIT_ARRAY_SPEC(hdmi_clk_gates5433),
.clk_muxes = INIT_ARRAY_SPEC(hdmi_clk_muxes5433),
};
static inline u32 hdmi_map_reg(struct hdmi_context *hdata, u32 reg_id)
......@@ -585,266 +713,52 @@ static int hdmiphy_reg_write_buf(struct hdmi_context *hdata,
}
}
static void hdmi_v13_regs_dump(struct hdmi_context *hdata, char *prefix)
static int hdmi_clk_enable_gates(struct hdmi_context *hdata)
{
#define DUMPREG(reg_id) \
DRM_DEBUG_KMS("%s:" #reg_id " = %08x\n", prefix, \
readl(hdata->regs + reg_id))
DRM_DEBUG_KMS("%s: ---- CONTROL REGISTERS ----\n", prefix);
DUMPREG(HDMI_INTC_FLAG);
DUMPREG(HDMI_INTC_CON);
DUMPREG(HDMI_HPD_STATUS);
DUMPREG(HDMI_V13_PHY_RSTOUT);
DUMPREG(HDMI_V13_PHY_VPLL);
DUMPREG(HDMI_V13_PHY_CMU);
DUMPREG(HDMI_V13_CORE_RSTOUT);
DRM_DEBUG_KMS("%s: ---- CORE REGISTERS ----\n", prefix);
DUMPREG(HDMI_CON_0);
DUMPREG(HDMI_CON_1);
DUMPREG(HDMI_CON_2);
DUMPREG(HDMI_SYS_STATUS);
DUMPREG(HDMI_V13_PHY_STATUS);
DUMPREG(HDMI_STATUS_EN);
DUMPREG(HDMI_HPD);
DUMPREG(HDMI_MODE_SEL);
DUMPREG(HDMI_V13_HPD_GEN);
DUMPREG(HDMI_V13_DC_CONTROL);
DUMPREG(HDMI_V13_VIDEO_PATTERN_GEN);
DRM_DEBUG_KMS("%s: ---- CORE SYNC REGISTERS ----\n", prefix);
DUMPREG(HDMI_H_BLANK_0);
DUMPREG(HDMI_H_BLANK_1);
DUMPREG(HDMI_V13_V_BLANK_0);
DUMPREG(HDMI_V13_V_BLANK_1);
DUMPREG(HDMI_V13_V_BLANK_2);
DUMPREG(HDMI_V13_H_V_LINE_0);
DUMPREG(HDMI_V13_H_V_LINE_1);
DUMPREG(HDMI_V13_H_V_LINE_2);
DUMPREG(HDMI_VSYNC_POL);
DUMPREG(HDMI_INT_PRO_MODE);
DUMPREG(HDMI_V13_V_BLANK_F_0);
DUMPREG(HDMI_V13_V_BLANK_F_1);
DUMPREG(HDMI_V13_V_BLANK_F_2);
DUMPREG(HDMI_V13_H_SYNC_GEN_0);
DUMPREG(HDMI_V13_H_SYNC_GEN_1);
DUMPREG(HDMI_V13_H_SYNC_GEN_2);
DUMPREG(HDMI_V13_V_SYNC_GEN_1_0);
DUMPREG(HDMI_V13_V_SYNC_GEN_1_1);
DUMPREG(HDMI_V13_V_SYNC_GEN_1_2);
DUMPREG(HDMI_V13_V_SYNC_GEN_2_0);
DUMPREG(HDMI_V13_V_SYNC_GEN_2_1);
DUMPREG(HDMI_V13_V_SYNC_GEN_2_2);
DUMPREG(HDMI_V13_V_SYNC_GEN_3_0);
DUMPREG(HDMI_V13_V_SYNC_GEN_3_1);
DUMPREG(HDMI_V13_V_SYNC_GEN_3_2);
DRM_DEBUG_KMS("%s: ---- TG REGISTERS ----\n", prefix);
DUMPREG(HDMI_TG_CMD);
DUMPREG(HDMI_TG_H_FSZ_L);
DUMPREG(HDMI_TG_H_FSZ_H);
DUMPREG(HDMI_TG_HACT_ST_L);
DUMPREG(HDMI_TG_HACT_ST_H);
DUMPREG(HDMI_TG_HACT_SZ_L);
DUMPREG(HDMI_TG_HACT_SZ_H);
DUMPREG(HDMI_TG_V_FSZ_L);
DUMPREG(HDMI_TG_V_FSZ_H);
DUMPREG(HDMI_TG_VSYNC_L);
DUMPREG(HDMI_TG_VSYNC_H);
DUMPREG(HDMI_TG_VSYNC2_L);
DUMPREG(HDMI_TG_VSYNC2_H);
DUMPREG(HDMI_TG_VACT_ST_L);
DUMPREG(HDMI_TG_VACT_ST_H);
DUMPREG(HDMI_TG_VACT_SZ_L);
DUMPREG(HDMI_TG_VACT_SZ_H);
DUMPREG(HDMI_TG_FIELD_CHG_L);
DUMPREG(HDMI_TG_FIELD_CHG_H);
DUMPREG(HDMI_TG_VACT_ST2_L);
DUMPREG(HDMI_TG_VACT_ST2_H);
DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_L);
DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_H);
DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_L);
DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_H);
DUMPREG(HDMI_TG_FIELD_TOP_HDMI_L);
DUMPREG(HDMI_TG_FIELD_TOP_HDMI_H);
DUMPREG(HDMI_TG_FIELD_BOT_HDMI_L);
DUMPREG(HDMI_TG_FIELD_BOT_HDMI_H);
#undef DUMPREG
int i, ret;
for (i = 0; i < hdata->drv_data->clk_gates.count; ++i) {
ret = clk_prepare_enable(hdata->clk_gates[i]);
if (!ret)
continue;
dev_err(hdata->dev, "Cannot enable clock '%s', %d\n",
hdata->drv_data->clk_gates.data[i], ret);
while (i--)
clk_disable_unprepare(hdata->clk_gates[i]);
return ret;
}
return 0;
}
static void hdmi_v14_regs_dump(struct hdmi_context *hdata, char *prefix)
static void hdmi_clk_disable_gates(struct hdmi_context *hdata)
{
int i;
int i = hdata->drv_data->clk_gates.count;
#define DUMPREG(reg_id) \
DRM_DEBUG_KMS("%s:" #reg_id " = %08x\n", prefix, \
readl(hdata->regs + reg_id))
DRM_DEBUG_KMS("%s: ---- CONTROL REGISTERS ----\n", prefix);
DUMPREG(HDMI_INTC_CON);
DUMPREG(HDMI_INTC_FLAG);
DUMPREG(HDMI_HPD_STATUS);
DUMPREG(HDMI_INTC_CON_1);
DUMPREG(HDMI_INTC_FLAG_1);
DUMPREG(HDMI_PHY_STATUS_0);
DUMPREG(HDMI_PHY_STATUS_PLL);
DUMPREG(HDMI_PHY_CON_0);
DUMPREG(HDMI_V14_PHY_RSTOUT);
DUMPREG(HDMI_PHY_VPLL);
DUMPREG(HDMI_PHY_CMU);
DUMPREG(HDMI_CORE_RSTOUT);
DRM_DEBUG_KMS("%s: ---- CORE REGISTERS ----\n", prefix);
DUMPREG(HDMI_CON_0);
DUMPREG(HDMI_CON_1);
DUMPREG(HDMI_CON_2);
DUMPREG(HDMI_SYS_STATUS);
DUMPREG(HDMI_PHY_STATUS_0);
DUMPREG(HDMI_STATUS_EN);
DUMPREG(HDMI_HPD);
DUMPREG(HDMI_MODE_SEL);
DUMPREG(HDMI_ENC_EN);
DUMPREG(HDMI_DC_CONTROL);
DUMPREG(HDMI_VIDEO_PATTERN_GEN);
DRM_DEBUG_KMS("%s: ---- CORE SYNC REGISTERS ----\n", prefix);
DUMPREG(HDMI_H_BLANK_0);
DUMPREG(HDMI_H_BLANK_1);
DUMPREG(HDMI_V2_BLANK_0);
DUMPREG(HDMI_V2_BLANK_1);
DUMPREG(HDMI_V1_BLANK_0);
DUMPREG(HDMI_V1_BLANK_1);
DUMPREG(HDMI_V_LINE_0);
DUMPREG(HDMI_V_LINE_1);
DUMPREG(HDMI_H_LINE_0);
DUMPREG(HDMI_H_LINE_1);
DUMPREG(HDMI_HSYNC_POL);
DUMPREG(HDMI_VSYNC_POL);
DUMPREG(HDMI_INT_PRO_MODE);
DUMPREG(HDMI_V_BLANK_F0_0);
DUMPREG(HDMI_V_BLANK_F0_1);
DUMPREG(HDMI_V_BLANK_F1_0);
DUMPREG(HDMI_V_BLANK_F1_1);
DUMPREG(HDMI_H_SYNC_START_0);
DUMPREG(HDMI_H_SYNC_START_1);
DUMPREG(HDMI_H_SYNC_END_0);
DUMPREG(HDMI_H_SYNC_END_1);
DUMPREG(HDMI_V_SYNC_LINE_BEF_2_0);
DUMPREG(HDMI_V_SYNC_LINE_BEF_2_1);
DUMPREG(HDMI_V_SYNC_LINE_BEF_1_0);
DUMPREG(HDMI_V_SYNC_LINE_BEF_1_1);
DUMPREG(HDMI_V_SYNC_LINE_AFT_2_0);
DUMPREG(HDMI_V_SYNC_LINE_AFT_2_1);
DUMPREG(HDMI_V_SYNC_LINE_AFT_1_0);
DUMPREG(HDMI_V_SYNC_LINE_AFT_1_1);
DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_2_0);
DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_2_1);
DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_1_0);
DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_1_1);
DUMPREG(HDMI_V_BLANK_F2_0);
DUMPREG(HDMI_V_BLANK_F2_1);
DUMPREG(HDMI_V_BLANK_F3_0);
DUMPREG(HDMI_V_BLANK_F3_1);
DUMPREG(HDMI_V_BLANK_F4_0);
DUMPREG(HDMI_V_BLANK_F4_1);
DUMPREG(HDMI_V_BLANK_F5_0);
DUMPREG(HDMI_V_BLANK_F5_1);
DUMPREG(HDMI_V_SYNC_LINE_AFT_3_0);
DUMPREG(HDMI_V_SYNC_LINE_AFT_3_1);
DUMPREG(HDMI_V_SYNC_LINE_AFT_4_0);
DUMPREG(HDMI_V_SYNC_LINE_AFT_4_1);
DUMPREG(HDMI_V_SYNC_LINE_AFT_5_0);
DUMPREG(HDMI_V_SYNC_LINE_AFT_5_1);
DUMPREG(HDMI_V_SYNC_LINE_AFT_6_0);
DUMPREG(HDMI_V_SYNC_LINE_AFT_6_1);
DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_3_0);
DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_3_1);
DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_4_0);
DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_4_1);
DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_5_0);
DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_5_1);
DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_6_0);
DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_6_1);
DUMPREG(HDMI_VACT_SPACE_1_0);
DUMPREG(HDMI_VACT_SPACE_1_1);
DUMPREG(HDMI_VACT_SPACE_2_0);
DUMPREG(HDMI_VACT_SPACE_2_1);
DUMPREG(HDMI_VACT_SPACE_3_0);
DUMPREG(HDMI_VACT_SPACE_3_1);
DUMPREG(HDMI_VACT_SPACE_4_0);
DUMPREG(HDMI_VACT_SPACE_4_1);
DUMPREG(HDMI_VACT_SPACE_5_0);
DUMPREG(HDMI_VACT_SPACE_5_1);
DUMPREG(HDMI_VACT_SPACE_6_0);
DUMPREG(HDMI_VACT_SPACE_6_1);
DRM_DEBUG_KMS("%s: ---- TG REGISTERS ----\n", prefix);
DUMPREG(HDMI_TG_CMD);
DUMPREG(HDMI_TG_H_FSZ_L);
DUMPREG(HDMI_TG_H_FSZ_H);
DUMPREG(HDMI_TG_HACT_ST_L);
DUMPREG(HDMI_TG_HACT_ST_H);
DUMPREG(HDMI_TG_HACT_SZ_L);
DUMPREG(HDMI_TG_HACT_SZ_H);
DUMPREG(HDMI_TG_V_FSZ_L);
DUMPREG(HDMI_TG_V_FSZ_H);
DUMPREG(HDMI_TG_VSYNC_L);
DUMPREG(HDMI_TG_VSYNC_H);
DUMPREG(HDMI_TG_VSYNC2_L);
DUMPREG(HDMI_TG_VSYNC2_H);
DUMPREG(HDMI_TG_VACT_ST_L);
DUMPREG(HDMI_TG_VACT_ST_H);
DUMPREG(HDMI_TG_VACT_SZ_L);
DUMPREG(HDMI_TG_VACT_SZ_H);
DUMPREG(HDMI_TG_FIELD_CHG_L);
DUMPREG(HDMI_TG_FIELD_CHG_H);
DUMPREG(HDMI_TG_VACT_ST2_L);
DUMPREG(HDMI_TG_VACT_ST2_H);
DUMPREG(HDMI_TG_VACT_ST3_L);
DUMPREG(HDMI_TG_VACT_ST3_H);
DUMPREG(HDMI_TG_VACT_ST4_L);
DUMPREG(HDMI_TG_VACT_ST4_H);
DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_L);
DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_H);
DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_L);
DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_H);
DUMPREG(HDMI_TG_FIELD_TOP_HDMI_L);
DUMPREG(HDMI_TG_FIELD_TOP_HDMI_H);
DUMPREG(HDMI_TG_FIELD_BOT_HDMI_L);
DUMPREG(HDMI_TG_FIELD_BOT_HDMI_H);
DUMPREG(HDMI_TG_3D);
DRM_DEBUG_KMS("%s: ---- PACKET REGISTERS ----\n", prefix);
DUMPREG(HDMI_AVI_CON);
DUMPREG(HDMI_AVI_HEADER0);
DUMPREG(HDMI_AVI_HEADER1);
DUMPREG(HDMI_AVI_HEADER2);
DUMPREG(HDMI_AVI_CHECK_SUM);
DUMPREG(HDMI_VSI_CON);
DUMPREG(HDMI_VSI_HEADER0);
DUMPREG(HDMI_VSI_HEADER1);
DUMPREG(HDMI_VSI_HEADER2);
for (i = 0; i < 7; ++i)
DUMPREG(HDMI_VSI_DATA(i));
#undef DUMPREG
while (i--)
clk_disable_unprepare(hdata->clk_gates[i]);
}
static void hdmi_regs_dump(struct hdmi_context *hdata, char *prefix)
static int hdmi_clk_set_parents(struct hdmi_context *hdata, bool to_phy)
{
if (hdata->drv_data->type == HDMI_TYPE13)
hdmi_v13_regs_dump(hdata, prefix);
else
hdmi_v14_regs_dump(hdata, prefix);
struct device *dev = hdata->dev;
int ret = 0;
int i;
for (i = 0; i < hdata->drv_data->clk_muxes.count; i += 3) {
struct clk **c = &hdata->clk_muxes[i];
ret = clk_set_parent(c[2], c[to_phy]);
if (!ret)
continue;
dev_err(dev, "Cannot set clock parent of '%s' to '%s', %d\n",
hdata->drv_data->clk_muxes.data[i + 2],
hdata->drv_data->clk_muxes.data[i + to_phy], ret);
}
return ret;
}
static u8 hdmi_chksum(struct hdmi_context *hdata,
......@@ -993,10 +907,11 @@ static int hdmi_get_modes(struct drm_connector *connector)
static int hdmi_find_phy_conf(struct hdmi_context *hdata, u32 pixel_clock)
{
const struct hdmiphy_configs *confs = &hdata->drv_data->phy_confs;
int i;
for (i = 0; i < hdata->drv_data->phy_conf_count; i++)
if (hdata->drv_data->phy_confs[i].pixel_clock == pixel_clock)
for (i = 0; i < confs->count; i++)
if (confs->data[i].pixel_clock == pixel_clock)
return i;
DRM_DEBUG_KMS("Could not find phy config for %d\n", pixel_clock);
......@@ -1078,13 +993,11 @@ static bool hdmi_mode_fixup(struct drm_encoder *encoder,
mode_ok = hdmi_mode_valid(connector, adjusted_mode);
/* just return if user desired mode exists. */
if (mode_ok == MODE_OK)
return true;
/*
* otherwise, find the most suitable mode among modes and change it
* to adjusted_mode.
* Find the most suitable mode and copy it to adjusted_mode.
*/
list_for_each_entry(m, &connector->modes, head) {
mode_ok = hdmi_mode_valid(connector, m);
......@@ -1230,13 +1143,12 @@ static void hdmi_conf_init(struct hdmi_context *hdata)
/* choose HDMI mode */
hdmi_reg_writemask(hdata, HDMI_MODE_SEL,
HDMI_MODE_HDMI_EN, HDMI_MODE_MASK);
/* Apply Video preable and Guard band in HDMI mode only */
/* apply video pre-amble and guard band in HDMI mode only */
hdmi_reg_writeb(hdata, HDMI_CON_2, 0);
/* disable bluescreen */
hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_BLUE_SCR_EN);
if (hdata->dvi_mode) {
/* choose DVI mode */
hdmi_reg_writemask(hdata, HDMI_MODE_SEL,
HDMI_MODE_DVI_EN, HDMI_MODE_MASK);
hdmi_reg_writeb(hdata, HDMI_CON_2,
......@@ -1319,7 +1231,6 @@ static void hdmi_v13_mode_apply(struct hdmi_context *hdata)
/* Following values & calculations differ for different type of modes */
if (m->flags & DRM_MODE_FLAG_INTERLACE) {
/* Interlaced Mode */
val = ((m->vsync_end - m->vdisplay) / 2);
val |= ((m->vsync_start - m->vdisplay) / 2) << 12;
hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_1_0, 3, val);
......@@ -1348,8 +1259,6 @@ static void hdmi_v13_mode_apply(struct hdmi_context *hdata)
hdmi_reg_writev(hdata, HDMI_TG_VACT_ST2_L, 2, 0x249);
} else {
/* Progressive Mode */
val = m->vtotal;
val |= (m->vtotal - m->vdisplay) << 11;
hdmi_reg_writev(hdata, HDMI_V13_V_BLANK_0, 3, val);
......@@ -1365,21 +1274,12 @@ static void hdmi_v13_mode_apply(struct hdmi_context *hdata)
hdmi_reg_writev(hdata, HDMI_TG_VACT_ST_L, 2,
m->vtotal - m->vdisplay);
hdmi_reg_writev(hdata, HDMI_TG_VACT_SZ_L, 2, m->vdisplay);
hdmi_reg_writev(hdata, HDMI_TG_VACT_ST2_L, 2, 0x248);
}
/* Timing generator registers */
hdmi_reg_writev(hdata, HDMI_TG_H_FSZ_L, 2, m->htotal);
hdmi_reg_writev(hdata, HDMI_TG_HACT_ST_L, 2, m->htotal - m->hdisplay);
hdmi_reg_writev(hdata, HDMI_TG_HACT_SZ_L, 2, m->hdisplay);
hdmi_reg_writev(hdata, HDMI_TG_V_FSZ_L, 2, m->vtotal);
hdmi_reg_writev(hdata, HDMI_TG_VSYNC_L, 2, 0x1);
hdmi_reg_writev(hdata, HDMI_TG_VSYNC2_L, 2, 0x233);
hdmi_reg_writev(hdata, HDMI_TG_FIELD_CHG_L, 2, 0x233);
hdmi_reg_writev(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, 2, 0x1);
hdmi_reg_writev(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, 2, 0x233);
hdmi_reg_writev(hdata, HDMI_TG_FIELD_TOP_HDMI_L, 2, 0x1);
hdmi_reg_writev(hdata, HDMI_TG_FIELD_BOT_HDMI_L, 2, 0x233);
}
static void hdmi_v14_mode_apply(struct hdmi_context *hdata)
......@@ -1404,7 +1304,6 @@ static void hdmi_v14_mode_apply(struct hdmi_context *hdata)
/* Following values & calculations differ for different type of modes */
if (m->flags & DRM_MODE_FLAG_INTERLACE) {
/* Interlaced Mode */
hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_2_0, 2,
(m->vsync_end - m->vdisplay) / 2);
hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_1_0, 2,
......@@ -1437,7 +1336,6 @@ static void hdmi_v14_mode_apply(struct hdmi_context *hdata)
hdmi_reg_writev(hdata, HDMI_TG_VACT_ST3_L, 2, 0x0);
hdmi_reg_writev(hdata, HDMI_TG_VACT_ST4_L, 2, 0x0);
} else {
/* Progressive Mode */
hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_2_0, 2,
m->vsync_end - m->vdisplay);
hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_1_0, 2,
......@@ -1454,15 +1352,8 @@ static void hdmi_v14_mode_apply(struct hdmi_context *hdata)
hdmi_reg_writev(hdata, HDMI_TG_VACT_ST_L, 2,
m->vtotal - m->vdisplay);
hdmi_reg_writev(hdata, HDMI_TG_VACT_SZ_L, 2, m->vdisplay);
hdmi_reg_writev(hdata, HDMI_TG_VACT_ST2_L, 2, 0x248);
hdmi_reg_writev(hdata, HDMI_TG_VACT_ST3_L, 2, 0x47b);
hdmi_reg_writev(hdata, HDMI_TG_VACT_ST4_L, 2, 0x6ae);
hdmi_reg_writev(hdata, HDMI_TG_VSYNC2_L, 2, 0x233);
hdmi_reg_writev(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, 2, 0x233);
hdmi_reg_writev(hdata, HDMI_TG_FIELD_BOT_HDMI_L, 2, 0x233);
}
/* Following values & calculations are same irrespective of mode type */
hdmi_reg_writev(hdata, HDMI_H_SYNC_START_0, 2,
m->hsync_start - m->hdisplay - 2);
hdmi_reg_writev(hdata, HDMI_H_SYNC_END_0, 2,
......@@ -1486,16 +1377,12 @@ static void hdmi_v14_mode_apply(struct hdmi_context *hdata)
hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_5_0, 2, 0xffff);
hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_6_0, 2, 0xffff);
/* Timing generator registers */
hdmi_reg_writev(hdata, HDMI_TG_H_FSZ_L, 2, m->htotal);
hdmi_reg_writev(hdata, HDMI_TG_HACT_ST_L, 2, m->htotal - m->hdisplay);
hdmi_reg_writev(hdata, HDMI_TG_HACT_SZ_L, 2, m->hdisplay);
hdmi_reg_writev(hdata, HDMI_TG_V_FSZ_L, 2, m->vtotal);
hdmi_reg_writev(hdata, HDMI_TG_VSYNC_L, 2, 0x1);
hdmi_reg_writev(hdata, HDMI_TG_FIELD_CHG_L, 2, 0x233);
hdmi_reg_writev(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, 2, 0x1);
hdmi_reg_writev(hdata, HDMI_TG_FIELD_TOP_HDMI_L, 2, 0x1);
hdmi_reg_writev(hdata, HDMI_TG_3D, 1, 0x0);
if (hdata->drv_data == &exynos5433_hdmi_driver_data)
hdmi_reg_writeb(hdata, HDMI_TG_DECON_EN, 1);
}
static void hdmi_mode_apply(struct hdmi_context *hdata)
......@@ -1505,62 +1392,65 @@ static void hdmi_mode_apply(struct hdmi_context *hdata)
else
hdmi_v14_mode_apply(hdata);
hdmiphy_wait_for_pll(hdata);
clk_set_parent(hdata->mout_hdmi, hdata->sclk_hdmiphy);
/* enable HDMI and timing generator */
hdmi_start(hdata, true);
}
static void hdmiphy_conf_reset(struct hdmi_context *hdata)
{
clk_set_parent(hdata->mout_hdmi, hdata->sclk_pixel);
/* reset hdmiphy */
hdmi_reg_writemask(hdata, HDMI_CORE_RSTOUT, 0, 1);
usleep_range(10000, 12000);
hdmi_reg_writemask(hdata, HDMI_CORE_RSTOUT, ~0, 1);
usleep_range(10000, 12000);
hdmi_reg_writemask(hdata, HDMI_PHY_RSTOUT, ~0, HDMI_PHY_SW_RSTOUT);
usleep_range(10000, 12000);
hdmi_reg_writemask(hdata, HDMI_PHY_RSTOUT, 0, HDMI_PHY_SW_RSTOUT);
usleep_range(10000, 12000);
}
static void hdmiphy_enable_mode_set(struct hdmi_context *hdata, bool enable)
{
u8 v = enable ? HDMI_PHY_ENABLE_MODE_SET : HDMI_PHY_DISABLE_MODE_SET;
if (hdata->drv_data == &exynos5433_hdmi_driver_data)
writel(v, hdata->regs_hdmiphy + HDMIPHY5433_MODE_SET_DONE);
}
static void hdmiphy_conf_apply(struct hdmi_context *hdata)
{
int ret;
int i;
const u8 *phy_conf;
/* pixel clock */
i = hdmi_find_phy_conf(hdata, hdata->current_mode.clock * 1000);
if (i < 0) {
ret = hdmi_find_phy_conf(hdata, hdata->current_mode.clock * 1000);
if (ret < 0) {
DRM_ERROR("failed to find hdmiphy conf\n");
return;
}
phy_conf = hdata->drv_data->phy_confs.data[ret].conf;
ret = hdmiphy_reg_write_buf(hdata, 0,
hdata->drv_data->phy_confs[i].conf, 32);
hdmi_clk_set_parents(hdata, false);
hdmiphy_conf_reset(hdata);
hdmiphy_enable_mode_set(hdata, true);
ret = hdmiphy_reg_write_buf(hdata, 0, phy_conf, 32);
if (ret) {
DRM_ERROR("failed to configure hdmiphy\n");
return;
}
hdmiphy_enable_mode_set(hdata, false);
hdmi_clk_set_parents(hdata, true);
usleep_range(10000, 12000);
hdmiphy_wait_for_pll(hdata);
}
static void hdmi_conf_apply(struct hdmi_context *hdata)
{
hdmiphy_conf_reset(hdata);
hdmiphy_conf_apply(hdata);
hdmi_start(hdata, false);
hdmi_conf_init(hdata);
hdmi_audio_init(hdata);
/* setting core registers */
hdmi_mode_apply(hdata);
hdmi_audio_control(hdata, true);
hdmi_regs_dump(hdata, "start");
}
static void hdmi_mode_set(struct drm_encoder *encoder,
......@@ -1579,6 +1469,15 @@ static void hdmi_mode_set(struct drm_encoder *encoder,
hdata->cea_video_id = drm_match_cea_mode(mode);
}
static void hdmi_set_refclk(struct hdmi_context *hdata, bool on)
{
if (!hdata->sysreg)
return;
regmap_update_bits(hdata->sysreg, EXYNOS5433_SYSREG_DISP_HDMI_PHY,
SYSREG_HDMI_REFCLK_INT_CLK, on ? ~0 : 0);
}
static void hdmi_enable(struct drm_encoder *encoder)
{
struct hdmi_context *hdata = encoder_to_hdmi(encoder);
......@@ -1591,10 +1490,13 @@ static void hdmi_enable(struct drm_encoder *encoder)
if (regulator_bulk_enable(ARRAY_SIZE(supply), hdata->regul_bulk))
DRM_DEBUG_KMS("failed to enable regulator bulk\n");
/* set pmu hdmiphy control bit to enable hdmiphy */
regmap_update_bits(hdata->pmureg, PMU_HDMI_PHY_CONTROL,
PMU_HDMI_PHY_ENABLE_BIT, 1);
hdmi_set_refclk(hdata, true);
hdmi_reg_writemask(hdata, HDMI_PHY_CON_0, 0, HDMI_PHY_POWER_OFF_EN);
hdmi_conf_apply(hdata);
hdata->powered = true;
......@@ -1623,12 +1525,14 @@ static void hdmi_disable(struct drm_encoder *encoder)
if (funcs && funcs->disable)
(*funcs->disable)(crtc);
/* HDMI System Disable */
hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_EN);
cancel_delayed_work(&hdata->hotplug_work);
/* reset pmu hdmiphy control bit to disable hdmiphy */
hdmi_reg_writemask(hdata, HDMI_PHY_CON_0, ~0, HDMI_PHY_POWER_OFF_EN);
hdmi_set_refclk(hdata, false);
regmap_update_bits(hdata->pmureg, PMU_HDMI_PHY_CONTROL,
PMU_HDMI_PHY_ENABLE_BIT, 0);
......@@ -1670,6 +1574,57 @@ static irqreturn_t hdmi_irq_thread(int irq, void *arg)
return IRQ_HANDLED;
}
static int hdmi_clks_get(struct hdmi_context *hdata,
const struct string_array_spec *names,
struct clk **clks)
{
struct device *dev = hdata->dev;
int i;
for (i = 0; i < names->count; ++i) {
struct clk *clk = devm_clk_get(dev, names->data[i]);
if (IS_ERR(clk)) {
int ret = PTR_ERR(clk);
dev_err(dev, "Cannot get clock %s, %d\n",
names->data[i], ret);
return ret;
}
clks[i] = clk;
}
return 0;
}
static int hdmi_clk_init(struct hdmi_context *hdata)
{
const struct hdmi_driver_data *drv_data = hdata->drv_data;
int count = drv_data->clk_gates.count + drv_data->clk_muxes.count;
struct device *dev = hdata->dev;
struct clk **clks;
int ret;
if (!count)
return 0;
clks = devm_kzalloc(dev, sizeof(*clks) * count, GFP_KERNEL);
if (!clks)
return -ENOMEM;
hdata->clk_gates = clks;
hdata->clk_muxes = clks + drv_data->clk_gates.count;
ret = hdmi_clks_get(hdata, &drv_data->clk_gates, hdata->clk_gates);
if (ret)
return ret;
return hdmi_clks_get(hdata, &drv_data->clk_muxes, hdata->clk_muxes);
}
static int hdmi_resources_init(struct hdmi_context *hdata)
{
struct device *dev = hdata->dev;
......@@ -1688,39 +1643,14 @@ static int hdmi_resources_init(struct hdmi_context *hdata)
DRM_ERROR("failed to get GPIO irq\n");
return hdata->irq;
}
/* get clocks, power */
hdata->hdmi = devm_clk_get(dev, "hdmi");
if (IS_ERR(hdata->hdmi)) {
DRM_ERROR("failed to get clock 'hdmi'\n");
ret = PTR_ERR(hdata->hdmi);
goto fail;
}
hdata->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi");
if (IS_ERR(hdata->sclk_hdmi)) {
DRM_ERROR("failed to get clock 'sclk_hdmi'\n");
ret = PTR_ERR(hdata->sclk_hdmi);
goto fail;
}
hdata->sclk_pixel = devm_clk_get(dev, "sclk_pixel");
if (IS_ERR(hdata->sclk_pixel)) {
DRM_ERROR("failed to get clock 'sclk_pixel'\n");
ret = PTR_ERR(hdata->sclk_pixel);
goto fail;
}
hdata->sclk_hdmiphy = devm_clk_get(dev, "sclk_hdmiphy");
if (IS_ERR(hdata->sclk_hdmiphy)) {
DRM_ERROR("failed to get clock 'sclk_hdmiphy'\n");
ret = PTR_ERR(hdata->sclk_hdmiphy);
goto fail;
}
hdata->mout_hdmi = devm_clk_get(dev, "mout_hdmi");
if (IS_ERR(hdata->mout_hdmi)) {
DRM_ERROR("failed to get clock 'mout_hdmi'\n");
ret = PTR_ERR(hdata->mout_hdmi);
goto fail;
}
clk_set_parent(hdata->mout_hdmi, hdata->sclk_pixel);
ret = hdmi_clk_init(hdata);
if (ret)
return ret;
ret = hdmi_clk_set_parents(hdata, false);
if (ret)
return ret;
for (i = 0; i < ARRAY_SIZE(supply); ++i) {
hdata->regul_bulk[i].supply = supply[i];
......@@ -1745,9 +1675,6 @@ static int hdmi_resources_init(struct hdmi_context *hdata)
DRM_ERROR("failed to enable hdmi-en regulator\n");
return ret;
fail:
DRM_ERROR("HDMI resource init - failed\n");
return ret;
}
static struct of_device_id hdmi_match_types[] = {
......@@ -1760,6 +1687,9 @@ static struct of_device_id hdmi_match_types[] = {
}, {
.compatible = "samsung,exynos5420-hdmi",
.data = &exynos5420_hdmi_driver_data,
}, {
.compatible = "samsung,exynos5433-hdmi",
.data = &exynos5433_hdmi_driver_data,
}, {
/* end node */
}
......@@ -1830,7 +1760,6 @@ static struct device_node *hdmi_legacy_phy_dt_binding(struct device *dev)
static int hdmi_probe(struct platform_device *pdev)
{
struct device_node *ddc_node, *phy_node;
const struct of_device_id *match;
struct device *dev = &pdev->dev;
struct hdmi_context *hdata;
struct resource *res;
......@@ -1840,11 +1769,7 @@ static int hdmi_probe(struct platform_device *pdev)
if (!hdata)
return -ENOMEM;
match = of_match_device(hdmi_match_types, dev);
if (!match)
return -ENODEV;
hdata->drv_data = match->data;
hdata->drv_data = of_device_get_match_data(dev);
platform_set_drvdata(pdev, hdata);
......@@ -1867,7 +1792,6 @@ static int hdmi_probe(struct platform_device *pdev)
if (ddc_node)
goto out_get_ddc_adpt;
/* DDC i2c driver */
ddc_node = of_parse_phandle(dev->of_node, "ddc", 0);
if (!ddc_node) {
DRM_ERROR("Failed to find ddc node in device tree\n");
......@@ -1885,7 +1809,6 @@ static int hdmi_probe(struct platform_device *pdev)
if (phy_node)
goto out_get_phy_port;
/* hdmiphy i2c driver */
phy_node = of_parse_phandle(dev->of_node, "phy", 0);
if (!phy_node) {
DRM_ERROR("Failed to find hdmiphy node in device tree\n");
......@@ -1929,6 +1852,16 @@ static int hdmi_probe(struct platform_device *pdev)
goto err_hdmiphy;
}
if (hdata->drv_data->has_sysreg) {
hdata->sysreg = syscon_regmap_lookup_by_phandle(dev->of_node,
"samsung,sysreg-phandle");
if (IS_ERR(hdata->sysreg)) {
DRM_ERROR("sysreg regmap lookup failed.\n");
ret = -EPROBE_DEFER;
goto err_hdmiphy;
}
}
pm_runtime_enable(dev);
ret = component_add(&pdev->dev, &hdmi_component_ops);
......@@ -1975,8 +1908,7 @@ static int exynos_hdmi_suspend(struct device *dev)
{
struct hdmi_context *hdata = dev_get_drvdata(dev);
clk_disable_unprepare(hdata->sclk_hdmi);
clk_disable_unprepare(hdata->hdmi);
hdmi_clk_disable_gates(hdata);
return 0;
}
......@@ -1986,17 +1918,9 @@ static int exynos_hdmi_resume(struct device *dev)
struct hdmi_context *hdata = dev_get_drvdata(dev);
int ret;
ret = clk_prepare_enable(hdata->hdmi);
if (ret < 0) {
DRM_ERROR("Failed to prepare_enable the hdmi clk [%d]\n", ret);
return ret;
}
ret = clk_prepare_enable(hdata->sclk_hdmi);
if (ret < 0) {
DRM_ERROR("Failed to prepare_enable the sclk_mixer clk [%d]\n",
ret);
ret = hdmi_clk_enable_gates(hdata);
if (ret < 0)
return ret;
}
return 0;
}
......
......@@ -31,6 +31,7 @@
#include <linux/clk.h>
#include <linux/regulator/consumer.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/component.h>
#include <drm/exynos_drm.h>
......@@ -103,8 +104,6 @@ struct mixer_context {
struct mixer_resources mixer_res;
enum mixer_version_id mxr_ver;
wait_queue_head_t wait_vsync_queue;
atomic_t wait_vsync_event;
};
struct mixer_drv_data {
......@@ -787,12 +786,6 @@ static irqreturn_t mixer_irq_handler(int irq, void *arg)
exynos_drm_crtc_finish_update(ctx->crtc, plane);
}
/* set wait vsync event to zero and wake up queue. */
if (atomic_read(&ctx->wait_vsync_event)) {
atomic_set(&ctx->wait_vsync_event, 0);
wake_up(&ctx->wait_vsync_queue);
}
}
out:
......@@ -1027,34 +1020,6 @@ static void mixer_atomic_flush(struct exynos_drm_crtc *crtc)
mixer_vsync_set_update(mixer_ctx, true);
}
static void mixer_wait_for_vblank(struct exynos_drm_crtc *crtc)
{
struct mixer_context *mixer_ctx = crtc->ctx;
int err;
if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags))
return;
err = drm_vblank_get(mixer_ctx->drm_dev, mixer_ctx->pipe);
if (err < 0) {
DRM_DEBUG_KMS("failed to acquire vblank counter\n");
return;
}
atomic_set(&mixer_ctx->wait_vsync_event, 1);
/*
* wait for MIXER to signal VSYNC interrupt or return after
* timeout which is set to 50ms (refresh rate of 20).
*/
if (!wait_event_timeout(mixer_ctx->wait_vsync_queue,
!atomic_read(&mixer_ctx->wait_vsync_event),
HZ/20))
DRM_DEBUG_KMS("vblank wait timed out.\n");
drm_vblank_put(mixer_ctx->drm_dev, mixer_ctx->pipe);
}
static void mixer_enable(struct exynos_drm_crtc *crtc)
{
struct mixer_context *ctx = crtc->ctx;
......@@ -1065,6 +1030,8 @@ static void mixer_enable(struct exynos_drm_crtc *crtc)
pm_runtime_get_sync(ctx->dev);
exynos_drm_pipe_clk_enable(crtc, true);
mixer_vsync_set_update(ctx, false);
mixer_reg_writemask(res, MXR_STATUS, ~0, MXR_STATUS_SOFT_RESET);
......@@ -1094,6 +1061,8 @@ static void mixer_disable(struct exynos_drm_crtc *crtc)
for (i = 0; i < MIXER_WIN_NR; i++)
mixer_disable_plane(crtc, &ctx->planes[i]);
exynos_drm_pipe_clk_enable(crtc, false);
pm_runtime_put(ctx->dev);
clear_bit(MXR_BIT_POWERED, &ctx->flags);
......@@ -1126,7 +1095,6 @@ static const struct exynos_drm_crtc_ops mixer_crtc_ops = {
.disable = mixer_disable,
.enable_vblank = mixer_enable_vblank,
.disable_vblank = mixer_disable_vblank,
.wait_for_vblank = mixer_wait_for_vblank,
.atomic_begin = mixer_atomic_begin,
.update_plane = mixer_update_plane,
.disable_plane = mixer_disable_plane,
......@@ -1155,18 +1123,6 @@ static struct mixer_drv_data exynos4210_mxr_drv_data = {
.has_sclk = 1,
};
static const struct platform_device_id mixer_driver_types[] = {
{
.name = "s5p-mixer",
.driver_data = (unsigned long)&exynos4210_mxr_drv_data,
}, {
.name = "exynos5-mixer",
.driver_data = (unsigned long)&exynos5250_mxr_drv_data,
}, {
/* end node */
}
};
static struct of_device_id mixer_match_types[] = {
{
.compatible = "samsung,exynos4210-mixer",
......@@ -1243,7 +1199,7 @@ static const struct component_ops mixer_component_ops = {
static int mixer_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct mixer_drv_data *drv;
const struct mixer_drv_data *drv;
struct mixer_context *ctx;
int ret;
......@@ -1253,23 +1209,13 @@ static int mixer_probe(struct platform_device *pdev)
return -ENOMEM;
}
if (dev->of_node) {
const struct of_device_id *match;
match = of_match_node(mixer_match_types, dev->of_node);
drv = (struct mixer_drv_data *)match->data;
} else {
drv = (struct mixer_drv_data *)
platform_get_device_id(pdev)->driver_data;
}
drv = of_device_get_match_data(dev);
ctx->pdev = pdev;
ctx->dev = dev;
ctx->vp_enabled = drv->is_vp_enabled;
ctx->has_sclk = drv->has_sclk;
ctx->mxr_ver = drv->version;
init_waitqueue_head(&ctx->wait_vsync_queue);
atomic_set(&ctx->wait_vsync_event, 0);
platform_set_drvdata(pdev, ctx);
......@@ -1355,5 +1301,4 @@ struct platform_driver mixer_driver = {
},
.probe = mixer_probe,
.remove = mixer_remove,
.id_table = mixer_driver_types,
};
......@@ -586,10 +586,12 @@
#define HDMI_TG_VACT_ST4_L HDMI_TG_BASE(0x0070)
#define HDMI_TG_VACT_ST4_H HDMI_TG_BASE(0x0074)
#define HDMI_TG_3D HDMI_TG_BASE(0x00F0)
#define HDMI_TG_DECON_EN HDMI_TG_BASE(0x01e0)
/* HDMI PHY Registers Offsets*/
#define HDMIPHY_POWER (0x74 >> 2)
#define HDMIPHY_MODE_SET_DONE (0x7c >> 2)
#define HDMIPHY_POWER 0x74
#define HDMIPHY_MODE_SET_DONE 0x7c
#define HDMIPHY5433_MODE_SET_DONE 0x84
/* HDMI PHY Values */
#define HDMI_PHY_POWER_ON 0x80
......@@ -603,4 +605,7 @@
#define PMU_HDMI_PHY_CONTROL 0x700
#define PMU_HDMI_PHY_ENABLE_BIT BIT(0)
#define EXYNOS5433_SYSREG_DISP_HDMI_PHY 0x1008
#define SYSREG_HDMI_REFCLK_INT_CLK 1
#endif /* SAMSUNG_REGS_HDMI_H */
......@@ -179,9 +179,9 @@
#define TRIGCON_TRIGMODE_W1BUF (1 << 10)
#define TRIGCON_SWTRIGCMD_W0BUF (1 << 6)
#define TRIGCON_TRIGMODE_W0BUF (1 << 5)
#define TRIGCON_HWTRIGMASK_I80_RGB (1 << 4)
#define TRIGCON_HWTRIGEN_I80_RGB (1 << 3)
#define TRIGCON_HWTRIG_INV_I80_RGB (1 << 2)
#define TRIGCON_HWTRIGMASK (1 << 4)
#define TRIGCON_HWTRIGEN (1 << 3)
#define TRIGCON_HWTRIG_INV (1 << 2)
#define TRIGCON_SWTRIGCMD (1 << 1)
#define TRIGCON_SWTRIGEN (1 << 0)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment