Merge branch 'exynos-drm-next' of git://git.kernel.org/pub/scm/linux/kernel/git/daeinki/drm-exynos into drm-next
This pull request includes comprehensive cleanups to HDMI part and several fixups. In addition, this pull request includes also a defconfig patch which enables mixer driver as default. For this, I got already Acked-by from Krzysztof Kozlowski who is a Exynos SoC maintainer. * 'exynos-drm-next' of git://git.kernel.org/pub/scm/linux/kernel/git/daeinki/drm-exynos: (34 commits) drm/exynos/gem: remove DMA-mapping hacks used for constructing page array ARM: exynos_defconfig: enable Exynos DRM Mixer driver drm/exynos: simplify Kconfig component names drm/exynos: re-arrange Kconfig entries drm/exynos: abstract out common dependency drm/exynos: separate Mixer and HDMI drivers drm/exynos/mixer: replace direct cross-driver call with drm mode validation drm/exynos: add atomic_check callback to exynos_crtc drm/exynos/decon5433: add support for DECON-TV drm/exynos/decon5433: remove duplicated initialization drm/exynos/decon5433: merge different flag fields drm/exynos/decon5433: add function to set particular register bits drm/exynos/decon5433: fix timing registers writes drm/exynos/decon5433: add PCLK clock drm/exynos: cleanup name of gem object for exynos_drm drm/exynos: fix to detach device of iommu drm/exynos: add cursor plane support drm/exynos: add global macro for the default primary plane drm/exynos: fix spelling errors drm: exynos: mixer: fix using usleep() in atomic context ...
This commit is contained in:
Коммит
b459004796
|
@ -132,6 +132,7 @@ CONFIG_DRM_PARADE_PS8622=y
|
|||
CONFIG_DRM_EXYNOS=y
|
||||
CONFIG_DRM_EXYNOS_FIMD=y
|
||||
CONFIG_DRM_EXYNOS_DSI=y
|
||||
CONFIG_DRM_EXYNOS_MIXER=y
|
||||
CONFIG_DRM_EXYNOS_HDMI=y
|
||||
CONFIG_DRM_PANEL_SIMPLE=y
|
||||
CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0=y
|
||||
|
|
|
@ -11,43 +11,59 @@ config DRM_EXYNOS
|
|||
Choose this option if you have a Samsung SoC EXYNOS chipset.
|
||||
If M is selected the module will be called exynosdrm.
|
||||
|
||||
if DRM_EXYNOS
|
||||
|
||||
config DRM_EXYNOS_IOMMU
|
||||
bool
|
||||
depends on DRM_EXYNOS && EXYNOS_IOMMU && ARM_DMA_USE_IOMMU
|
||||
depends on EXYNOS_IOMMU && ARM_DMA_USE_IOMMU
|
||||
default y
|
||||
|
||||
comment "CRTCs"
|
||||
|
||||
config DRM_EXYNOS_FIMD
|
||||
bool "Exynos DRM FIMD"
|
||||
depends on DRM_EXYNOS && !FB_S3C
|
||||
bool "FIMD"
|
||||
depends on !FB_S3C
|
||||
select FB_MODE_HELPERS
|
||||
select MFD_SYSCON
|
||||
help
|
||||
Choose this option if you want to use Exynos FIMD for DRM.
|
||||
|
||||
config DRM_EXYNOS5433_DECON
|
||||
bool "Exynos5433 DRM DECON"
|
||||
depends on DRM_EXYNOS
|
||||
bool "DECON on Exynos5433"
|
||||
help
|
||||
Choose this option if you want to use Exynos5433 DECON for DRM.
|
||||
|
||||
config DRM_EXYNOS7_DECON
|
||||
bool "Exynos7 DRM DECON"
|
||||
depends on DRM_EXYNOS && !FB_S3C
|
||||
bool "DECON on Exynos7"
|
||||
depends on !FB_S3C
|
||||
select FB_MODE_HELPERS
|
||||
help
|
||||
Choose this option if you want to use Exynos DECON for DRM.
|
||||
|
||||
config DRM_EXYNOS_MIXER
|
||||
bool "Mixer"
|
||||
depends on !VIDEO_SAMSUNG_S5P_TV
|
||||
help
|
||||
Choose this option if you want to use Exynos Mixer for DRM.
|
||||
|
||||
config DRM_EXYNOS_VIDI
|
||||
bool "Virtual Display"
|
||||
help
|
||||
Choose this option if you want to use Exynos VIDI for DRM.
|
||||
|
||||
comment "Encoders and Bridges"
|
||||
|
||||
config DRM_EXYNOS_DPI
|
||||
bool "EXYNOS DRM parallel output support"
|
||||
depends on DRM_EXYNOS && (DRM_EXYNOS_FIMD || DRM_EXYNOS7_DECON)
|
||||
bool "Parallel output"
|
||||
depends on DRM_EXYNOS_FIMD
|
||||
select DRM_PANEL
|
||||
default n
|
||||
help
|
||||
This enables support for Exynos parallel output.
|
||||
|
||||
config DRM_EXYNOS_DSI
|
||||
bool "EXYNOS DRM MIPI-DSI driver support"
|
||||
depends on DRM_EXYNOS && (DRM_EXYNOS_FIMD || DRM_EXYNOS5433_DECON || DRM_EXYNOS7_DECON)
|
||||
bool "MIPI-DSI host"
|
||||
depends on DRM_EXYNOS_FIMD || DRM_EXYNOS5433_DECON || DRM_EXYNOS7_DECON
|
||||
select DRM_MIPI_DSI
|
||||
select DRM_PANEL
|
||||
default n
|
||||
|
@ -55,58 +71,55 @@ config DRM_EXYNOS_DSI
|
|||
This enables support for Exynos MIPI-DSI device.
|
||||
|
||||
config DRM_EXYNOS_DP
|
||||
bool "EXYNOS DRM DP driver support"
|
||||
depends on DRM_EXYNOS && (DRM_EXYNOS_FIMD || DRM_EXYNOS7_DECON)
|
||||
bool "Display Port"
|
||||
depends on DRM_EXYNOS_FIMD || DRM_EXYNOS7_DECON
|
||||
default DRM_EXYNOS
|
||||
select DRM_PANEL
|
||||
help
|
||||
This enables support for DP device.
|
||||
|
||||
config DRM_EXYNOS_HDMI
|
||||
bool "Exynos DRM HDMI"
|
||||
depends on DRM_EXYNOS && !VIDEO_SAMSUNG_S5P_TV
|
||||
bool "HDMI"
|
||||
depends on !VIDEO_SAMSUNG_S5P_TV && (DRM_EXYNOS_MIXER || DRM_EXYNOS5433_DECON)
|
||||
help
|
||||
Choose this option if you want to use Exynos HDMI for DRM.
|
||||
|
||||
config DRM_EXYNOS_VIDI
|
||||
bool "Exynos DRM Virtual Display"
|
||||
depends on DRM_EXYNOS
|
||||
config DRM_EXYNOS_MIC
|
||||
bool "Mobile Image Compressor"
|
||||
depends on DRM_EXYNOS5433_DECON
|
||||
help
|
||||
Choose this option if you want to use Exynos VIDI for DRM.
|
||||
Choose this option if you want to use Exynos MIC for DRM.
|
||||
|
||||
comment "Sub-drivers"
|
||||
|
||||
config DRM_EXYNOS_G2D
|
||||
bool "Exynos DRM G2D"
|
||||
depends on DRM_EXYNOS && !VIDEO_SAMSUNG_S5P_G2D
|
||||
bool "G2D"
|
||||
depends on !VIDEO_SAMSUNG_S5P_G2D
|
||||
select FRAME_VECTOR
|
||||
help
|
||||
Choose this option if you want to use Exynos G2D for DRM.
|
||||
|
||||
config DRM_EXYNOS_IPP
|
||||
bool "Exynos DRM IPP"
|
||||
depends on DRM_EXYNOS
|
||||
bool "Image Post Processor"
|
||||
help
|
||||
Choose this option if you want to use IPP feature for DRM.
|
||||
|
||||
config DRM_EXYNOS_FIMC
|
||||
bool "Exynos DRM FIMC"
|
||||
bool "FIMC"
|
||||
depends on DRM_EXYNOS_IPP && MFD_SYSCON
|
||||
help
|
||||
Choose this option if you want to use Exynos FIMC for DRM.
|
||||
|
||||
config DRM_EXYNOS_ROTATOR
|
||||
bool "Exynos DRM Rotator"
|
||||
bool "Rotator"
|
||||
depends on DRM_EXYNOS_IPP
|
||||
help
|
||||
Choose this option if you want to use Exynos Rotator for DRM.
|
||||
|
||||
config DRM_EXYNOS_GSC
|
||||
bool "Exynos DRM GSC"
|
||||
bool "GScaler"
|
||||
depends on DRM_EXYNOS_IPP && ARCH_EXYNOS5 && !ARCH_MULTIPLATFORM
|
||||
help
|
||||
Choose this option if you want to use Exynos GSC for DRM.
|
||||
|
||||
config DRM_EXYNOS_MIC
|
||||
bool "Exynos DRM MIC"
|
||||
depends on (DRM_EXYNOS && DRM_EXYNOS5433_DECON)
|
||||
help
|
||||
Choose this option if you want to use Exynos MIC for DRM.
|
||||
endif
|
||||
|
|
|
@ -14,7 +14,8 @@ exynosdrm-$(CONFIG_DRM_EXYNOS7_DECON) += exynos7_drm_decon.o
|
|||
exynosdrm-$(CONFIG_DRM_EXYNOS_DPI) += exynos_drm_dpi.o
|
||||
exynosdrm-$(CONFIG_DRM_EXYNOS_DSI) += exynos_drm_dsi.o
|
||||
exynosdrm-$(CONFIG_DRM_EXYNOS_DP) += exynos_dp_core.o exynos_dp_reg.o
|
||||
exynosdrm-$(CONFIG_DRM_EXYNOS_HDMI) += exynos_hdmi.o exynos_mixer.o
|
||||
exynosdrm-$(CONFIG_DRM_EXYNOS_MIXER) += exynos_mixer.o
|
||||
exynosdrm-$(CONFIG_DRM_EXYNOS_HDMI) += exynos_hdmi.o
|
||||
exynosdrm-$(CONFIG_DRM_EXYNOS_VIDI) += exynos_drm_vidi.o
|
||||
exynosdrm-$(CONFIG_DRM_EXYNOS_G2D) += exynos_drm_g2d.o
|
||||
exynosdrm-$(CONFIG_DRM_EXYNOS_IPP) += exynos_drm_ipp.o
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include <linux/platform_device.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/component.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
|
@ -24,34 +25,43 @@
|
|||
#include "exynos_drm_iommu.h"
|
||||
|
||||
#define WINDOWS_NR 3
|
||||
#define CURSOR_WIN 2
|
||||
#define MIN_FB_WIDTH_FOR_16WORD_BURST 128
|
||||
|
||||
static const char * const decon_clks_name[] = {
|
||||
"pclk",
|
||||
"aclk_decon",
|
||||
"aclk_smmu_decon0x",
|
||||
"aclk_xiu_decon0x",
|
||||
"pclk_smmu_decon0x",
|
||||
"sclk_decon_vclk",
|
||||
"sclk_decon_eclk",
|
||||
};
|
||||
|
||||
enum decon_iftype {
|
||||
IFTYPE_RGB,
|
||||
IFTYPE_I80,
|
||||
IFTYPE_HDMI
|
||||
};
|
||||
|
||||
enum decon_flag_bits {
|
||||
BIT_CLKS_ENABLED,
|
||||
BIT_IRQS_ENABLED,
|
||||
BIT_WIN_UPDATED,
|
||||
BIT_SUSPENDED
|
||||
};
|
||||
|
||||
struct decon_context {
|
||||
struct device *dev;
|
||||
struct drm_device *drm_dev;
|
||||
struct exynos_drm_crtc *crtc;
|
||||
struct exynos_drm_plane planes[WINDOWS_NR];
|
||||
void __iomem *addr;
|
||||
struct clk *clks[6];
|
||||
unsigned int default_win;
|
||||
unsigned long irq_flags;
|
||||
struct clk *clks[ARRAY_SIZE(decon_clks_name)];
|
||||
int pipe;
|
||||
bool suspended;
|
||||
|
||||
#define BIT_CLKS_ENABLED 0
|
||||
#define BIT_IRQS_ENABLED 1
|
||||
unsigned long enabled;
|
||||
bool i80_if;
|
||||
atomic_t win_updated;
|
||||
};
|
||||
|
||||
static const char * const decon_clks_name[] = {
|
||||
"aclk_decon",
|
||||
"aclk_smmu_decon0x",
|
||||
"aclk_xiu_decon0x",
|
||||
"pclk_smmu_decon0x",
|
||||
"sclk_decon_vclk",
|
||||
"sclk_decon_eclk",
|
||||
unsigned long flags;
|
||||
enum decon_iftype out_type;
|
||||
int first_win;
|
||||
};
|
||||
|
||||
static const uint32_t decon_formats[] = {
|
||||
|
@ -61,17 +71,24 @@ static const uint32_t decon_formats[] = {
|
|||
DRM_FORMAT_ARGB8888,
|
||||
};
|
||||
|
||||
static inline void decon_set_bits(struct decon_context *ctx, u32 reg, u32 mask,
|
||||
u32 val)
|
||||
{
|
||||
val = (val & mask) | (readl(ctx->addr + reg) & ~mask);
|
||||
writel(val, ctx->addr + reg);
|
||||
}
|
||||
|
||||
static int decon_enable_vblank(struct exynos_drm_crtc *crtc)
|
||||
{
|
||||
struct decon_context *ctx = crtc->ctx;
|
||||
u32 val;
|
||||
|
||||
if (ctx->suspended)
|
||||
if (test_bit(BIT_SUSPENDED, &ctx->flags))
|
||||
return -EPERM;
|
||||
|
||||
if (test_and_set_bit(0, &ctx->irq_flags)) {
|
||||
if (test_and_set_bit(BIT_IRQS_ENABLED, &ctx->flags)) {
|
||||
val = VIDINTCON0_INTEN;
|
||||
if (ctx->i80_if)
|
||||
if (ctx->out_type == IFTYPE_I80)
|
||||
val |= VIDINTCON0_FRAMEDONE;
|
||||
else
|
||||
val |= VIDINTCON0_INTFRMEN;
|
||||
|
@ -86,79 +103,85 @@ static void decon_disable_vblank(struct exynos_drm_crtc *crtc)
|
|||
{
|
||||
struct decon_context *ctx = crtc->ctx;
|
||||
|
||||
if (ctx->suspended)
|
||||
if (test_bit(BIT_SUSPENDED, &ctx->flags))
|
||||
return;
|
||||
|
||||
if (test_and_clear_bit(0, &ctx->irq_flags))
|
||||
if (test_and_clear_bit(BIT_IRQS_ENABLED, &ctx->flags))
|
||||
writel(0, ctx->addr + DECON_VIDINTCON0);
|
||||
}
|
||||
|
||||
static void decon_setup_trigger(struct decon_context *ctx)
|
||||
{
|
||||
u32 val = TRIGCON_TRIGEN_PER_F | TRIGCON_TRIGEN_F |
|
||||
TRIGCON_TE_AUTO_MASK | TRIGCON_SWTRIGEN;
|
||||
u32 val = (ctx->out_type != IFTYPE_HDMI)
|
||||
? 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;
|
||||
writel(val, ctx->addr + DECON_TRIGCON);
|
||||
}
|
||||
|
||||
static void decon_commit(struct exynos_drm_crtc *crtc)
|
||||
{
|
||||
struct decon_context *ctx = crtc->ctx;
|
||||
struct drm_display_mode *mode = &crtc->base.mode;
|
||||
struct drm_display_mode *m = &crtc->base.mode;
|
||||
u32 val;
|
||||
|
||||
if (ctx->suspended)
|
||||
if (test_bit(BIT_SUSPENDED, &ctx->flags))
|
||||
return;
|
||||
|
||||
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;
|
||||
m->crtc_vsync_end = m->crtc_vsync_start + 1;
|
||||
}
|
||||
|
||||
decon_set_bits(ctx, DECON_VIDCON0, VIDCON0_ENVID, 0);
|
||||
|
||||
/* enable clock gate */
|
||||
val = CMU_CLKGAGE_MODE_SFR_F | CMU_CLKGAGE_MODE_MEM_F;
|
||||
writel(val, ctx->addr + DECON_CMU);
|
||||
|
||||
/* lcd on and use command if */
|
||||
val = VIDOUT_LCD_ON;
|
||||
if (ctx->i80_if)
|
||||
if (ctx->out_type == IFTYPE_I80)
|
||||
val |= VIDOUT_COMMAND_IF;
|
||||
else
|
||||
val |= VIDOUT_RGB_IF;
|
||||
writel(val, ctx->addr + DECON_VIDOUTCON0);
|
||||
|
||||
val = VIDTCON2_LINEVAL(mode->vdisplay - 1) |
|
||||
VIDTCON2_HOZVAL(mode->hdisplay - 1);
|
||||
val = VIDTCON2_LINEVAL(m->vdisplay - 1) |
|
||||
VIDTCON2_HOZVAL(m->hdisplay - 1);
|
||||
writel(val, ctx->addr + DECON_VIDTCON2);
|
||||
|
||||
if (!ctx->i80_if) {
|
||||
if (ctx->out_type != IFTYPE_I80) {
|
||||
val = VIDTCON00_VBPD_F(
|
||||
mode->crtc_vtotal - mode->crtc_vsync_end) |
|
||||
m->crtc_vtotal - m->crtc_vsync_end - 1) |
|
||||
VIDTCON00_VFPD_F(
|
||||
mode->crtc_vsync_start - mode->crtc_vdisplay);
|
||||
m->crtc_vsync_start - m->crtc_vdisplay - 1);
|
||||
writel(val, ctx->addr + DECON_VIDTCON00);
|
||||
|
||||
val = VIDTCON01_VSPW_F(
|
||||
mode->crtc_vsync_end - mode->crtc_vsync_start);
|
||||
m->crtc_vsync_end - m->crtc_vsync_start - 1);
|
||||
writel(val, ctx->addr + DECON_VIDTCON01);
|
||||
|
||||
val = VIDTCON10_HBPD_F(
|
||||
mode->crtc_htotal - mode->crtc_hsync_end) |
|
||||
m->crtc_htotal - m->crtc_hsync_end - 1) |
|
||||
VIDTCON10_HFPD_F(
|
||||
mode->crtc_hsync_start - mode->crtc_hdisplay);
|
||||
m->crtc_hsync_start - m->crtc_hdisplay - 1);
|
||||
writel(val, ctx->addr + DECON_VIDTCON10);
|
||||
|
||||
val = VIDTCON11_HSPW_F(
|
||||
mode->crtc_hsync_end - mode->crtc_hsync_start);
|
||||
m->crtc_hsync_end - m->crtc_hsync_start - 1);
|
||||
writel(val, ctx->addr + DECON_VIDTCON11);
|
||||
}
|
||||
|
||||
decon_setup_trigger(ctx);
|
||||
|
||||
/* enable output and display signal */
|
||||
val = VIDCON0_ENVID | VIDCON0_ENVID_F;
|
||||
writel(val, ctx->addr + DECON_VIDCON0);
|
||||
decon_set_bits(ctx, DECON_VIDCON0, VIDCON0_ENVID | VIDCON0_ENVID_F, ~0);
|
||||
}
|
||||
|
||||
#define COORDINATE_X(x) (((x) & 0xfff) << 12)
|
||||
#define COORDINATE_Y(x) ((x) & 0xfff)
|
||||
#define OFFSIZE(x) (((x) & 0x3fff) << 14)
|
||||
#define PAGEWIDTH(x) ((x) & 0x3fff)
|
||||
|
||||
static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win,
|
||||
struct drm_framebuffer *fb)
|
||||
{
|
||||
|
@ -214,16 +237,8 @@ static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win,
|
|||
static void decon_shadow_protect_win(struct decon_context *ctx, int win,
|
||||
bool protect)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = readl(ctx->addr + DECON_SHADOWCON);
|
||||
|
||||
if (protect)
|
||||
val |= SHADOWCON_Wx_PROTECT(win);
|
||||
else
|
||||
val &= ~SHADOWCON_Wx_PROTECT(win);
|
||||
|
||||
writel(val, ctx->addr + DECON_SHADOWCON);
|
||||
decon_set_bits(ctx, DECON_SHADOWCON, SHADOWCON_Wx_PROTECT(win),
|
||||
protect ? ~0 : 0);
|
||||
}
|
||||
|
||||
static void decon_atomic_begin(struct exynos_drm_crtc *crtc,
|
||||
|
@ -231,12 +246,16 @@ static void decon_atomic_begin(struct exynos_drm_crtc *crtc,
|
|||
{
|
||||
struct decon_context *ctx = crtc->ctx;
|
||||
|
||||
if (ctx->suspended)
|
||||
if (test_bit(BIT_SUSPENDED, &ctx->flags))
|
||||
return;
|
||||
|
||||
decon_shadow_protect_win(ctx, plane->zpos, true);
|
||||
}
|
||||
|
||||
#define BIT_VAL(x, e, s) (((x) & ((1 << ((e) - (s) + 1)) - 1)) << (s))
|
||||
#define COORDINATE_X(x) BIT_VAL((x), 23, 12)
|
||||
#define COORDINATE_Y(x) BIT_VAL((x), 11, 0)
|
||||
|
||||
static void decon_update_plane(struct exynos_drm_crtc *crtc,
|
||||
struct exynos_drm_plane *plane)
|
||||
{
|
||||
|
@ -247,7 +266,7 @@ static void decon_update_plane(struct exynos_drm_crtc *crtc,
|
|||
unsigned int pitch = state->fb->pitches[0];
|
||||
u32 val;
|
||||
|
||||
if (ctx->suspended)
|
||||
if (test_bit(BIT_SUSPENDED, &ctx->flags))
|
||||
return;
|
||||
|
||||
val = COORDINATE_X(plane->crtc_x) | COORDINATE_Y(plane->crtc_y);
|
||||
|
@ -270,21 +289,21 @@ static void decon_update_plane(struct exynos_drm_crtc *crtc,
|
|||
val = plane->dma_addr[0] + pitch * plane->crtc_h;
|
||||
writel(val, ctx->addr + DECON_VIDW0xADD1B0(win));
|
||||
|
||||
val = OFFSIZE(pitch - plane->crtc_w * bpp)
|
||||
| PAGEWIDTH(plane->crtc_w * bpp);
|
||||
if (ctx->out_type != IFTYPE_HDMI)
|
||||
val = BIT_VAL(pitch - plane->crtc_w * bpp, 27, 14)
|
||||
| BIT_VAL(plane->crtc_w * bpp, 13, 0);
|
||||
else
|
||||
val = BIT_VAL(pitch - plane->crtc_w * bpp, 29, 15)
|
||||
| BIT_VAL(plane->crtc_w * bpp, 14, 0);
|
||||
writel(val, ctx->addr + DECON_VIDW0xADD2(win));
|
||||
|
||||
decon_win_set_pixfmt(ctx, win, state->fb);
|
||||
|
||||
/* window enable */
|
||||
val = readl(ctx->addr + DECON_WINCONx(win));
|
||||
val |= WINCONx_ENWIN_F;
|
||||
writel(val, ctx->addr + DECON_WINCONx(win));
|
||||
decon_set_bits(ctx, DECON_WINCONx(win), WINCONx_ENWIN_F, ~0);
|
||||
|
||||
/* standalone update */
|
||||
val = readl(ctx->addr + DECON_UPDATE);
|
||||
val |= STANDALONE_UPDATE_F;
|
||||
writel(val, ctx->addr + DECON_UPDATE);
|
||||
decon_set_bits(ctx, DECON_UPDATE, STANDALONE_UPDATE_F, ~0);
|
||||
}
|
||||
|
||||
static void decon_disable_plane(struct exynos_drm_crtc *crtc,
|
||||
|
@ -292,24 +311,19 @@ static void decon_disable_plane(struct exynos_drm_crtc *crtc,
|
|||
{
|
||||
struct decon_context *ctx = crtc->ctx;
|
||||
unsigned int win = plane->zpos;
|
||||
u32 val;
|
||||
|
||||
if (ctx->suspended)
|
||||
if (test_bit(BIT_SUSPENDED, &ctx->flags))
|
||||
return;
|
||||
|
||||
decon_shadow_protect_win(ctx, win, true);
|
||||
|
||||
/* window disable */
|
||||
val = readl(ctx->addr + DECON_WINCONx(win));
|
||||
val &= ~WINCONx_ENWIN_F;
|
||||
writel(val, ctx->addr + DECON_WINCONx(win));
|
||||
decon_set_bits(ctx, DECON_WINCONx(win), WINCONx_ENWIN_F, 0);
|
||||
|
||||
decon_shadow_protect_win(ctx, win, false);
|
||||
|
||||
/* standalone update */
|
||||
val = readl(ctx->addr + DECON_UPDATE);
|
||||
val |= STANDALONE_UPDATE_F;
|
||||
writel(val, ctx->addr + DECON_UPDATE);
|
||||
decon_set_bits(ctx, DECON_UPDATE, STANDALONE_UPDATE_F, ~0);
|
||||
}
|
||||
|
||||
static void decon_atomic_flush(struct exynos_drm_crtc *crtc,
|
||||
|
@ -317,13 +331,13 @@ static void decon_atomic_flush(struct exynos_drm_crtc *crtc,
|
|||
{
|
||||
struct decon_context *ctx = crtc->ctx;
|
||||
|
||||
if (ctx->suspended)
|
||||
if (test_bit(BIT_SUSPENDED, &ctx->flags))
|
||||
return;
|
||||
|
||||
decon_shadow_protect_win(ctx, plane->zpos, false);
|
||||
|
||||
if (ctx->i80_if)
|
||||
atomic_set(&ctx->win_updated, 1);
|
||||
if (ctx->out_type == IFTYPE_I80)
|
||||
set_bit(BIT_WIN_UPDATED, &ctx->flags);
|
||||
}
|
||||
|
||||
static void decon_swreset(struct decon_context *ctx)
|
||||
|
@ -347,6 +361,17 @@ static void decon_swreset(struct decon_context *ctx)
|
|||
}
|
||||
|
||||
WARN(tries == 0, "failed to software reset DECON\n");
|
||||
|
||||
if (ctx->out_type != IFTYPE_HDMI)
|
||||
return;
|
||||
|
||||
writel(VIDCON0_CLKVALUP | VIDCON0_VLCKFREE, ctx->addr + DECON_VIDCON0);
|
||||
decon_set_bits(ctx, DECON_CMU,
|
||||
CMU_CLKGAGE_MODE_SFR_F | CMU_CLKGAGE_MODE_MEM_F, ~0);
|
||||
writel(VIDCON1_VCLK_RUN_VDEN_DISABLE, ctx->addr + DECON_VIDCON1);
|
||||
writel(CRCCTRL_CRCEN | CRCCTRL_CRCSTART_F | CRCCTRL_CRCCLKEN,
|
||||
ctx->addr + DECON_CRCCTRL);
|
||||
decon_setup_trigger(ctx);
|
||||
}
|
||||
|
||||
static void decon_enable(struct exynos_drm_crtc *crtc)
|
||||
|
@ -355,11 +380,9 @@ static void decon_enable(struct exynos_drm_crtc *crtc)
|
|||
int ret;
|
||||
int i;
|
||||
|
||||
if (!ctx->suspended)
|
||||
if (!test_and_clear_bit(BIT_SUSPENDED, &ctx->flags))
|
||||
return;
|
||||
|
||||
ctx->suspended = false;
|
||||
|
||||
pm_runtime_get_sync(ctx->dev);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(decon_clks_name); i++) {
|
||||
|
@ -368,10 +391,10 @@ static void decon_enable(struct exynos_drm_crtc *crtc)
|
|||
goto err;
|
||||
}
|
||||
|
||||
set_bit(BIT_CLKS_ENABLED, &ctx->enabled);
|
||||
set_bit(BIT_CLKS_ENABLED, &ctx->flags);
|
||||
|
||||
/* if vblank was enabled status, enable it again. */
|
||||
if (test_and_clear_bit(0, &ctx->irq_flags))
|
||||
if (test_and_clear_bit(BIT_IRQS_ENABLED, &ctx->flags))
|
||||
decon_enable_vblank(ctx->crtc);
|
||||
|
||||
decon_commit(ctx->crtc);
|
||||
|
@ -381,7 +404,7 @@ err:
|
|||
while (--i >= 0)
|
||||
clk_disable_unprepare(ctx->clks[i]);
|
||||
|
||||
ctx->suspended = true;
|
||||
set_bit(BIT_SUSPENDED, &ctx->flags);
|
||||
}
|
||||
|
||||
static void decon_disable(struct exynos_drm_crtc *crtc)
|
||||
|
@ -389,7 +412,7 @@ static void decon_disable(struct exynos_drm_crtc *crtc)
|
|||
struct decon_context *ctx = crtc->ctx;
|
||||
int i;
|
||||
|
||||
if (ctx->suspended)
|
||||
if (test_bit(BIT_SUSPENDED, &ctx->flags))
|
||||
return;
|
||||
|
||||
/*
|
||||
|
@ -397,7 +420,7 @@ static void decon_disable(struct exynos_drm_crtc *crtc)
|
|||
* suspend that connector. Otherwise we might try to scan from
|
||||
* a destroyed buffer later.
|
||||
*/
|
||||
for (i = 0; i < WINDOWS_NR; i++)
|
||||
for (i = ctx->first_win; i < WINDOWS_NR; i++)
|
||||
decon_disable_plane(crtc, &ctx->planes[i]);
|
||||
|
||||
decon_swreset(ctx);
|
||||
|
@ -405,27 +428,22 @@ static void decon_disable(struct exynos_drm_crtc *crtc)
|
|||
for (i = 0; i < ARRAY_SIZE(decon_clks_name); i++)
|
||||
clk_disable_unprepare(ctx->clks[i]);
|
||||
|
||||
clear_bit(BIT_CLKS_ENABLED, &ctx->enabled);
|
||||
clear_bit(BIT_CLKS_ENABLED, &ctx->flags);
|
||||
|
||||
pm_runtime_put_sync(ctx->dev);
|
||||
|
||||
ctx->suspended = true;
|
||||
set_bit(BIT_SUSPENDED, &ctx->flags);
|
||||
}
|
||||
|
||||
void decon_te_irq_handler(struct exynos_drm_crtc *crtc)
|
||||
{
|
||||
struct decon_context *ctx = crtc->ctx;
|
||||
u32 val;
|
||||
|
||||
if (!test_bit(BIT_CLKS_ENABLED, &ctx->enabled))
|
||||
if (!test_bit(BIT_CLKS_ENABLED, &ctx->flags))
|
||||
return;
|
||||
|
||||
if (atomic_add_unless(&ctx->win_updated, -1, 0)) {
|
||||
/* trigger */
|
||||
val = readl(ctx->addr + DECON_TRIGCON);
|
||||
val |= TRIGCON_SWTRIGCMD;
|
||||
writel(val, ctx->addr + DECON_TRIGCON);
|
||||
}
|
||||
if (test_and_clear_bit(BIT_WIN_UPDATED, &ctx->flags))
|
||||
decon_set_bits(ctx, DECON_TRIGCON, TRIGCON_SWTRIGCMD, ~0);
|
||||
|
||||
drm_crtc_handle_vblank(&ctx->crtc->base);
|
||||
}
|
||||
|
@ -434,7 +452,6 @@ static void decon_clear_channels(struct exynos_drm_crtc *crtc)
|
|||
{
|
||||
struct decon_context *ctx = crtc->ctx;
|
||||
int win, i, ret;
|
||||
u32 val;
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
|
@ -445,25 +462,10 @@ static void decon_clear_channels(struct exynos_drm_crtc *crtc)
|
|||
}
|
||||
|
||||
for (win = 0; win < WINDOWS_NR; win++) {
|
||||
/* shadow update disable */
|
||||
val = readl(ctx->addr + DECON_SHADOWCON);
|
||||
val |= SHADOWCON_Wx_PROTECT(win);
|
||||
writel(val, ctx->addr + DECON_SHADOWCON);
|
||||
|
||||
/* window disable */
|
||||
val = readl(ctx->addr + DECON_WINCONx(win));
|
||||
val &= ~WINCONx_ENWIN_F;
|
||||
writel(val, ctx->addr + DECON_WINCONx(win));
|
||||
|
||||
/* shadow update enable */
|
||||
val = readl(ctx->addr + DECON_SHADOWCON);
|
||||
val &= ~SHADOWCON_Wx_PROTECT(win);
|
||||
writel(val, ctx->addr + DECON_SHADOWCON);
|
||||
|
||||
/* standalone update */
|
||||
val = readl(ctx->addr + DECON_UPDATE);
|
||||
val |= STANDALONE_UPDATE_F;
|
||||
writel(val, ctx->addr + DECON_UPDATE);
|
||||
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);
|
||||
}
|
||||
/* TODO: wait for possible vsync */
|
||||
msleep(50);
|
||||
|
@ -479,7 +481,6 @@ static struct exynos_drm_crtc_ops decon_crtc_ops = {
|
|||
.commit = decon_commit,
|
||||
.enable_vblank = decon_enable_vblank,
|
||||
.disable_vblank = decon_disable_vblank,
|
||||
.commit = decon_commit,
|
||||
.atomic_begin = decon_atomic_begin,
|
||||
.update_plane = decon_update_plane,
|
||||
.disable_plane = decon_disable_plane,
|
||||
|
@ -493,26 +494,30 @@ static int decon_bind(struct device *dev, struct device *master, void *data)
|
|||
struct drm_device *drm_dev = data;
|
||||
struct exynos_drm_private *priv = drm_dev->dev_private;
|
||||
struct exynos_drm_plane *exynos_plane;
|
||||
enum exynos_drm_output_type out_type;
|
||||
enum drm_plane_type type;
|
||||
unsigned int zpos;
|
||||
unsigned int win;
|
||||
int ret;
|
||||
|
||||
ctx->drm_dev = drm_dev;
|
||||
ctx->pipe = priv->pipe++;
|
||||
|
||||
for (zpos = 0; zpos < WINDOWS_NR; zpos++) {
|
||||
type = (zpos == ctx->default_win) ? DRM_PLANE_TYPE_PRIMARY :
|
||||
DRM_PLANE_TYPE_OVERLAY;
|
||||
ret = exynos_plane_init(drm_dev, &ctx->planes[zpos],
|
||||
for (win = ctx->first_win; win < WINDOWS_NR; win++) {
|
||||
int tmp = (win == ctx->first_win) ? 0 : win;
|
||||
|
||||
type = exynos_plane_get_type(tmp, CURSOR_WIN);
|
||||
ret = exynos_plane_init(drm_dev, &ctx->planes[win],
|
||||
1 << ctx->pipe, type, decon_formats,
|
||||
ARRAY_SIZE(decon_formats), zpos);
|
||||
ARRAY_SIZE(decon_formats), win);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
exynos_plane = &ctx->planes[ctx->default_win];
|
||||
exynos_plane = &ctx->planes[ctx->first_win];
|
||||
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, EXYNOS_DISPLAY_TYPE_LCD,
|
||||
ctx->pipe, out_type,
|
||||
&decon_crtc_ops, ctx);
|
||||
if (IS_ERR(ctx->crtc)) {
|
||||
ret = PTR_ERR(ctx->crtc);
|
||||
|
@ -546,38 +551,20 @@ static const struct component_ops decon_component_ops = {
|
|||
.unbind = decon_unbind,
|
||||
};
|
||||
|
||||
static irqreturn_t decon_vsync_irq_handler(int irq, void *dev_id)
|
||||
{
|
||||
struct decon_context *ctx = dev_id;
|
||||
u32 val;
|
||||
|
||||
if (!test_bit(BIT_CLKS_ENABLED, &ctx->enabled))
|
||||
goto out;
|
||||
|
||||
val = readl(ctx->addr + DECON_VIDINTCON1);
|
||||
if (val & VIDINTCON1_INTFRMPEND) {
|
||||
drm_crtc_handle_vblank(&ctx->crtc->base);
|
||||
|
||||
/* clear */
|
||||
writel(VIDINTCON1_INTFRMPEND, ctx->addr + DECON_VIDINTCON1);
|
||||
}
|
||||
|
||||
out:
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t decon_lcd_sys_irq_handler(int irq, void *dev_id)
|
||||
static irqreturn_t decon_irq_handler(int irq, void *dev_id)
|
||||
{
|
||||
struct decon_context *ctx = dev_id;
|
||||
u32 val;
|
||||
int win;
|
||||
|
||||
if (!test_bit(BIT_CLKS_ENABLED, &ctx->enabled))
|
||||
if (!test_bit(BIT_CLKS_ENABLED, &ctx->flags))
|
||||
goto out;
|
||||
|
||||
val = readl(ctx->addr + DECON_VIDINTCON1);
|
||||
if (val & VIDINTCON1_INTFRMDONEPEND) {
|
||||
for (win = 0 ; win < WINDOWS_NR ; win++) {
|
||||
val &= VIDINTCON1_INTFRMDONEPEND | VIDINTCON1_INTFRMPEND;
|
||||
|
||||
if (val) {
|
||||
for (win = ctx->first_win; win < WINDOWS_NR ; win++) {
|
||||
struct exynos_drm_plane *plane = &ctx->planes[win];
|
||||
|
||||
if (!plane->pending_fb)
|
||||
|
@ -587,16 +574,29 @@ static irqreturn_t decon_lcd_sys_irq_handler(int irq, void *dev_id)
|
|||
}
|
||||
|
||||
/* clear */
|
||||
writel(VIDINTCON1_INTFRMDONEPEND,
|
||||
ctx->addr + DECON_VIDINTCON1);
|
||||
writel(val, ctx->addr + DECON_VIDINTCON1);
|
||||
}
|
||||
|
||||
out:
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static const struct of_device_id exynos5433_decon_driver_dt_match[] = {
|
||||
{
|
||||
.compatible = "samsung,exynos5433-decon",
|
||||
.data = (void *)IFTYPE_RGB
|
||||
},
|
||||
{
|
||||
.compatible = "samsung,exynos5433-decon-tv",
|
||||
.data = (void *)IFTYPE_HDMI
|
||||
},
|
||||
{},
|
||||
};
|
||||
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;
|
||||
|
@ -607,11 +607,16 @@ static int exynos5433_decon_probe(struct platform_device *pdev)
|
|||
if (!ctx)
|
||||
return -ENOMEM;
|
||||
|
||||
ctx->default_win = 0;
|
||||
ctx->suspended = true;
|
||||
__set_bit(BIT_SUSPENDED, &ctx->flags);
|
||||
ctx->dev = dev;
|
||||
if (of_get_child_by_name(dev->of_node, "i80-if-timings"))
|
||||
ctx->i80_if = true;
|
||||
|
||||
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)
|
||||
ctx->first_win = 1;
|
||||
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;
|
||||
|
@ -636,15 +641,14 @@ static int exynos5433_decon_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
|
||||
ctx->i80_if ? "lcd_sys" : "vsync");
|
||||
(ctx->out_type == IFTYPE_I80) ? "lcd_sys" : "vsync");
|
||||
if (!res) {
|
||||
dev_err(dev, "cannot find IRQ resource\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
ret = devm_request_irq(dev, res->start, ctx->i80_if ?
|
||||
decon_lcd_sys_irq_handler : decon_vsync_irq_handler, 0,
|
||||
"drm_decon", ctx);
|
||||
ret = devm_request_irq(dev, res->start, decon_irq_handler, 0,
|
||||
"drm_decon", ctx);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "lcd_sys irq request failed\n");
|
||||
return ret;
|
||||
|
@ -675,12 +679,6 @@ static int exynos5433_decon_remove(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id exynos5433_decon_driver_dt_match[] = {
|
||||
{ .compatible = "samsung,exynos5433-decon" },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, exynos5433_decon_driver_dt_match);
|
||||
|
||||
struct platform_driver exynos5433_decon_driver = {
|
||||
.probe = exynos5433_decon_probe,
|
||||
.remove = exynos5433_decon_remove,
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
#define MIN_FB_WIDTH_FOR_16WORD_BURST 128
|
||||
|
||||
#define WINDOWS_NR 2
|
||||
#define CURSOR_WIN 1
|
||||
|
||||
struct decon_context {
|
||||
struct device *dev;
|
||||
|
@ -51,7 +52,6 @@ struct decon_context {
|
|||
struct clk *eclk;
|
||||
struct clk *vclk;
|
||||
void __iomem *regs;
|
||||
unsigned int default_win;
|
||||
unsigned long irq_flags;
|
||||
bool i80_if;
|
||||
bool suspended;
|
||||
|
@ -690,8 +690,7 @@ static int decon_bind(struct device *dev, struct device *master, void *data)
|
|||
}
|
||||
|
||||
for (zpos = 0; zpos < WINDOWS_NR; zpos++) {
|
||||
type = (zpos == ctx->default_win) ? DRM_PLANE_TYPE_PRIMARY :
|
||||
DRM_PLANE_TYPE_OVERLAY;
|
||||
type = exynos_plane_get_type(zpos, CURSOR_WIN);
|
||||
ret = exynos_plane_init(drm_dev, &ctx->planes[zpos],
|
||||
1 << ctx->pipe, type, decon_formats,
|
||||
ARRAY_SIZE(decon_formats), zpos);
|
||||
|
@ -699,7 +698,7 @@ static int decon_bind(struct device *dev, struct device *master, void *data)
|
|||
return ret;
|
||||
}
|
||||
|
||||
exynos_plane = &ctx->planes[ctx->default_win];
|
||||
exynos_plane = &ctx->planes[DEFAULT_WIN];
|
||||
ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base,
|
||||
ctx->pipe, EXYNOS_DISPLAY_TYPE_LCD,
|
||||
&decon_crtc_ops, ctx);
|
||||
|
|
|
@ -50,6 +50,17 @@ exynos_drm_crtc_mode_set_nofb(struct drm_crtc *crtc)
|
|||
exynos_crtc->ops->commit(exynos_crtc);
|
||||
}
|
||||
|
||||
static int exynos_crtc_atomic_check(struct drm_crtc *crtc,
|
||||
struct drm_crtc_state *state)
|
||||
{
|
||||
struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
|
||||
|
||||
if (exynos_crtc->ops->atomic_check)
|
||||
return exynos_crtc->ops->atomic_check(exynos_crtc, state);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void exynos_crtc_atomic_begin(struct drm_crtc *crtc,
|
||||
struct drm_crtc_state *old_crtc_state)
|
||||
{
|
||||
|
@ -86,6 +97,7 @@ static struct drm_crtc_helper_funcs exynos_crtc_helper_funcs = {
|
|||
.enable = exynos_drm_crtc_enable,
|
||||
.disable = exynos_drm_crtc_disable,
|
||||
.mode_set_nofb = exynos_drm_crtc_mode_set_nofb,
|
||||
.atomic_check = exynos_crtc_atomic_check,
|
||||
.atomic_begin = exynos_crtc_atomic_begin,
|
||||
.atomic_flush = exynos_crtc_atomic_flush,
|
||||
};
|
||||
|
|
|
@ -529,8 +529,10 @@ static struct platform_driver *const exynos_drm_kms_drivers[] = {
|
|||
#ifdef CONFIG_DRM_EXYNOS_DSI
|
||||
&dsi_driver,
|
||||
#endif
|
||||
#ifdef CONFIG_DRM_EXYNOS_HDMI
|
||||
#ifdef CONFIG_DRM_EXYNOS_MIXER
|
||||
&mixer_driver,
|
||||
#endif
|
||||
#ifdef CONFIG_DRM_EXYNOS_HDMI
|
||||
&hdmi_driver,
|
||||
#endif
|
||||
#ifdef CONFIG_DRM_EXYNOS_VIDI
|
||||
|
|
|
@ -22,6 +22,8 @@
|
|||
#define MAX_PLANE 5
|
||||
#define MAX_FB_BUFFER 4
|
||||
|
||||
#define DEFAULT_WIN 0
|
||||
|
||||
#define to_exynos_crtc(x) container_of(x, struct exynos_drm_crtc, base)
|
||||
#define to_exynos_plane(x) container_of(x, struct exynos_drm_plane, base)
|
||||
|
||||
|
@ -87,6 +89,7 @@ struct exynos_drm_plane {
|
|||
* @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 a window to receive a update
|
||||
* @atomic_flush: mark the end of a window update
|
||||
* @update_plane: apply hardware specific overlay data to registers.
|
||||
|
@ -106,6 +109,8 @@ struct exynos_drm_crtc_ops {
|
|||
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,
|
||||
struct exynos_drm_plane *plane);
|
||||
void (*update_plane)(struct exynos_drm_crtc *crtc,
|
||||
|
|
|
@ -32,15 +32,15 @@
|
|||
* exynos specific framebuffer structure.
|
||||
*
|
||||
* @fb: drm framebuffer obejct.
|
||||
* @exynos_gem_obj: array of exynos specific gem object containing a gem object.
|
||||
* @exynos_gem: array of exynos specific gem object containing a gem object.
|
||||
*/
|
||||
struct exynos_drm_fb {
|
||||
struct drm_framebuffer fb;
|
||||
struct exynos_drm_gem_obj *exynos_gem_obj[MAX_FB_BUFFER];
|
||||
struct drm_framebuffer fb;
|
||||
struct exynos_drm_gem *exynos_gem[MAX_FB_BUFFER];
|
||||
};
|
||||
|
||||
static int check_fb_gem_memory_type(struct drm_device *drm_dev,
|
||||
struct exynos_drm_gem_obj *exynos_gem_obj)
|
||||
struct exynos_drm_gem *exynos_gem)
|
||||
{
|
||||
unsigned int flags;
|
||||
|
||||
|
@ -51,7 +51,7 @@ static int check_fb_gem_memory_type(struct drm_device *drm_dev,
|
|||
if (is_drm_iommu_supported(drm_dev))
|
||||
return 0;
|
||||
|
||||
flags = exynos_gem_obj->flags;
|
||||
flags = exynos_gem->flags;
|
||||
|
||||
/*
|
||||
* without iommu support, not support physically non-continuous memory
|
||||
|
@ -75,13 +75,13 @@ static void exynos_drm_fb_destroy(struct drm_framebuffer *fb)
|
|||
|
||||
drm_framebuffer_cleanup(fb);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(exynos_fb->exynos_gem_obj); i++) {
|
||||
for (i = 0; i < ARRAY_SIZE(exynos_fb->exynos_gem); i++) {
|
||||
struct drm_gem_object *obj;
|
||||
|
||||
if (exynos_fb->exynos_gem_obj[i] == NULL)
|
||||
if (exynos_fb->exynos_gem[i] == NULL)
|
||||
continue;
|
||||
|
||||
obj = &exynos_fb->exynos_gem_obj[i]->base;
|
||||
obj = &exynos_fb->exynos_gem[i]->base;
|
||||
drm_gem_object_unreference_unlocked(obj);
|
||||
}
|
||||
|
||||
|
@ -96,7 +96,7 @@ static int exynos_drm_fb_create_handle(struct drm_framebuffer *fb,
|
|||
struct exynos_drm_fb *exynos_fb = to_exynos_fb(fb);
|
||||
|
||||
return drm_gem_handle_create(file_priv,
|
||||
&exynos_fb->exynos_gem_obj[0]->base, handle);
|
||||
&exynos_fb->exynos_gem[0]->base, handle);
|
||||
}
|
||||
|
||||
static int exynos_drm_fb_dirty(struct drm_framebuffer *fb,
|
||||
|
@ -118,7 +118,7 @@ static struct drm_framebuffer_funcs exynos_drm_fb_funcs = {
|
|||
struct drm_framebuffer *
|
||||
exynos_drm_framebuffer_init(struct drm_device *dev,
|
||||
struct drm_mode_fb_cmd2 *mode_cmd,
|
||||
struct exynos_drm_gem_obj **gem_obj,
|
||||
struct exynos_drm_gem **exynos_gem,
|
||||
int count)
|
||||
{
|
||||
struct exynos_drm_fb *exynos_fb;
|
||||
|
@ -130,11 +130,11 @@ exynos_drm_framebuffer_init(struct drm_device *dev,
|
|||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
ret = check_fb_gem_memory_type(dev, gem_obj[i]);
|
||||
ret = check_fb_gem_memory_type(dev, exynos_gem[i]);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
exynos_fb->exynos_gem_obj[i] = gem_obj[i];
|
||||
exynos_fb->exynos_gem[i] = exynos_gem[i];
|
||||
}
|
||||
|
||||
drm_helper_mode_fill_fb_struct(&exynos_fb->fb, mode_cmd);
|
||||
|
@ -156,7 +156,7 @@ static struct drm_framebuffer *
|
|||
exynos_user_fb_create(struct drm_device *dev, struct drm_file *file_priv,
|
||||
struct drm_mode_fb_cmd2 *mode_cmd)
|
||||
{
|
||||
struct exynos_drm_gem_obj *gem_objs[MAX_FB_BUFFER];
|
||||
struct exynos_drm_gem *exynos_gem[MAX_FB_BUFFER];
|
||||
struct drm_gem_object *obj;
|
||||
struct drm_framebuffer *fb;
|
||||
int i;
|
||||
|
@ -171,10 +171,10 @@ exynos_user_fb_create(struct drm_device *dev, struct drm_file *file_priv,
|
|||
goto err;
|
||||
}
|
||||
|
||||
gem_objs[i] = to_exynos_gem_obj(obj);
|
||||
exynos_gem[i] = to_exynos_gem(obj);
|
||||
}
|
||||
|
||||
fb = exynos_drm_framebuffer_init(dev, mode_cmd, gem_objs, i);
|
||||
fb = exynos_drm_framebuffer_init(dev, mode_cmd, exynos_gem, i);
|
||||
if (IS_ERR(fb)) {
|
||||
ret = PTR_ERR(fb);
|
||||
goto err;
|
||||
|
@ -184,27 +184,26 @@ exynos_user_fb_create(struct drm_device *dev, struct drm_file *file_priv,
|
|||
|
||||
err:
|
||||
while (i--)
|
||||
drm_gem_object_unreference_unlocked(&gem_objs[i]->base);
|
||||
drm_gem_object_unreference_unlocked(&exynos_gem[i]->base);
|
||||
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
struct exynos_drm_gem_obj *exynos_drm_fb_gem_obj(struct drm_framebuffer *fb,
|
||||
int index)
|
||||
struct exynos_drm_gem *exynos_drm_fb_gem(struct drm_framebuffer *fb, int index)
|
||||
{
|
||||
struct exynos_drm_fb *exynos_fb = to_exynos_fb(fb);
|
||||
struct exynos_drm_gem_obj *obj;
|
||||
struct exynos_drm_gem *exynos_gem;
|
||||
|
||||
if (index >= MAX_FB_BUFFER)
|
||||
return NULL;
|
||||
|
||||
obj = exynos_fb->exynos_gem_obj[index];
|
||||
if (!obj)
|
||||
exynos_gem = exynos_fb->exynos_gem[index];
|
||||
if (!exynos_gem)
|
||||
return NULL;
|
||||
|
||||
DRM_DEBUG_KMS("dma_addr = 0x%lx\n", (unsigned long)obj->dma_addr);
|
||||
DRM_DEBUG_KMS("dma_addr: 0x%lx\n", (unsigned long)exynos_gem->dma_addr);
|
||||
|
||||
return obj;
|
||||
return exynos_gem;
|
||||
}
|
||||
|
||||
static void exynos_drm_output_poll_changed(struct drm_device *dev)
|
||||
|
|
|
@ -19,12 +19,11 @@
|
|||
struct drm_framebuffer *
|
||||
exynos_drm_framebuffer_init(struct drm_device *dev,
|
||||
struct drm_mode_fb_cmd2 *mode_cmd,
|
||||
struct exynos_drm_gem_obj **gem_obj,
|
||||
struct exynos_drm_gem **exynos_gem,
|
||||
int count);
|
||||
|
||||
/* get gem object of a drm framebuffer */
|
||||
struct exynos_drm_gem_obj *exynos_drm_fb_gem_obj(struct drm_framebuffer *fb,
|
||||
int index);
|
||||
struct exynos_drm_gem *exynos_drm_fb_gem(struct drm_framebuffer *fb, int index);
|
||||
|
||||
void exynos_drm_mode_config_init(struct drm_device *dev);
|
||||
|
||||
|
|
|
@ -30,8 +30,8 @@
|
|||
drm_fb_helper)
|
||||
|
||||
struct exynos_drm_fbdev {
|
||||
struct drm_fb_helper drm_fb_helper;
|
||||
struct exynos_drm_gem_obj *obj;
|
||||
struct drm_fb_helper drm_fb_helper;
|
||||
struct exynos_drm_gem *exynos_gem;
|
||||
};
|
||||
|
||||
static int exynos_drm_fb_mmap(struct fb_info *info,
|
||||
|
@ -39,7 +39,7 @@ static int exynos_drm_fb_mmap(struct fb_info *info,
|
|||
{
|
||||
struct drm_fb_helper *helper = info->par;
|
||||
struct exynos_drm_fbdev *exynos_fbd = to_exynos_fbdev(helper);
|
||||
struct exynos_drm_gem_obj *obj = exynos_fbd->obj;
|
||||
struct exynos_drm_gem *exynos_gem = exynos_fbd->exynos_gem;
|
||||
unsigned long vm_size;
|
||||
int ret;
|
||||
|
||||
|
@ -47,11 +47,12 @@ static int exynos_drm_fb_mmap(struct fb_info *info,
|
|||
|
||||
vm_size = vma->vm_end - vma->vm_start;
|
||||
|
||||
if (vm_size > obj->size)
|
||||
if (vm_size > exynos_gem->size)
|
||||
return -EINVAL;
|
||||
|
||||
ret = dma_mmap_attrs(helper->dev->dev, vma, obj->pages, obj->dma_addr,
|
||||
obj->size, &obj->dma_attrs);
|
||||
ret = dma_mmap_attrs(helper->dev->dev, vma, exynos_gem->pages,
|
||||
exynos_gem->dma_addr, exynos_gem->size,
|
||||
&exynos_gem->dma_attrs);
|
||||
if (ret < 0) {
|
||||
DRM_ERROR("failed to mmap.\n");
|
||||
return ret;
|
||||
|
@ -75,7 +76,7 @@ static struct fb_ops exynos_drm_fb_ops = {
|
|||
|
||||
static int exynos_drm_fbdev_update(struct drm_fb_helper *helper,
|
||||
struct drm_fb_helper_surface_size *sizes,
|
||||
struct exynos_drm_gem_obj *obj)
|
||||
struct exynos_drm_gem *exynos_gem)
|
||||
{
|
||||
struct fb_info *fbi;
|
||||
struct drm_framebuffer *fb = helper->fb;
|
||||
|
@ -96,11 +97,11 @@ static int exynos_drm_fbdev_update(struct drm_fb_helper *helper,
|
|||
drm_fb_helper_fill_fix(fbi, fb->pitches[0], fb->depth);
|
||||
drm_fb_helper_fill_var(fbi, helper, sizes->fb_width, sizes->fb_height);
|
||||
|
||||
nr_pages = obj->size >> PAGE_SHIFT;
|
||||
nr_pages = exynos_gem->size >> PAGE_SHIFT;
|
||||
|
||||
obj->kvaddr = (void __iomem *) vmap(obj->pages, nr_pages, VM_MAP,
|
||||
pgprot_writecombine(PAGE_KERNEL));
|
||||
if (!obj->kvaddr) {
|
||||
exynos_gem->kvaddr = (void __iomem *) vmap(exynos_gem->pages, nr_pages,
|
||||
VM_MAP, pgprot_writecombine(PAGE_KERNEL));
|
||||
if (!exynos_gem->kvaddr) {
|
||||
DRM_ERROR("failed to map pages to kernel space.\n");
|
||||
drm_fb_helper_release_fbi(helper);
|
||||
return -EIO;
|
||||
|
@ -109,7 +110,7 @@ static int exynos_drm_fbdev_update(struct drm_fb_helper *helper,
|
|||
offset = fbi->var.xoffset * (fb->bits_per_pixel >> 3);
|
||||
offset += fbi->var.yoffset * fb->pitches[0];
|
||||
|
||||
fbi->screen_base = obj->kvaddr + offset;
|
||||
fbi->screen_base = exynos_gem->kvaddr + offset;
|
||||
fbi->screen_size = size;
|
||||
fbi->fix.smem_len = size;
|
||||
|
||||
|
@ -120,7 +121,7 @@ static int exynos_drm_fbdev_create(struct drm_fb_helper *helper,
|
|||
struct drm_fb_helper_surface_size *sizes)
|
||||
{
|
||||
struct exynos_drm_fbdev *exynos_fbdev = to_exynos_fbdev(helper);
|
||||
struct exynos_drm_gem_obj *obj;
|
||||
struct exynos_drm_gem *exynos_gem;
|
||||
struct drm_device *dev = helper->dev;
|
||||
struct drm_mode_fb_cmd2 mode_cmd = { 0 };
|
||||
struct platform_device *pdev = dev->platformdev;
|
||||
|
@ -141,32 +142,34 @@ static int exynos_drm_fbdev_create(struct drm_fb_helper *helper,
|
|||
|
||||
size = mode_cmd.pitches[0] * mode_cmd.height;
|
||||
|
||||
obj = exynos_drm_gem_create(dev, EXYNOS_BO_CONTIG, size);
|
||||
exynos_gem = exynos_drm_gem_create(dev, EXYNOS_BO_CONTIG, size);
|
||||
/*
|
||||
* If physically contiguous memory allocation fails and if IOMMU is
|
||||
* supported then try to get buffer from non physically contiguous
|
||||
* memory area.
|
||||
*/
|
||||
if (IS_ERR(obj) && is_drm_iommu_supported(dev)) {
|
||||
if (IS_ERR(exynos_gem) && is_drm_iommu_supported(dev)) {
|
||||
dev_warn(&pdev->dev, "contiguous FB allocation failed, falling back to non-contiguous\n");
|
||||
obj = exynos_drm_gem_create(dev, EXYNOS_BO_NONCONTIG, size);
|
||||
exynos_gem = exynos_drm_gem_create(dev, EXYNOS_BO_NONCONTIG,
|
||||
size);
|
||||
}
|
||||
|
||||
if (IS_ERR(obj)) {
|
||||
ret = PTR_ERR(obj);
|
||||
if (IS_ERR(exynos_gem)) {
|
||||
ret = PTR_ERR(exynos_gem);
|
||||
goto out;
|
||||
}
|
||||
|
||||
exynos_fbdev->obj = obj;
|
||||
exynos_fbdev->exynos_gem = exynos_gem;
|
||||
|
||||
helper->fb = exynos_drm_framebuffer_init(dev, &mode_cmd, &obj, 1);
|
||||
helper->fb =
|
||||
exynos_drm_framebuffer_init(dev, &mode_cmd, &exynos_gem, 1);
|
||||
if (IS_ERR(helper->fb)) {
|
||||
DRM_ERROR("failed to create drm framebuffer.\n");
|
||||
ret = PTR_ERR(helper->fb);
|
||||
goto err_destroy_gem;
|
||||
}
|
||||
|
||||
ret = exynos_drm_fbdev_update(helper, sizes, obj);
|
||||
ret = exynos_drm_fbdev_update(helper, sizes, exynos_gem);
|
||||
if (ret < 0)
|
||||
goto err_destroy_framebuffer;
|
||||
|
||||
|
@ -176,7 +179,7 @@ static int exynos_drm_fbdev_create(struct drm_fb_helper *helper,
|
|||
err_destroy_framebuffer:
|
||||
drm_framebuffer_cleanup(helper->fb);
|
||||
err_destroy_gem:
|
||||
exynos_drm_gem_destroy(obj);
|
||||
exynos_drm_gem_destroy(exynos_gem);
|
||||
|
||||
/*
|
||||
* if failed, all resources allocated above would be released by
|
||||
|
@ -269,11 +272,11 @@ static void exynos_drm_fbdev_destroy(struct drm_device *dev,
|
|||
struct drm_fb_helper *fb_helper)
|
||||
{
|
||||
struct exynos_drm_fbdev *exynos_fbd = to_exynos_fbdev(fb_helper);
|
||||
struct exynos_drm_gem_obj *obj = exynos_fbd->obj;
|
||||
struct exynos_drm_gem *exynos_gem = exynos_fbd->exynos_gem;
|
||||
struct drm_framebuffer *fb;
|
||||
|
||||
if (obj->kvaddr)
|
||||
vunmap(obj->kvaddr);
|
||||
if (exynos_gem->kvaddr)
|
||||
vunmap(exynos_gem->kvaddr);
|
||||
|
||||
/* release drm framebuffer and real buffer */
|
||||
if (fb_helper->fb && fb_helper->fb->funcs) {
|
||||
|
|
|
@ -466,7 +466,7 @@ static int fimc_src_set_fmt_order(struct fimc_context *ctx, u32 fmt)
|
|||
EXYNOS_MSCTRL_C_INT_IN_2PLANE);
|
||||
break;
|
||||
default:
|
||||
dev_err(ippdrv->dev, "inavlid source yuv order 0x%x.\n", fmt);
|
||||
dev_err(ippdrv->dev, "invalid source yuv order 0x%x.\n", fmt);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -513,7 +513,7 @@ static int fimc_src_set_fmt(struct device *dev, u32 fmt)
|
|||
cfg |= EXYNOS_MSCTRL_INFORMAT_YCBCR420;
|
||||
break;
|
||||
default:
|
||||
dev_err(ippdrv->dev, "inavlid source format 0x%x.\n", fmt);
|
||||
dev_err(ippdrv->dev, "invalid source format 0x%x.\n", fmt);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -578,7 +578,7 @@ static int fimc_src_set_transf(struct device *dev,
|
|||
cfg1 &= ~EXYNOS_MSCTRL_FLIP_Y_MIRROR;
|
||||
break;
|
||||
default:
|
||||
dev_err(ippdrv->dev, "inavlid degree value %d.\n", degree);
|
||||
dev_err(ippdrv->dev, "invalid degree value %d.\n", degree);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -701,7 +701,7 @@ static int fimc_src_set_addr(struct device *dev,
|
|||
property->prop_id, buf_id, buf_type);
|
||||
|
||||
if (buf_id > FIMC_MAX_SRC) {
|
||||
dev_info(ippdrv->dev, "inavlid buf_id %d.\n", buf_id);
|
||||
dev_info(ippdrv->dev, "invalid buf_id %d.\n", buf_id);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
|
@ -812,7 +812,7 @@ static int fimc_dst_set_fmt_order(struct fimc_context *ctx, u32 fmt)
|
|||
cfg |= EXYNOS_CIOCTRL_YCBCR_2PLANE;
|
||||
break;
|
||||
default:
|
||||
dev_err(ippdrv->dev, "inavlid target yuv order 0x%x.\n", fmt);
|
||||
dev_err(ippdrv->dev, "invalid target yuv order 0x%x.\n", fmt);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -865,7 +865,7 @@ static int fimc_dst_set_fmt(struct device *dev, u32 fmt)
|
|||
cfg |= EXYNOS_CITRGFMT_OUTFORMAT_YCBCR420;
|
||||
break;
|
||||
default:
|
||||
dev_err(ippdrv->dev, "inavlid target format 0x%x.\n",
|
||||
dev_err(ippdrv->dev, "invalid target format 0x%x.\n",
|
||||
fmt);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -929,7 +929,7 @@ static int fimc_dst_set_transf(struct device *dev,
|
|||
cfg &= ~EXYNOS_CITRGFMT_FLIP_Y_MIRROR;
|
||||
break;
|
||||
default:
|
||||
dev_err(ippdrv->dev, "inavlid degree value %d.\n", degree);
|
||||
dev_err(ippdrv->dev, "invalid degree value %d.\n", degree);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -1160,7 +1160,7 @@ static int fimc_dst_set_addr(struct device *dev,
|
|||
property->prop_id, buf_id, buf_type);
|
||||
|
||||
if (buf_id > FIMC_MAX_DST) {
|
||||
dev_info(ippdrv->dev, "inavlid buf_id %d.\n", buf_id);
|
||||
dev_info(ippdrv->dev, "invalid buf_id %d.\n", buf_id);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
|
|
|
@ -87,6 +87,7 @@
|
|||
|
||||
/* FIMD has totally five hardware windows. */
|
||||
#define WINDOWS_NR 5
|
||||
#define CURSOR_WIN 4
|
||||
|
||||
struct fimd_driver_data {
|
||||
unsigned int timing_base;
|
||||
|
@ -153,7 +154,6 @@ struct fimd_context {
|
|||
struct clk *lcd_clk;
|
||||
void __iomem *regs;
|
||||
struct regmap *sysreg;
|
||||
unsigned int default_win;
|
||||
unsigned long irq_flags;
|
||||
u32 vidcon0;
|
||||
u32 vidcon1;
|
||||
|
@ -949,8 +949,7 @@ static int fimd_bind(struct device *dev, struct device *master, void *data)
|
|||
ctx->pipe = priv->pipe++;
|
||||
|
||||
for (zpos = 0; zpos < WINDOWS_NR; zpos++) {
|
||||
type = (zpos == ctx->default_win) ? DRM_PLANE_TYPE_PRIMARY :
|
||||
DRM_PLANE_TYPE_OVERLAY;
|
||||
type = exynos_plane_get_type(zpos, CURSOR_WIN);
|
||||
ret = exynos_plane_init(drm_dev, &ctx->planes[zpos],
|
||||
1 << ctx->pipe, type, fimd_formats,
|
||||
ARRAY_SIZE(fimd_formats), zpos);
|
||||
|
@ -958,7 +957,7 @@ static int fimd_bind(struct device *dev, struct device *master, void *data)
|
|||
return ret;
|
||||
}
|
||||
|
||||
exynos_plane = &ctx->planes[ctx->default_win];
|
||||
exynos_plane = &ctx->planes[DEFAULT_WIN];
|
||||
ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base,
|
||||
ctx->pipe, EXYNOS_DISPLAY_TYPE_LCD,
|
||||
&fimd_crtc_ops, ctx);
|
||||
|
|
|
@ -20,97 +20,108 @@
|
|||
#include "exynos_drm_gem.h"
|
||||
#include "exynos_drm_iommu.h"
|
||||
|
||||
static int exynos_drm_alloc_buf(struct exynos_drm_gem_obj *obj)
|
||||
static int exynos_drm_alloc_buf(struct exynos_drm_gem *exynos_gem)
|
||||
{
|
||||
struct drm_device *dev = obj->base.dev;
|
||||
struct drm_device *dev = exynos_gem->base.dev;
|
||||
enum dma_attr attr;
|
||||
unsigned int nr_pages;
|
||||
struct sg_table sgt;
|
||||
int ret = -ENOMEM;
|
||||
|
||||
if (obj->dma_addr) {
|
||||
if (exynos_gem->dma_addr) {
|
||||
DRM_DEBUG_KMS("already allocated.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
init_dma_attrs(&obj->dma_attrs);
|
||||
init_dma_attrs(&exynos_gem->dma_attrs);
|
||||
|
||||
/*
|
||||
* if EXYNOS_BO_CONTIG, fully physically contiguous memory
|
||||
* region will be allocated else physically contiguous
|
||||
* as possible.
|
||||
*/
|
||||
if (!(obj->flags & EXYNOS_BO_NONCONTIG))
|
||||
dma_set_attr(DMA_ATTR_FORCE_CONTIGUOUS, &obj->dma_attrs);
|
||||
if (!(exynos_gem->flags & EXYNOS_BO_NONCONTIG))
|
||||
dma_set_attr(DMA_ATTR_FORCE_CONTIGUOUS, &exynos_gem->dma_attrs);
|
||||
|
||||
/*
|
||||
* if EXYNOS_BO_WC or EXYNOS_BO_NONCACHABLE, writecombine mapping
|
||||
* else cachable mapping.
|
||||
*/
|
||||
if (obj->flags & EXYNOS_BO_WC || !(obj->flags & EXYNOS_BO_CACHABLE))
|
||||
if (exynos_gem->flags & EXYNOS_BO_WC ||
|
||||
!(exynos_gem->flags & EXYNOS_BO_CACHABLE))
|
||||
attr = DMA_ATTR_WRITE_COMBINE;
|
||||
else
|
||||
attr = DMA_ATTR_NON_CONSISTENT;
|
||||
|
||||
dma_set_attr(attr, &obj->dma_attrs);
|
||||
dma_set_attr(DMA_ATTR_NO_KERNEL_MAPPING, &obj->dma_attrs);
|
||||
dma_set_attr(attr, &exynos_gem->dma_attrs);
|
||||
dma_set_attr(DMA_ATTR_NO_KERNEL_MAPPING, &exynos_gem->dma_attrs);
|
||||
|
||||
nr_pages = obj->size >> PAGE_SHIFT;
|
||||
nr_pages = exynos_gem->size >> PAGE_SHIFT;
|
||||
|
||||
if (!is_drm_iommu_supported(dev)) {
|
||||
obj->pages = drm_calloc_large(nr_pages, sizeof(struct page *));
|
||||
if (!obj->pages) {
|
||||
DRM_ERROR("failed to allocate pages.\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
obj->cookie = dma_alloc_attrs(dev->dev, obj->size, &obj->dma_addr,
|
||||
GFP_KERNEL, &obj->dma_attrs);
|
||||
if (!obj->cookie) {
|
||||
DRM_ERROR("failed to allocate buffer.\n");
|
||||
if (obj->pages)
|
||||
drm_free_large(obj->pages);
|
||||
exynos_gem->pages = drm_calloc_large(nr_pages, sizeof(struct page *));
|
||||
if (!exynos_gem->pages) {
|
||||
DRM_ERROR("failed to allocate pages.\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (obj->pages) {
|
||||
dma_addr_t start_addr;
|
||||
unsigned int i = 0;
|
||||
|
||||
start_addr = obj->dma_addr;
|
||||
while (i < nr_pages) {
|
||||
obj->pages[i] = pfn_to_page(dma_to_pfn(dev->dev,
|
||||
start_addr));
|
||||
start_addr += PAGE_SIZE;
|
||||
i++;
|
||||
}
|
||||
} else {
|
||||
obj->pages = obj->cookie;
|
||||
exynos_gem->cookie = dma_alloc_attrs(dev->dev, exynos_gem->size,
|
||||
&exynos_gem->dma_addr, GFP_KERNEL,
|
||||
&exynos_gem->dma_attrs);
|
||||
if (!exynos_gem->cookie) {
|
||||
DRM_ERROR("failed to allocate buffer.\n");
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
ret = dma_get_sgtable_attrs(dev->dev, &sgt, exynos_gem->cookie,
|
||||
exynos_gem->dma_addr, exynos_gem->size,
|
||||
&exynos_gem->dma_attrs);
|
||||
if (ret < 0) {
|
||||
DRM_ERROR("failed to get sgtable.\n");
|
||||
goto err_dma_free;
|
||||
}
|
||||
|
||||
if (drm_prime_sg_to_page_addr_arrays(&sgt, exynos_gem->pages, NULL,
|
||||
nr_pages)) {
|
||||
DRM_ERROR("invalid sgtable.\n");
|
||||
ret = -EINVAL;
|
||||
goto err_sgt_free;
|
||||
}
|
||||
|
||||
sg_free_table(&sgt);
|
||||
|
||||
DRM_DEBUG_KMS("dma_addr(0x%lx), size(0x%lx)\n",
|
||||
(unsigned long)obj->dma_addr,
|
||||
obj->size);
|
||||
(unsigned long)exynos_gem->dma_addr, exynos_gem->size);
|
||||
|
||||
return 0;
|
||||
|
||||
err_sgt_free:
|
||||
sg_free_table(&sgt);
|
||||
err_dma_free:
|
||||
dma_free_attrs(dev->dev, exynos_gem->size, exynos_gem->cookie,
|
||||
exynos_gem->dma_addr, &exynos_gem->dma_attrs);
|
||||
err_free:
|
||||
drm_free_large(exynos_gem->pages);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void exynos_drm_free_buf(struct exynos_drm_gem_obj *obj)
|
||||
static void exynos_drm_free_buf(struct exynos_drm_gem *exynos_gem)
|
||||
{
|
||||
struct drm_device *dev = obj->base.dev;
|
||||
struct drm_device *dev = exynos_gem->base.dev;
|
||||
|
||||
if (!obj->dma_addr) {
|
||||
if (!exynos_gem->dma_addr) {
|
||||
DRM_DEBUG_KMS("dma_addr is invalid.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
DRM_DEBUG_KMS("dma_addr(0x%lx), size(0x%lx)\n",
|
||||
(unsigned long)obj->dma_addr, obj->size);
|
||||
(unsigned long)exynos_gem->dma_addr, exynos_gem->size);
|
||||
|
||||
dma_free_attrs(dev->dev, obj->size, obj->cookie,
|
||||
(dma_addr_t)obj->dma_addr, &obj->dma_attrs);
|
||||
dma_free_attrs(dev->dev, exynos_gem->size, exynos_gem->cookie,
|
||||
(dma_addr_t)exynos_gem->dma_addr,
|
||||
&exynos_gem->dma_attrs);
|
||||
|
||||
if (!is_drm_iommu_supported(dev))
|
||||
drm_free_large(obj->pages);
|
||||
drm_free_large(exynos_gem->pages);
|
||||
}
|
||||
|
||||
static int exynos_drm_gem_handle_create(struct drm_gem_object *obj,
|
||||
|
@ -135,9 +146,9 @@ static int exynos_drm_gem_handle_create(struct drm_gem_object *obj,
|
|||
return 0;
|
||||
}
|
||||
|
||||
void exynos_drm_gem_destroy(struct exynos_drm_gem_obj *exynos_gem_obj)
|
||||
void exynos_drm_gem_destroy(struct exynos_drm_gem *exynos_gem)
|
||||
{
|
||||
struct drm_gem_object *obj = &exynos_gem_obj->base;
|
||||
struct drm_gem_object *obj = &exynos_gem->base;
|
||||
|
||||
DRM_DEBUG_KMS("handle count = %d\n", obj->handle_count);
|
||||
|
||||
|
@ -148,21 +159,21 @@ void exynos_drm_gem_destroy(struct exynos_drm_gem_obj *exynos_gem_obj)
|
|||
* once dmabuf's refcount becomes 0.
|
||||
*/
|
||||
if (obj->import_attach)
|
||||
drm_prime_gem_destroy(obj, exynos_gem_obj->sgt);
|
||||
drm_prime_gem_destroy(obj, exynos_gem->sgt);
|
||||
else
|
||||
exynos_drm_free_buf(exynos_gem_obj);
|
||||
exynos_drm_free_buf(exynos_gem);
|
||||
|
||||
/* release file pointer to gem object. */
|
||||
drm_gem_object_release(obj);
|
||||
|
||||
kfree(exynos_gem_obj);
|
||||
kfree(exynos_gem);
|
||||
}
|
||||
|
||||
unsigned long exynos_drm_gem_get_size(struct drm_device *dev,
|
||||
unsigned int gem_handle,
|
||||
struct drm_file *file_priv)
|
||||
{
|
||||
struct exynos_drm_gem_obj *exynos_gem_obj;
|
||||
struct exynos_drm_gem *exynos_gem;
|
||||
struct drm_gem_object *obj;
|
||||
|
||||
obj = drm_gem_object_lookup(dev, file_priv, gem_handle);
|
||||
|
@ -171,51 +182,51 @@ unsigned long exynos_drm_gem_get_size(struct drm_device *dev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
exynos_gem_obj = to_exynos_gem_obj(obj);
|
||||
exynos_gem = to_exynos_gem(obj);
|
||||
|
||||
drm_gem_object_unreference_unlocked(obj);
|
||||
|
||||
return exynos_gem_obj->size;
|
||||
return exynos_gem->size;
|
||||
}
|
||||
|
||||
static struct exynos_drm_gem_obj *exynos_drm_gem_init(struct drm_device *dev,
|
||||
unsigned long size)
|
||||
static struct exynos_drm_gem *exynos_drm_gem_init(struct drm_device *dev,
|
||||
unsigned long size)
|
||||
{
|
||||
struct exynos_drm_gem_obj *exynos_gem_obj;
|
||||
struct exynos_drm_gem *exynos_gem;
|
||||
struct drm_gem_object *obj;
|
||||
int ret;
|
||||
|
||||
exynos_gem_obj = kzalloc(sizeof(*exynos_gem_obj), GFP_KERNEL);
|
||||
if (!exynos_gem_obj)
|
||||
exynos_gem = kzalloc(sizeof(*exynos_gem), GFP_KERNEL);
|
||||
if (!exynos_gem)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
exynos_gem_obj->size = size;
|
||||
obj = &exynos_gem_obj->base;
|
||||
exynos_gem->size = size;
|
||||
obj = &exynos_gem->base;
|
||||
|
||||
ret = drm_gem_object_init(dev, obj, size);
|
||||
if (ret < 0) {
|
||||
DRM_ERROR("failed to initialize gem object\n");
|
||||
kfree(exynos_gem_obj);
|
||||
kfree(exynos_gem);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
ret = drm_gem_create_mmap_offset(obj);
|
||||
if (ret < 0) {
|
||||
drm_gem_object_release(obj);
|
||||
kfree(exynos_gem_obj);
|
||||
kfree(exynos_gem);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
DRM_DEBUG_KMS("created file object = 0x%x\n", (unsigned int)obj->filp);
|
||||
|
||||
return exynos_gem_obj;
|
||||
return exynos_gem;
|
||||
}
|
||||
|
||||
struct exynos_drm_gem_obj *exynos_drm_gem_create(struct drm_device *dev,
|
||||
unsigned int flags,
|
||||
unsigned long size)
|
||||
struct exynos_drm_gem *exynos_drm_gem_create(struct drm_device *dev,
|
||||
unsigned int flags,
|
||||
unsigned long size)
|
||||
{
|
||||
struct exynos_drm_gem_obj *exynos_gem_obj;
|
||||
struct exynos_drm_gem *exynos_gem;
|
||||
int ret;
|
||||
|
||||
if (flags & ~(EXYNOS_BO_MASK)) {
|
||||
|
@ -230,38 +241,38 @@ struct exynos_drm_gem_obj *exynos_drm_gem_create(struct drm_device *dev,
|
|||
|
||||
size = roundup(size, PAGE_SIZE);
|
||||
|
||||
exynos_gem_obj = exynos_drm_gem_init(dev, size);
|
||||
if (IS_ERR(exynos_gem_obj))
|
||||
return exynos_gem_obj;
|
||||
exynos_gem = exynos_drm_gem_init(dev, size);
|
||||
if (IS_ERR(exynos_gem))
|
||||
return exynos_gem;
|
||||
|
||||
/* set memory type and cache attribute from user side. */
|
||||
exynos_gem_obj->flags = flags;
|
||||
exynos_gem->flags = flags;
|
||||
|
||||
ret = exynos_drm_alloc_buf(exynos_gem_obj);
|
||||
ret = exynos_drm_alloc_buf(exynos_gem);
|
||||
if (ret < 0) {
|
||||
drm_gem_object_release(&exynos_gem_obj->base);
|
||||
kfree(exynos_gem_obj);
|
||||
drm_gem_object_release(&exynos_gem->base);
|
||||
kfree(exynos_gem);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
return exynos_gem_obj;
|
||||
return exynos_gem;
|
||||
}
|
||||
|
||||
int exynos_drm_gem_create_ioctl(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv)
|
||||
{
|
||||
struct drm_exynos_gem_create *args = data;
|
||||
struct exynos_drm_gem_obj *exynos_gem_obj;
|
||||
struct exynos_drm_gem *exynos_gem;
|
||||
int ret;
|
||||
|
||||
exynos_gem_obj = exynos_drm_gem_create(dev, args->flags, args->size);
|
||||
if (IS_ERR(exynos_gem_obj))
|
||||
return PTR_ERR(exynos_gem_obj);
|
||||
exynos_gem = exynos_drm_gem_create(dev, args->flags, args->size);
|
||||
if (IS_ERR(exynos_gem))
|
||||
return PTR_ERR(exynos_gem);
|
||||
|
||||
ret = exynos_drm_gem_handle_create(&exynos_gem_obj->base, file_priv,
|
||||
&args->handle);
|
||||
ret = exynos_drm_gem_handle_create(&exynos_gem->base, file_priv,
|
||||
&args->handle);
|
||||
if (ret) {
|
||||
exynos_drm_gem_destroy(exynos_gem_obj);
|
||||
exynos_drm_gem_destroy(exynos_gem);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -272,7 +283,7 @@ dma_addr_t *exynos_drm_gem_get_dma_addr(struct drm_device *dev,
|
|||
unsigned int gem_handle,
|
||||
struct drm_file *filp)
|
||||
{
|
||||
struct exynos_drm_gem_obj *exynos_gem_obj;
|
||||
struct exynos_drm_gem *exynos_gem;
|
||||
struct drm_gem_object *obj;
|
||||
|
||||
obj = drm_gem_object_lookup(dev, filp, gem_handle);
|
||||
|
@ -281,9 +292,9 @@ dma_addr_t *exynos_drm_gem_get_dma_addr(struct drm_device *dev,
|
|||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
exynos_gem_obj = to_exynos_gem_obj(obj);
|
||||
exynos_gem = to_exynos_gem(obj);
|
||||
|
||||
return &exynos_gem_obj->dma_addr;
|
||||
return &exynos_gem->dma_addr;
|
||||
}
|
||||
|
||||
void exynos_drm_gem_put_dma_addr(struct drm_device *dev,
|
||||
|
@ -307,10 +318,10 @@ void exynos_drm_gem_put_dma_addr(struct drm_device *dev,
|
|||
drm_gem_object_unreference_unlocked(obj);
|
||||
}
|
||||
|
||||
static int exynos_drm_gem_mmap_buffer(struct exynos_drm_gem_obj *exynos_gem_obj,
|
||||
static int exynos_drm_gem_mmap_buffer(struct exynos_drm_gem *exynos_gem,
|
||||
struct vm_area_struct *vma)
|
||||
{
|
||||
struct drm_device *drm_dev = exynos_gem_obj->base.dev;
|
||||
struct drm_device *drm_dev = exynos_gem->base.dev;
|
||||
unsigned long vm_size;
|
||||
int ret;
|
||||
|
||||
|
@ -320,12 +331,12 @@ static int exynos_drm_gem_mmap_buffer(struct exynos_drm_gem_obj *exynos_gem_obj,
|
|||
vm_size = vma->vm_end - vma->vm_start;
|
||||
|
||||
/* check if user-requested size is valid. */
|
||||
if (vm_size > exynos_gem_obj->size)
|
||||
if (vm_size > exynos_gem->size)
|
||||
return -EINVAL;
|
||||
|
||||
ret = dma_mmap_attrs(drm_dev->dev, vma, exynos_gem_obj->pages,
|
||||
exynos_gem_obj->dma_addr, exynos_gem_obj->size,
|
||||
&exynos_gem_obj->dma_attrs);
|
||||
ret = dma_mmap_attrs(drm_dev->dev, vma, exynos_gem->pages,
|
||||
exynos_gem->dma_addr, exynos_gem->size,
|
||||
&exynos_gem->dma_attrs);
|
||||
if (ret < 0) {
|
||||
DRM_ERROR("failed to mmap.\n");
|
||||
return ret;
|
||||
|
@ -337,7 +348,7 @@ static int exynos_drm_gem_mmap_buffer(struct exynos_drm_gem_obj *exynos_gem_obj,
|
|||
int exynos_drm_gem_get_ioctl(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv)
|
||||
{
|
||||
struct exynos_drm_gem_obj *exynos_gem_obj;
|
||||
struct exynos_drm_gem *exynos_gem;
|
||||
struct drm_exynos_gem_info *args = data;
|
||||
struct drm_gem_object *obj;
|
||||
|
||||
|
@ -350,10 +361,10 @@ int exynos_drm_gem_get_ioctl(struct drm_device *dev, void *data,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
exynos_gem_obj = to_exynos_gem_obj(obj);
|
||||
exynos_gem = to_exynos_gem(obj);
|
||||
|
||||
args->flags = exynos_gem_obj->flags;
|
||||
args->size = exynos_gem_obj->size;
|
||||
args->flags = exynos_gem->flags;
|
||||
args->size = exynos_gem->size;
|
||||
|
||||
drm_gem_object_unreference(obj);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
|
@ -389,14 +400,14 @@ void exynos_gem_unmap_sgt_from_dma(struct drm_device *drm_dev,
|
|||
|
||||
void exynos_drm_gem_free_object(struct drm_gem_object *obj)
|
||||
{
|
||||
exynos_drm_gem_destroy(to_exynos_gem_obj(obj));
|
||||
exynos_drm_gem_destroy(to_exynos_gem(obj));
|
||||
}
|
||||
|
||||
int exynos_drm_gem_dumb_create(struct drm_file *file_priv,
|
||||
struct drm_device *dev,
|
||||
struct drm_mode_create_dumb *args)
|
||||
{
|
||||
struct exynos_drm_gem_obj *exynos_gem_obj;
|
||||
struct exynos_drm_gem *exynos_gem;
|
||||
unsigned int flags;
|
||||
int ret;
|
||||
|
||||
|
@ -414,16 +425,16 @@ int exynos_drm_gem_dumb_create(struct drm_file *file_priv,
|
|||
else
|
||||
flags = EXYNOS_BO_CONTIG | EXYNOS_BO_WC;
|
||||
|
||||
exynos_gem_obj = exynos_drm_gem_create(dev, flags, args->size);
|
||||
if (IS_ERR(exynos_gem_obj)) {
|
||||
exynos_gem = exynos_drm_gem_create(dev, flags, args->size);
|
||||
if (IS_ERR(exynos_gem)) {
|
||||
dev_warn(dev->dev, "FB allocation failed.\n");
|
||||
return PTR_ERR(exynos_gem_obj);
|
||||
return PTR_ERR(exynos_gem);
|
||||
}
|
||||
|
||||
ret = exynos_drm_gem_handle_create(&exynos_gem_obj->base, file_priv,
|
||||
&args->handle);
|
||||
ret = exynos_drm_gem_handle_create(&exynos_gem->base, file_priv,
|
||||
&args->handle);
|
||||
if (ret) {
|
||||
exynos_drm_gem_destroy(exynos_gem_obj);
|
||||
exynos_drm_gem_destroy(exynos_gem);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -464,7 +475,7 @@ unlock:
|
|||
int exynos_drm_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
|
||||
{
|
||||
struct drm_gem_object *obj = vma->vm_private_data;
|
||||
struct exynos_drm_gem_obj *exynos_gem_obj = to_exynos_gem_obj(obj);
|
||||
struct exynos_drm_gem *exynos_gem = to_exynos_gem(obj);
|
||||
unsigned long pfn;
|
||||
pgoff_t page_offset;
|
||||
int ret;
|
||||
|
@ -472,13 +483,13 @@ int exynos_drm_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
|
|||
page_offset = ((unsigned long)vmf->virtual_address -
|
||||
vma->vm_start) >> PAGE_SHIFT;
|
||||
|
||||
if (page_offset >= (exynos_gem_obj->size >> PAGE_SHIFT)) {
|
||||
if (page_offset >= (exynos_gem->size >> PAGE_SHIFT)) {
|
||||
DRM_ERROR("invalid page offset\n");
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
pfn = page_to_pfn(exynos_gem_obj->pages[page_offset]);
|
||||
pfn = page_to_pfn(exynos_gem->pages[page_offset]);
|
||||
ret = vm_insert_mixed(vma, (unsigned long)vmf->virtual_address, pfn);
|
||||
|
||||
out:
|
||||
|
@ -496,7 +507,7 @@ out:
|
|||
|
||||
int exynos_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma)
|
||||
{
|
||||
struct exynos_drm_gem_obj *exynos_gem_obj;
|
||||
struct exynos_drm_gem *exynos_gem;
|
||||
struct drm_gem_object *obj;
|
||||
int ret;
|
||||
|
||||
|
@ -508,21 +519,21 @@ int exynos_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma)
|
|||
}
|
||||
|
||||
obj = vma->vm_private_data;
|
||||
exynos_gem_obj = to_exynos_gem_obj(obj);
|
||||
exynos_gem = to_exynos_gem(obj);
|
||||
|
||||
DRM_DEBUG_KMS("flags = 0x%x\n", exynos_gem_obj->flags);
|
||||
DRM_DEBUG_KMS("flags = 0x%x\n", exynos_gem->flags);
|
||||
|
||||
/* non-cachable as default. */
|
||||
if (exynos_gem_obj->flags & EXYNOS_BO_CACHABLE)
|
||||
if (exynos_gem->flags & EXYNOS_BO_CACHABLE)
|
||||
vma->vm_page_prot = vm_get_page_prot(vma->vm_flags);
|
||||
else if (exynos_gem_obj->flags & EXYNOS_BO_WC)
|
||||
else if (exynos_gem->flags & EXYNOS_BO_WC)
|
||||
vma->vm_page_prot =
|
||||
pgprot_writecombine(vm_get_page_prot(vma->vm_flags));
|
||||
else
|
||||
vma->vm_page_prot =
|
||||
pgprot_noncached(vm_get_page_prot(vma->vm_flags));
|
||||
|
||||
ret = exynos_drm_gem_mmap_buffer(exynos_gem_obj, vma);
|
||||
ret = exynos_drm_gem_mmap_buffer(exynos_gem, vma);
|
||||
if (ret)
|
||||
goto err_close_vm;
|
||||
|
||||
|
@ -537,12 +548,12 @@ err_close_vm:
|
|||
/* low-level interface prime helpers */
|
||||
struct sg_table *exynos_drm_gem_prime_get_sg_table(struct drm_gem_object *obj)
|
||||
{
|
||||
struct exynos_drm_gem_obj *exynos_gem_obj = to_exynos_gem_obj(obj);
|
||||
struct exynos_drm_gem *exynos_gem = to_exynos_gem(obj);
|
||||
int npages;
|
||||
|
||||
npages = exynos_gem_obj->size >> PAGE_SHIFT;
|
||||
npages = exynos_gem->size >> PAGE_SHIFT;
|
||||
|
||||
return drm_prime_pages_to_sg(exynos_gem_obj->pages, npages);
|
||||
return drm_prime_pages_to_sg(exynos_gem->pages, npages);
|
||||
}
|
||||
|
||||
struct drm_gem_object *
|
||||
|
@ -550,35 +561,35 @@ exynos_drm_gem_prime_import_sg_table(struct drm_device *dev,
|
|||
struct dma_buf_attachment *attach,
|
||||
struct sg_table *sgt)
|
||||
{
|
||||
struct exynos_drm_gem_obj *exynos_gem_obj;
|
||||
struct exynos_drm_gem *exynos_gem;
|
||||
int npages;
|
||||
int ret;
|
||||
|
||||
exynos_gem_obj = exynos_drm_gem_init(dev, attach->dmabuf->size);
|
||||
if (IS_ERR(exynos_gem_obj)) {
|
||||
ret = PTR_ERR(exynos_gem_obj);
|
||||
exynos_gem = exynos_drm_gem_init(dev, attach->dmabuf->size);
|
||||
if (IS_ERR(exynos_gem)) {
|
||||
ret = PTR_ERR(exynos_gem);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
exynos_gem_obj->dma_addr = sg_dma_address(sgt->sgl);
|
||||
exynos_gem->dma_addr = sg_dma_address(sgt->sgl);
|
||||
|
||||
npages = exynos_gem_obj->size >> PAGE_SHIFT;
|
||||
exynos_gem_obj->pages = drm_malloc_ab(npages, sizeof(struct page *));
|
||||
if (!exynos_gem_obj->pages) {
|
||||
npages = exynos_gem->size >> PAGE_SHIFT;
|
||||
exynos_gem->pages = drm_malloc_ab(npages, sizeof(struct page *));
|
||||
if (!exynos_gem->pages) {
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = drm_prime_sg_to_page_addr_arrays(sgt, exynos_gem_obj->pages, NULL,
|
||||
npages);
|
||||
ret = drm_prime_sg_to_page_addr_arrays(sgt, exynos_gem->pages, NULL,
|
||||
npages);
|
||||
if (ret < 0)
|
||||
goto err_free_large;
|
||||
|
||||
exynos_gem_obj->sgt = sgt;
|
||||
exynos_gem->sgt = sgt;
|
||||
|
||||
if (sgt->nents == 1) {
|
||||
/* always physically continuous memory if sgt->nents is 1. */
|
||||
exynos_gem_obj->flags |= EXYNOS_BO_CONTIG;
|
||||
exynos_gem->flags |= EXYNOS_BO_CONTIG;
|
||||
} else {
|
||||
/*
|
||||
* this case could be CONTIG or NONCONTIG type but for now
|
||||
|
@ -586,16 +597,16 @@ exynos_drm_gem_prime_import_sg_table(struct drm_device *dev,
|
|||
* TODO. we have to find a way that exporter can notify
|
||||
* the type of its own buffer to importer.
|
||||
*/
|
||||
exynos_gem_obj->flags |= EXYNOS_BO_NONCONTIG;
|
||||
exynos_gem->flags |= EXYNOS_BO_NONCONTIG;
|
||||
}
|
||||
|
||||
return &exynos_gem_obj->base;
|
||||
return &exynos_gem->base;
|
||||
|
||||
err_free_large:
|
||||
drm_free_large(exynos_gem_obj->pages);
|
||||
drm_free_large(exynos_gem->pages);
|
||||
err:
|
||||
drm_gem_object_release(&exynos_gem_obj->base);
|
||||
kfree(exynos_gem_obj);
|
||||
drm_gem_object_release(&exynos_gem->base);
|
||||
kfree(exynos_gem);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
|
|
|
@ -14,8 +14,7 @@
|
|||
|
||||
#include <drm/drm_gem.h>
|
||||
|
||||
#define to_exynos_gem_obj(x) container_of(x,\
|
||||
struct exynos_drm_gem_obj, base)
|
||||
#define to_exynos_gem(x) container_of(x, struct exynos_drm_gem, base)
|
||||
|
||||
#define IS_NONCONTIG_BUFFER(f) (f & EXYNOS_BO_NONCONTIG)
|
||||
|
||||
|
@ -44,7 +43,7 @@
|
|||
* P.S. this object would be transferred to user as kms_bo.handle so
|
||||
* user can access the buffer through kms_bo.handle.
|
||||
*/
|
||||
struct exynos_drm_gem_obj {
|
||||
struct exynos_drm_gem {
|
||||
struct drm_gem_object base;
|
||||
unsigned int flags;
|
||||
unsigned long size;
|
||||
|
@ -59,12 +58,12 @@ struct exynos_drm_gem_obj {
|
|||
struct page **exynos_gem_get_pages(struct drm_gem_object *obj, gfp_t gfpmask);
|
||||
|
||||
/* destroy a buffer with gem object */
|
||||
void exynos_drm_gem_destroy(struct exynos_drm_gem_obj *exynos_gem_obj);
|
||||
void exynos_drm_gem_destroy(struct exynos_drm_gem *exynos_gem);
|
||||
|
||||
/* create a new buffer with gem object */
|
||||
struct exynos_drm_gem_obj *exynos_drm_gem_create(struct drm_device *dev,
|
||||
unsigned int flags,
|
||||
unsigned long size);
|
||||
struct exynos_drm_gem *exynos_drm_gem_create(struct drm_device *dev,
|
||||
unsigned int flags,
|
||||
unsigned long size);
|
||||
|
||||
/*
|
||||
* request gem object creation and buffer allocation as the size
|
||||
|
@ -106,7 +105,7 @@ unsigned long exynos_drm_gem_get_size(struct drm_device *dev,
|
|||
struct drm_file *file_priv);
|
||||
|
||||
/* free gem object. */
|
||||
void exynos_drm_gem_free_object(struct drm_gem_object *gem_obj);
|
||||
void exynos_drm_gem_free_object(struct drm_gem_object *obj);
|
||||
|
||||
/* create memory region for drm framebuffer. */
|
||||
int exynos_drm_gem_dumb_create(struct drm_file *file_priv,
|
||||
|
|
|
@ -543,7 +543,7 @@ static int gsc_src_set_fmt(struct device *dev, u32 fmt)
|
|||
GSC_IN_YUV420_2P);
|
||||
break;
|
||||
default:
|
||||
dev_err(ippdrv->dev, "inavlid target yuv order 0x%x.\n", fmt);
|
||||
dev_err(ippdrv->dev, "invalid target yuv order 0x%x.\n", fmt);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -595,7 +595,7 @@ static int gsc_src_set_transf(struct device *dev,
|
|||
cfg &= ~GSC_IN_ROT_YFLIP;
|
||||
break;
|
||||
default:
|
||||
dev_err(ippdrv->dev, "inavlid degree value %d.\n", degree);
|
||||
dev_err(ippdrv->dev, "invalid degree value %d.\n", degree);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -721,7 +721,7 @@ static int gsc_src_set_addr(struct device *dev,
|
|||
property->prop_id, buf_id, buf_type);
|
||||
|
||||
if (buf_id > GSC_MAX_SRC) {
|
||||
dev_info(ippdrv->dev, "inavlid buf_id %d.\n", buf_id);
|
||||
dev_info(ippdrv->dev, "invalid buf_id %d.\n", buf_id);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -814,7 +814,7 @@ static int gsc_dst_set_fmt(struct device *dev, u32 fmt)
|
|||
GSC_OUT_YUV420_2P);
|
||||
break;
|
||||
default:
|
||||
dev_err(ippdrv->dev, "inavlid target yuv order 0x%x.\n", fmt);
|
||||
dev_err(ippdrv->dev, "invalid target yuv order 0x%x.\n", fmt);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -866,7 +866,7 @@ static int gsc_dst_set_transf(struct device *dev,
|
|||
cfg &= ~GSC_IN_ROT_YFLIP;
|
||||
break;
|
||||
default:
|
||||
dev_err(ippdrv->dev, "inavlid degree value %d.\n", degree);
|
||||
dev_err(ippdrv->dev, "invalid degree value %d.\n", degree);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -1176,7 +1176,7 @@ static int gsc_dst_set_addr(struct device *dev,
|
|||
property->prop_id, buf_id, buf_type);
|
||||
|
||||
if (buf_id > GSC_MAX_DST) {
|
||||
dev_info(ippdrv->dev, "inavlid buf_id %d.\n", buf_id);
|
||||
dev_info(ippdrv->dev, "invalid buf_id %d.\n", buf_id);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
|
|
@ -139,6 +139,5 @@ void drm_iommu_detach_device(struct drm_device *drm_dev,
|
|||
if (!mapping || !mapping->domain)
|
||||
return;
|
||||
|
||||
iommu_detach_device(mapping->domain, subdrv_dev);
|
||||
drm_release_iommu_mapping(drm_dev);
|
||||
arm_iommu_detach_device(subdrv_dev);
|
||||
}
|
||||
|
|
|
@ -128,15 +128,14 @@ static int exynos_plane_atomic_check(struct drm_plane *plane,
|
|||
|
||||
nr = drm_format_num_planes(state->fb->pixel_format);
|
||||
for (i = 0; i < nr; i++) {
|
||||
struct exynos_drm_gem_obj *obj =
|
||||
exynos_drm_fb_gem_obj(state->fb, i);
|
||||
|
||||
if (!obj) {
|
||||
struct exynos_drm_gem *exynos_gem =
|
||||
exynos_drm_fb_gem(state->fb, i);
|
||||
if (!exynos_gem) {
|
||||
DRM_DEBUG_KMS("gem object is null\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
exynos_plane->dma_addr[i] = obj->dma_addr +
|
||||
exynos_plane->dma_addr[i] = exynos_gem->dma_addr +
|
||||
state->fb->offsets[i];
|
||||
|
||||
DRM_DEBUG_KMS("buffer: %d, dma_addr = 0x%lx\n",
|
||||
|
@ -208,6 +207,17 @@ static void exynos_plane_attach_zpos_property(struct drm_plane *plane,
|
|||
drm_object_attach_property(&plane->base, prop, zpos);
|
||||
}
|
||||
|
||||
enum drm_plane_type exynos_plane_get_type(unsigned int zpos,
|
||||
unsigned int cursor_win)
|
||||
{
|
||||
if (zpos == DEFAULT_WIN)
|
||||
return DRM_PLANE_TYPE_PRIMARY;
|
||||
else if (zpos == cursor_win)
|
||||
return DRM_PLANE_TYPE_CURSOR;
|
||||
else
|
||||
return DRM_PLANE_TYPE_OVERLAY;
|
||||
}
|
||||
|
||||
int exynos_plane_init(struct drm_device *dev,
|
||||
struct exynos_drm_plane *exynos_plane,
|
||||
unsigned long possible_crtcs, enum drm_plane_type type,
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
*
|
||||
*/
|
||||
|
||||
enum drm_plane_type exynos_plane_get_type(unsigned int zpos,
|
||||
unsigned int cursor_win);
|
||||
int exynos_plane_init(struct drm_device *dev,
|
||||
struct exynos_drm_plane *exynos_plane,
|
||||
unsigned long possible_crtcs, enum drm_plane_type type,
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
|
||||
/* vidi has totally three virtual windows. */
|
||||
#define WINDOWS_NR 3
|
||||
#define CURSOR_WIN 2
|
||||
|
||||
#define ctx_from_connector(c) container_of(c, struct vidi_context, \
|
||||
connector)
|
||||
|
@ -42,7 +43,6 @@ struct vidi_context {
|
|||
struct exynos_drm_plane planes[WINDOWS_NR];
|
||||
struct edid *raw_edid;
|
||||
unsigned int clkdiv;
|
||||
unsigned int default_win;
|
||||
unsigned long irq_flags;
|
||||
unsigned int connected;
|
||||
bool vblank_on;
|
||||
|
@ -446,8 +446,7 @@ static int vidi_bind(struct device *dev, struct device *master, void *data)
|
|||
vidi_ctx_initialize(ctx, drm_dev);
|
||||
|
||||
for (zpos = 0; zpos < WINDOWS_NR; zpos++) {
|
||||
type = (zpos == ctx->default_win) ? DRM_PLANE_TYPE_PRIMARY :
|
||||
DRM_PLANE_TYPE_OVERLAY;
|
||||
type = exynos_plane_get_type(zpos, CURSOR_WIN);
|
||||
ret = exynos_plane_init(drm_dev, &ctx->planes[zpos],
|
||||
1 << ctx->pipe, type, formats,
|
||||
ARRAY_SIZE(formats), zpos);
|
||||
|
@ -455,7 +454,7 @@ static int vidi_bind(struct device *dev, struct device *master, void *data)
|
|||
return ret;
|
||||
}
|
||||
|
||||
exynos_plane = &ctx->planes[ctx->default_win];
|
||||
exynos_plane = &ctx->planes[DEFAULT_WIN];
|
||||
ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base,
|
||||
ctx->pipe, EXYNOS_DISPLAY_TYPE_VIDI,
|
||||
&vidi_crtc_ops, ctx);
|
||||
|
@ -507,7 +506,6 @@ static int vidi_probe(struct platform_device *pdev)
|
|||
if (!ctx)
|
||||
return -ENOMEM;
|
||||
|
||||
ctx->default_win = 0;
|
||||
ctx->pdev = pdev;
|
||||
|
||||
INIT_WORK(&ctx->work, vidi_fake_vblank_handler);
|
||||
|
|
|
@ -30,11 +30,11 @@
|
|||
#include <linux/delay.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/hdmi.h>
|
||||
#include <linux/component.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
|
@ -44,11 +44,6 @@
|
|||
|
||||
#include "exynos_drm_drv.h"
|
||||
#include "exynos_drm_crtc.h"
|
||||
#include "exynos_mixer.h"
|
||||
|
||||
#include <linux/gpio.h>
|
||||
|
||||
#define ctx_from_connector(c) container_of(c, struct hdmi_context, connector)
|
||||
|
||||
#define HOTPLUG_DEBOUNCE_MS 1100
|
||||
|
||||
|
@ -66,6 +61,33 @@
|
|||
enum hdmi_type {
|
||||
HDMI_TYPE13,
|
||||
HDMI_TYPE14,
|
||||
HDMI_TYPE_COUNT
|
||||
};
|
||||
|
||||
#define HDMI_MAPPED_BASE 0xffff0000
|
||||
|
||||
enum hdmi_mapped_regs {
|
||||
HDMI_PHY_STATUS = HDMI_MAPPED_BASE,
|
||||
HDMI_PHY_RSTOUT,
|
||||
HDMI_ACR_CON,
|
||||
HDMI_ACR_MCTS0,
|
||||
HDMI_ACR_CTS0,
|
||||
HDMI_ACR_N0
|
||||
};
|
||||
|
||||
static const u32 hdmi_reg_map[][HDMI_TYPE_COUNT] = {
|
||||
{ HDMI_V13_PHY_STATUS, HDMI_PHY_STATUS_0 },
|
||||
{ HDMI_V13_PHY_RSTOUT, HDMI_V14_PHY_RSTOUT },
|
||||
{ HDMI_V13_ACR_CON, HDMI_V14_ACR_CON },
|
||||
{ HDMI_V13_ACR_MCTS0, HDMI_V14_ACR_MCTS0 },
|
||||
{ HDMI_V13_ACR_CTS0, HDMI_V14_ACR_CTS0 },
|
||||
{ HDMI_V13_ACR_N0, HDMI_V14_ACR_N0 },
|
||||
};
|
||||
|
||||
static const char * const supply[] = {
|
||||
"vdd",
|
||||
"vdd_osc",
|
||||
"vdd_pll",
|
||||
};
|
||||
|
||||
struct hdmi_driver_data {
|
||||
|
@ -75,44 +97,32 @@ struct hdmi_driver_data {
|
|||
unsigned int is_apb_phy:1;
|
||||
};
|
||||
|
||||
struct hdmi_resources {
|
||||
struct clk *hdmi;
|
||||
struct clk *sclk_hdmi;
|
||||
struct clk *sclk_pixel;
|
||||
struct clk *sclk_hdmiphy;
|
||||
struct clk *mout_hdmi;
|
||||
struct regulator_bulk_data *regul_bulk;
|
||||
struct regulator *reg_hdmi_en;
|
||||
int regul_count;
|
||||
};
|
||||
|
||||
struct hdmi_context {
|
||||
struct drm_encoder encoder;
|
||||
struct device *dev;
|
||||
struct drm_device *drm_dev;
|
||||
struct drm_connector connector;
|
||||
bool hpd;
|
||||
bool powered;
|
||||
bool dvi_mode;
|
||||
|
||||
void __iomem *regs;
|
||||
int irq;
|
||||
struct delayed_work hotplug_work;
|
||||
|
||||
struct i2c_adapter *ddc_adpt;
|
||||
struct i2c_client *hdmiphy_port;
|
||||
|
||||
/* current hdmiphy conf regs */
|
||||
struct drm_display_mode current_mode;
|
||||
u8 cea_video_id;
|
||||
|
||||
struct hdmi_resources res;
|
||||
const struct hdmi_driver_data *drv_data;
|
||||
|
||||
int hpd_gpio;
|
||||
void __iomem *regs;
|
||||
void __iomem *regs_hdmiphy;
|
||||
|
||||
struct i2c_client *hdmiphy_port;
|
||||
struct i2c_adapter *ddc_adpt;
|
||||
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 regulator_bulk_data regul_bulk[ARRAY_SIZE(supply)];
|
||||
struct regulator *reg_hdmi_en;
|
||||
};
|
||||
|
||||
static inline struct hdmi_context *encoder_to_hdmi(struct drm_encoder *e)
|
||||
|
@ -120,6 +130,11 @@ static inline struct hdmi_context *encoder_to_hdmi(struct drm_encoder *e)
|
|||
return container_of(e, struct hdmi_context, encoder);
|
||||
}
|
||||
|
||||
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];
|
||||
|
@ -133,7 +148,7 @@ static const struct hdmiphy_config hdmiphy_v13_configs[] = {
|
|||
0x01, 0x05, 0x00, 0xD8, 0x10, 0x1C, 0x30, 0x40,
|
||||
0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87,
|
||||
0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
|
||||
0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x00,
|
||||
0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x80,
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -142,7 +157,7 @@ static const struct hdmiphy_config hdmiphy_v13_configs[] = {
|
|||
0x01, 0x05, 0x00, 0xD4, 0x10, 0x9C, 0x09, 0x64,
|
||||
0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87,
|
||||
0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
|
||||
0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x00,
|
||||
0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x80,
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -151,7 +166,7 @@ static const struct hdmiphy_config hdmiphy_v13_configs[] = {
|
|||
0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xef, 0x5B,
|
||||
0x6D, 0x10, 0x01, 0x51, 0xef, 0xF3, 0x54, 0xb9,
|
||||
0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
|
||||
0x22, 0x40, 0xa5, 0x26, 0x01, 0x00, 0x00, 0x00,
|
||||
0x22, 0x40, 0xa5, 0x26, 0x01, 0x00, 0x00, 0x80,
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -160,7 +175,7 @@ static const struct hdmiphy_config hdmiphy_v13_configs[] = {
|
|||
0x01, 0x05, 0x00, 0xd8, 0x10, 0x9c, 0xf8, 0x40,
|
||||
0x6a, 0x10, 0x01, 0x51, 0xff, 0xf1, 0x54, 0xba,
|
||||
0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xe0,
|
||||
0x22, 0x40, 0xa4, 0x26, 0x01, 0x00, 0x00, 0x00,
|
||||
0x22, 0x40, 0xa4, 0x26, 0x01, 0x00, 0x00, 0x80,
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -169,7 +184,7 @@ static const struct hdmiphy_config hdmiphy_v13_configs[] = {
|
|||
0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xf8, 0x40,
|
||||
0x6A, 0x18, 0x00, 0x51, 0xff, 0xF1, 0x54, 0xba,
|
||||
0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xE0,
|
||||
0x22, 0x40, 0xa4, 0x26, 0x02, 0x00, 0x00, 0x00,
|
||||
0x22, 0x40, 0xa4, 0x26, 0x02, 0x00, 0x00, 0x80,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
@ -199,7 +214,7 @@ static const struct hdmiphy_config hdmiphy_v14_configs[] = {
|
|||
0x01, 0xd1, 0x2d, 0x72, 0x40, 0x64, 0x12, 0x08,
|
||||
0x43, 0xa0, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
|
||||
0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
|
||||
0x54, 0xe3, 0x24, 0x00, 0x00, 0x00, 0x01, 0x00,
|
||||
0x54, 0xe3, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -262,7 +277,7 @@ static const struct hdmiphy_config hdmiphy_v14_configs[] = {
|
|||
0x01, 0xd1, 0x1f, 0x10, 0x40, 0x40, 0xf8, 0x08,
|
||||
0x81, 0xa0, 0xba, 0xd8, 0x45, 0xa0, 0xac, 0x80,
|
||||
0x3c, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
|
||||
0x54, 0xa5, 0x24, 0x01, 0x00, 0x00, 0x01, 0x00,
|
||||
0x54, 0xa5, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -325,7 +340,7 @@ static const struct hdmiphy_config hdmiphy_v14_configs[] = {
|
|||
0x01, 0xd1, 0x1f, 0x00, 0x40, 0x40, 0xf8, 0x08,
|
||||
0x81, 0xa0, 0xba, 0xd8, 0x45, 0xa0, 0xac, 0x80,
|
||||
0x3c, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
|
||||
0x54, 0x4b, 0x25, 0x03, 0x00, 0x00, 0x01, 0x00,
|
||||
0x54, 0x4b, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
@ -507,29 +522,31 @@ static struct hdmi_driver_data exynos4210_hdmi_driver_data = {
|
|||
.is_apb_phy = 0,
|
||||
};
|
||||
|
||||
static struct hdmi_driver_data exynos5_hdmi_driver_data = {
|
||||
.type = HDMI_TYPE14,
|
||||
.phy_confs = hdmiphy_v13_configs,
|
||||
.phy_conf_count = ARRAY_SIZE(hdmiphy_v13_configs),
|
||||
.is_apb_phy = 0,
|
||||
};
|
||||
static inline u32 hdmi_map_reg(struct hdmi_context *hdata, u32 reg_id)
|
||||
{
|
||||
if ((reg_id & 0xffff0000) == HDMI_MAPPED_BASE)
|
||||
return hdmi_reg_map[reg_id & 0xffff][hdata->drv_data->type];
|
||||
return reg_id;
|
||||
}
|
||||
|
||||
static inline u32 hdmi_reg_read(struct hdmi_context *hdata, u32 reg_id)
|
||||
{
|
||||
return readl(hdata->regs + reg_id);
|
||||
return readl(hdata->regs + hdmi_map_reg(hdata, reg_id));
|
||||
}
|
||||
|
||||
static inline void hdmi_reg_writeb(struct hdmi_context *hdata,
|
||||
u32 reg_id, u8 value)
|
||||
{
|
||||
writeb(value, hdata->regs + reg_id);
|
||||
writel(value, hdata->regs + hdmi_map_reg(hdata, reg_id));
|
||||
}
|
||||
|
||||
static inline void hdmi_reg_writev(struct hdmi_context *hdata, u32 reg_id,
|
||||
int bytes, u32 val)
|
||||
{
|
||||
reg_id = hdmi_map_reg(hdata, reg_id);
|
||||
|
||||
while (--bytes >= 0) {
|
||||
writeb(val & 0xff, hdata->regs + reg_id);
|
||||
writel(val & 0xff, hdata->regs + reg_id);
|
||||
val >>= 8;
|
||||
reg_id += 4;
|
||||
}
|
||||
|
@ -538,31 +555,14 @@ static inline void hdmi_reg_writev(struct hdmi_context *hdata, u32 reg_id,
|
|||
static inline void hdmi_reg_writemask(struct hdmi_context *hdata,
|
||||
u32 reg_id, u32 value, u32 mask)
|
||||
{
|
||||
u32 old = readl(hdata->regs + reg_id);
|
||||
u32 old;
|
||||
|
||||
reg_id = hdmi_map_reg(hdata, reg_id);
|
||||
old = readl(hdata->regs + reg_id);
|
||||
value = (value & mask) | (old & ~mask);
|
||||
writel(value, hdata->regs + reg_id);
|
||||
}
|
||||
|
||||
static int hdmiphy_reg_writeb(struct hdmi_context *hdata,
|
||||
u32 reg_offset, u8 value)
|
||||
{
|
||||
if (hdata->hdmiphy_port) {
|
||||
u8 buffer[2];
|
||||
int ret;
|
||||
|
||||
buffer[0] = reg_offset;
|
||||
buffer[1] = value;
|
||||
|
||||
ret = i2c_master_send(hdata->hdmiphy_port, buffer, 2);
|
||||
if (ret == 2)
|
||||
return 0;
|
||||
return ret;
|
||||
} else {
|
||||
writeb(value, hdata->regs_hdmiphy + (reg_offset<<2));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int hdmiphy_reg_write_buf(struct hdmi_context *hdata,
|
||||
u32 reg_offset, const u8 *buf, u32 len)
|
||||
{
|
||||
|
@ -579,7 +579,7 @@ static int hdmiphy_reg_write_buf(struct hdmi_context *hdata,
|
|||
} else {
|
||||
int i;
|
||||
for (i = 0; i < len; i++)
|
||||
writeb(buf[i], hdata->regs_hdmiphy +
|
||||
writel(buf[i], hdata->regs_hdmiphy +
|
||||
((reg_offset + i)<<2));
|
||||
return 0;
|
||||
}
|
||||
|
@ -689,7 +689,7 @@ static void hdmi_v14_regs_dump(struct hdmi_context *hdata, char *prefix)
|
|||
DUMPREG(HDMI_PHY_STATUS_0);
|
||||
DUMPREG(HDMI_PHY_STATUS_PLL);
|
||||
DUMPREG(HDMI_PHY_CON_0);
|
||||
DUMPREG(HDMI_PHY_RSTOUT);
|
||||
DUMPREG(HDMI_V14_PHY_RSTOUT);
|
||||
DUMPREG(HDMI_PHY_VPLL);
|
||||
DUMPREG(HDMI_PHY_CMU);
|
||||
DUMPREG(HDMI_CORE_RSTOUT);
|
||||
|
@ -942,9 +942,9 @@ static void hdmi_reg_infoframe(struct hdmi_context *hdata,
|
|||
static enum drm_connector_status hdmi_detect(struct drm_connector *connector,
|
||||
bool force)
|
||||
{
|
||||
struct hdmi_context *hdata = ctx_from_connector(connector);
|
||||
struct hdmi_context *hdata = connector_to_hdmi(connector);
|
||||
|
||||
if (gpio_get_value(hdata->hpd_gpio))
|
||||
if (gpiod_get_value(hdata->hpd_gpio))
|
||||
return connector_status_connected;
|
||||
|
||||
return connector_status_disconnected;
|
||||
|
@ -968,7 +968,7 @@ static struct drm_connector_funcs hdmi_connector_funcs = {
|
|||
|
||||
static int hdmi_get_modes(struct drm_connector *connector)
|
||||
{
|
||||
struct hdmi_context *hdata = ctx_from_connector(connector);
|
||||
struct hdmi_context *hdata = connector_to_hdmi(connector);
|
||||
struct edid *edid;
|
||||
int ret;
|
||||
|
||||
|
@ -1008,7 +1008,7 @@ static int hdmi_find_phy_conf(struct hdmi_context *hdata, u32 pixel_clock)
|
|||
static int hdmi_mode_valid(struct drm_connector *connector,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
struct hdmi_context *hdata = ctx_from_connector(connector);
|
||||
struct hdmi_context *hdata = connector_to_hdmi(connector);
|
||||
int ret;
|
||||
|
||||
DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%d clock=%d\n",
|
||||
|
@ -1016,10 +1016,6 @@ static int hdmi_mode_valid(struct drm_connector *connector,
|
|||
(mode->flags & DRM_MODE_FLAG_INTERLACE) ? true :
|
||||
false, mode->clock * 1000);
|
||||
|
||||
ret = mixer_check_mode(mode);
|
||||
if (ret)
|
||||
return MODE_BAD;
|
||||
|
||||
ret = hdmi_find_phy_conf(hdata, mode->clock * 1000);
|
||||
if (ret < 0)
|
||||
return MODE_BAD;
|
||||
|
@ -1029,7 +1025,7 @@ static int hdmi_mode_valid(struct drm_connector *connector,
|
|||
|
||||
static struct drm_encoder *hdmi_best_encoder(struct drm_connector *connector)
|
||||
{
|
||||
struct hdmi_context *hdata = ctx_from_connector(connector);
|
||||
struct hdmi_context *hdata = connector_to_hdmi(connector);
|
||||
|
||||
return &hdata->encoder;
|
||||
}
|
||||
|
@ -1110,70 +1106,17 @@ static bool hdmi_mode_fixup(struct drm_encoder *encoder,
|
|||
return true;
|
||||
}
|
||||
|
||||
static void hdmi_set_acr(u32 freq, u8 *acr)
|
||||
static void hdmi_reg_acr(struct hdmi_context *hdata, u32 freq)
|
||||
{
|
||||
u32 n, cts;
|
||||
|
||||
switch (freq) {
|
||||
case 32000:
|
||||
n = 4096;
|
||||
cts = 27000;
|
||||
break;
|
||||
case 44100:
|
||||
n = 6272;
|
||||
cts = 30000;
|
||||
break;
|
||||
case 88200:
|
||||
n = 12544;
|
||||
cts = 30000;
|
||||
break;
|
||||
case 176400:
|
||||
n = 25088;
|
||||
cts = 30000;
|
||||
break;
|
||||
case 48000:
|
||||
n = 6144;
|
||||
cts = 27000;
|
||||
break;
|
||||
case 96000:
|
||||
n = 12288;
|
||||
cts = 27000;
|
||||
break;
|
||||
case 192000:
|
||||
n = 24576;
|
||||
cts = 27000;
|
||||
break;
|
||||
default:
|
||||
n = 0;
|
||||
cts = 0;
|
||||
break;
|
||||
}
|
||||
cts = (freq % 9) ? 27000 : 30000;
|
||||
n = 128 * freq / (27000000 / cts);
|
||||
|
||||
acr[1] = cts >> 16;
|
||||
acr[2] = cts >> 8 & 0xff;
|
||||
acr[3] = cts & 0xff;
|
||||
|
||||
acr[4] = n >> 16;
|
||||
acr[5] = n >> 8 & 0xff;
|
||||
acr[6] = n & 0xff;
|
||||
}
|
||||
|
||||
static void hdmi_reg_acr(struct hdmi_context *hdata, u8 *acr)
|
||||
{
|
||||
hdmi_reg_writeb(hdata, HDMI_ACR_N0, acr[6]);
|
||||
hdmi_reg_writeb(hdata, HDMI_ACR_N1, acr[5]);
|
||||
hdmi_reg_writeb(hdata, HDMI_ACR_N2, acr[4]);
|
||||
hdmi_reg_writeb(hdata, HDMI_ACR_MCTS0, acr[3]);
|
||||
hdmi_reg_writeb(hdata, HDMI_ACR_MCTS1, acr[2]);
|
||||
hdmi_reg_writeb(hdata, HDMI_ACR_MCTS2, acr[1]);
|
||||
hdmi_reg_writeb(hdata, HDMI_ACR_CTS0, acr[3]);
|
||||
hdmi_reg_writeb(hdata, HDMI_ACR_CTS1, acr[2]);
|
||||
hdmi_reg_writeb(hdata, HDMI_ACR_CTS2, acr[1]);
|
||||
|
||||
if (hdata->drv_data->type == HDMI_TYPE13)
|
||||
hdmi_reg_writeb(hdata, HDMI_V13_ACR_CON, 4);
|
||||
else
|
||||
hdmi_reg_writeb(hdata, HDMI_ACR_CON, 4);
|
||||
hdmi_reg_writev(hdata, HDMI_ACR_N0, 3, n);
|
||||
hdmi_reg_writev(hdata, HDMI_ACR_MCTS0, 3, cts);
|
||||
hdmi_reg_writev(hdata, HDMI_ACR_CTS0, 3, cts);
|
||||
hdmi_reg_writeb(hdata, HDMI_ACR_CON, 4);
|
||||
}
|
||||
|
||||
static void hdmi_audio_init(struct hdmi_context *hdata)
|
||||
|
@ -1181,7 +1124,6 @@ static void hdmi_audio_init(struct hdmi_context *hdata)
|
|||
u32 sample_rate, bits_per_sample;
|
||||
u32 data_num, bit_ch, sample_frq;
|
||||
u32 val;
|
||||
u8 acr[7];
|
||||
|
||||
sample_rate = 44100;
|
||||
bits_per_sample = 16;
|
||||
|
@ -1201,8 +1143,7 @@ static void hdmi_audio_init(struct hdmi_context *hdata)
|
|||
break;
|
||||
}
|
||||
|
||||
hdmi_set_acr(sample_rate, acr);
|
||||
hdmi_reg_acr(hdata, acr);
|
||||
hdmi_reg_acr(hdata, sample_rate);
|
||||
|
||||
hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CON, HDMI_I2S_IN_DISABLE
|
||||
| HDMI_I2S_AUD_I2S | HDMI_I2S_CUV_I2S_ENABLE
|
||||
|
@ -1335,11 +1276,27 @@ static void hdmi_conf_init(struct hdmi_context *hdata)
|
|||
}
|
||||
}
|
||||
|
||||
static void hdmiphy_wait_for_pll(struct hdmi_context *hdata)
|
||||
{
|
||||
int tries;
|
||||
|
||||
for (tries = 0; tries < 10; ++tries) {
|
||||
u32 val = hdmi_reg_read(hdata, HDMI_PHY_STATUS);
|
||||
|
||||
if (val & HDMI_PHY_STATUS_READY) {
|
||||
DRM_DEBUG_KMS("PLL stabilized after %d tries\n", tries);
|
||||
return;
|
||||
}
|
||||
usleep_range(10, 20);
|
||||
}
|
||||
|
||||
DRM_ERROR("PLL could not reach steady state\n");
|
||||
}
|
||||
|
||||
static void hdmi_v13_mode_apply(struct hdmi_context *hdata)
|
||||
{
|
||||
struct drm_display_mode *m = &hdata->current_mode;
|
||||
unsigned int val;
|
||||
int tries;
|
||||
|
||||
hdmi_reg_writev(hdata, HDMI_H_BLANK_0, 2, m->htotal - m->hdisplay);
|
||||
hdmi_reg_writev(hdata, HDMI_V13_H_V_LINE_0, 3,
|
||||
|
@ -1425,32 +1382,11 @@ static void hdmi_v13_mode_apply(struct hdmi_context *hdata)
|
|||
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);
|
||||
|
||||
/* waiting for HDMIPHY's PLL to get to steady state */
|
||||
for (tries = 100; tries; --tries) {
|
||||
u32 val = hdmi_reg_read(hdata, HDMI_V13_PHY_STATUS);
|
||||
if (val & HDMI_PHY_STATUS_READY)
|
||||
break;
|
||||
usleep_range(1000, 2000);
|
||||
}
|
||||
/* steady state not achieved */
|
||||
if (tries == 0) {
|
||||
DRM_ERROR("hdmiphy's pll could not reach steady state.\n");
|
||||
hdmi_regs_dump(hdata, "timing apply");
|
||||
}
|
||||
|
||||
clk_disable_unprepare(hdata->res.sclk_hdmi);
|
||||
clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_hdmiphy);
|
||||
clk_prepare_enable(hdata->res.sclk_hdmi);
|
||||
|
||||
/* enable HDMI and timing generator */
|
||||
hdmi_start(hdata, true);
|
||||
}
|
||||
|
||||
static void hdmi_v14_mode_apply(struct hdmi_context *hdata)
|
||||
{
|
||||
struct drm_display_mode *m = &hdata->current_mode;
|
||||
int tries;
|
||||
|
||||
hdmi_reg_writev(hdata, HDMI_H_BLANK_0, 2, m->htotal - m->hdisplay);
|
||||
hdmi_reg_writev(hdata, HDMI_V_LINE_0, 2, m->vtotal);
|
||||
|
@ -1562,26 +1498,6 @@ static void hdmi_v14_mode_apply(struct hdmi_context *hdata)
|
|||
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);
|
||||
|
||||
/* waiting for HDMIPHY's PLL to get to steady state */
|
||||
for (tries = 100; tries; --tries) {
|
||||
u32 val = hdmi_reg_read(hdata, HDMI_PHY_STATUS_0);
|
||||
if (val & HDMI_PHY_STATUS_READY)
|
||||
break;
|
||||
usleep_range(1000, 2000);
|
||||
}
|
||||
/* steady state not achieved */
|
||||
if (tries == 0) {
|
||||
DRM_ERROR("hdmiphy's pll could not reach steady state.\n");
|
||||
hdmi_regs_dump(hdata, "timing apply");
|
||||
}
|
||||
|
||||
clk_disable_unprepare(hdata->res.sclk_hdmi);
|
||||
clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_hdmiphy);
|
||||
clk_prepare_enable(hdata->res.sclk_hdmi);
|
||||
|
||||
/* enable HDMI and timing generator */
|
||||
hdmi_start(hdata, true);
|
||||
}
|
||||
|
||||
static void hdmi_mode_apply(struct hdmi_context *hdata)
|
||||
|
@ -1590,74 +1506,26 @@ static void hdmi_mode_apply(struct hdmi_context *hdata)
|
|||
hdmi_v13_mode_apply(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)
|
||||
{
|
||||
u32 reg;
|
||||
|
||||
clk_disable_unprepare(hdata->res.sclk_hdmi);
|
||||
clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_pixel);
|
||||
clk_prepare_enable(hdata->res.sclk_hdmi);
|
||||
|
||||
/* operation mode */
|
||||
hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
|
||||
HDMI_PHY_ENABLE_MODE_SET);
|
||||
|
||||
if (hdata->drv_data->type == HDMI_TYPE13)
|
||||
reg = HDMI_V13_PHY_RSTOUT;
|
||||
else
|
||||
reg = HDMI_PHY_RSTOUT;
|
||||
clk_set_parent(hdata->mout_hdmi, hdata->sclk_pixel);
|
||||
|
||||
/* reset hdmiphy */
|
||||
hdmi_reg_writemask(hdata, reg, ~0, HDMI_PHY_SW_RSTOUT);
|
||||
hdmi_reg_writemask(hdata, HDMI_PHY_RSTOUT, ~0, HDMI_PHY_SW_RSTOUT);
|
||||
usleep_range(10000, 12000);
|
||||
hdmi_reg_writemask(hdata, reg, 0, HDMI_PHY_SW_RSTOUT);
|
||||
hdmi_reg_writemask(hdata, HDMI_PHY_RSTOUT, 0, HDMI_PHY_SW_RSTOUT);
|
||||
usleep_range(10000, 12000);
|
||||
}
|
||||
|
||||
static void hdmiphy_poweron(struct hdmi_context *hdata)
|
||||
{
|
||||
if (hdata->drv_data->type != HDMI_TYPE14)
|
||||
return;
|
||||
|
||||
DRM_DEBUG_KMS("\n");
|
||||
|
||||
/* For PHY Mode Setting */
|
||||
hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
|
||||
HDMI_PHY_ENABLE_MODE_SET);
|
||||
/* Phy Power On */
|
||||
hdmiphy_reg_writeb(hdata, HDMIPHY_POWER,
|
||||
HDMI_PHY_POWER_ON);
|
||||
/* For PHY Mode Setting */
|
||||
hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
|
||||
HDMI_PHY_DISABLE_MODE_SET);
|
||||
/* PHY SW Reset */
|
||||
hdmiphy_conf_reset(hdata);
|
||||
}
|
||||
|
||||
static void hdmiphy_poweroff(struct hdmi_context *hdata)
|
||||
{
|
||||
if (hdata->drv_data->type != HDMI_TYPE14)
|
||||
return;
|
||||
|
||||
DRM_DEBUG_KMS("\n");
|
||||
|
||||
/* PHY SW Reset */
|
||||
hdmiphy_conf_reset(hdata);
|
||||
/* For PHY Mode Setting */
|
||||
hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
|
||||
HDMI_PHY_ENABLE_MODE_SET);
|
||||
|
||||
/* PHY Power Off */
|
||||
hdmiphy_reg_writeb(hdata, HDMIPHY_POWER,
|
||||
HDMI_PHY_POWER_OFF);
|
||||
|
||||
/* For PHY Mode Setting */
|
||||
hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
|
||||
HDMI_PHY_DISABLE_MODE_SET);
|
||||
}
|
||||
|
||||
static void hdmiphy_conf_apply(struct hdmi_context *hdata)
|
||||
{
|
||||
int ret;
|
||||
|
@ -1678,14 +1546,6 @@ static void hdmiphy_conf_apply(struct hdmi_context *hdata)
|
|||
}
|
||||
|
||||
usleep_range(10000, 12000);
|
||||
|
||||
ret = hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
|
||||
HDMI_PHY_DISABLE_MODE_SET);
|
||||
if (ret) {
|
||||
DRM_ERROR("failed to enable hdmiphy\n");
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void hdmi_conf_apply(struct hdmi_context *hdata)
|
||||
|
@ -1724,7 +1584,6 @@ static void hdmi_mode_set(struct drm_encoder *encoder,
|
|||
static void hdmi_enable(struct drm_encoder *encoder)
|
||||
{
|
||||
struct hdmi_context *hdata = encoder_to_hdmi(encoder);
|
||||
struct hdmi_resources *res = &hdata->res;
|
||||
|
||||
if (hdata->powered)
|
||||
return;
|
||||
|
@ -1733,24 +1592,22 @@ static void hdmi_enable(struct drm_encoder *encoder)
|
|||
|
||||
pm_runtime_get_sync(hdata->dev);
|
||||
|
||||
if (regulator_bulk_enable(res->regul_count, res->regul_bulk))
|
||||
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);
|
||||
|
||||
clk_prepare_enable(res->hdmi);
|
||||
clk_prepare_enable(res->sclk_hdmi);
|
||||
clk_prepare_enable(hdata->hdmi);
|
||||
clk_prepare_enable(hdata->sclk_hdmi);
|
||||
|
||||
hdmiphy_poweron(hdata);
|
||||
hdmi_conf_apply(hdata);
|
||||
}
|
||||
|
||||
static void hdmi_disable(struct drm_encoder *encoder)
|
||||
{
|
||||
struct hdmi_context *hdata = encoder_to_hdmi(encoder);
|
||||
struct hdmi_resources *res = &hdata->res;
|
||||
struct drm_crtc *crtc = encoder->crtc;
|
||||
const struct drm_crtc_helper_funcs *funcs = NULL;
|
||||
|
||||
|
@ -1774,18 +1631,16 @@ static void hdmi_disable(struct drm_encoder *encoder)
|
|||
/* HDMI System Disable */
|
||||
hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_EN);
|
||||
|
||||
hdmiphy_poweroff(hdata);
|
||||
|
||||
cancel_delayed_work(&hdata->hotplug_work);
|
||||
|
||||
clk_disable_unprepare(res->sclk_hdmi);
|
||||
clk_disable_unprepare(res->hdmi);
|
||||
clk_disable_unprepare(hdata->sclk_hdmi);
|
||||
clk_disable_unprepare(hdata->hdmi);
|
||||
|
||||
/* reset pmu hdmiphy control bit to disable hdmiphy */
|
||||
regmap_update_bits(hdata->pmureg, PMU_HDMI_PHY_CONTROL,
|
||||
PMU_HDMI_PHY_ENABLE_BIT, 0);
|
||||
|
||||
regulator_bulk_disable(res->regul_count, res->regul_bulk);
|
||||
regulator_bulk_disable(ARRAY_SIZE(supply), hdata->regul_bulk);
|
||||
|
||||
pm_runtime_put_sync(hdata->dev);
|
||||
|
||||
|
@ -1826,80 +1681,76 @@ static irqreturn_t hdmi_irq_thread(int irq, void *arg)
|
|||
static int hdmi_resources_init(struct hdmi_context *hdata)
|
||||
{
|
||||
struct device *dev = hdata->dev;
|
||||
struct hdmi_resources *res = &hdata->res;
|
||||
static char *supply[] = {
|
||||
"vdd",
|
||||
"vdd_osc",
|
||||
"vdd_pll",
|
||||
};
|
||||
int i, ret;
|
||||
|
||||
DRM_DEBUG_KMS("HDMI resource init\n");
|
||||
|
||||
hdata->hpd_gpio = devm_gpiod_get(dev, "hpd", GPIOD_IN);
|
||||
if (IS_ERR(hdata->hpd_gpio)) {
|
||||
DRM_ERROR("cannot get hpd gpio property\n");
|
||||
return PTR_ERR(hdata->hpd_gpio);
|
||||
}
|
||||
|
||||
hdata->irq = gpiod_to_irq(hdata->hpd_gpio);
|
||||
if (hdata->irq < 0) {
|
||||
DRM_ERROR("failed to get GPIO irq\n");
|
||||
return hdata->irq;
|
||||
}
|
||||
/* get clocks, power */
|
||||
res->hdmi = devm_clk_get(dev, "hdmi");
|
||||
if (IS_ERR(res->hdmi)) {
|
||||
hdata->hdmi = devm_clk_get(dev, "hdmi");
|
||||
if (IS_ERR(hdata->hdmi)) {
|
||||
DRM_ERROR("failed to get clock 'hdmi'\n");
|
||||
ret = PTR_ERR(res->hdmi);
|
||||
ret = PTR_ERR(hdata->hdmi);
|
||||
goto fail;
|
||||
}
|
||||
res->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi");
|
||||
if (IS_ERR(res->sclk_hdmi)) {
|
||||
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(res->sclk_hdmi);
|
||||
ret = PTR_ERR(hdata->sclk_hdmi);
|
||||
goto fail;
|
||||
}
|
||||
res->sclk_pixel = devm_clk_get(dev, "sclk_pixel");
|
||||
if (IS_ERR(res->sclk_pixel)) {
|
||||
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(res->sclk_pixel);
|
||||
ret = PTR_ERR(hdata->sclk_pixel);
|
||||
goto fail;
|
||||
}
|
||||
res->sclk_hdmiphy = devm_clk_get(dev, "sclk_hdmiphy");
|
||||
if (IS_ERR(res->sclk_hdmiphy)) {
|
||||
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(res->sclk_hdmiphy);
|
||||
ret = PTR_ERR(hdata->sclk_hdmiphy);
|
||||
goto fail;
|
||||
}
|
||||
res->mout_hdmi = devm_clk_get(dev, "mout_hdmi");
|
||||
if (IS_ERR(res->mout_hdmi)) {
|
||||
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(res->mout_hdmi);
|
||||
ret = PTR_ERR(hdata->mout_hdmi);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
clk_set_parent(res->mout_hdmi, res->sclk_pixel);
|
||||
clk_set_parent(hdata->mout_hdmi, hdata->sclk_pixel);
|
||||
|
||||
res->regul_bulk = devm_kzalloc(dev, ARRAY_SIZE(supply) *
|
||||
sizeof(res->regul_bulk[0]), GFP_KERNEL);
|
||||
if (!res->regul_bulk) {
|
||||
ret = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
for (i = 0; i < ARRAY_SIZE(supply); ++i) {
|
||||
res->regul_bulk[i].supply = supply[i];
|
||||
res->regul_bulk[i].consumer = NULL;
|
||||
hdata->regul_bulk[i].supply = supply[i];
|
||||
hdata->regul_bulk[i].consumer = NULL;
|
||||
}
|
||||
ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(supply), res->regul_bulk);
|
||||
ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(supply), hdata->regul_bulk);
|
||||
if (ret) {
|
||||
DRM_ERROR("failed to get regulators\n");
|
||||
return ret;
|
||||
}
|
||||
res->regul_count = ARRAY_SIZE(supply);
|
||||
|
||||
res->reg_hdmi_en = devm_regulator_get(dev, "hdmi-en");
|
||||
if (IS_ERR(res->reg_hdmi_en) && PTR_ERR(res->reg_hdmi_en) != -ENOENT) {
|
||||
DRM_ERROR("failed to get hdmi-en regulator\n");
|
||||
return PTR_ERR(res->reg_hdmi_en);
|
||||
}
|
||||
if (!IS_ERR(res->reg_hdmi_en)) {
|
||||
ret = regulator_enable(res->reg_hdmi_en);
|
||||
if (ret) {
|
||||
DRM_ERROR("failed to enable hdmi-en regulator\n");
|
||||
return ret;
|
||||
}
|
||||
} else
|
||||
res->reg_hdmi_en = NULL;
|
||||
hdata->reg_hdmi_en = devm_regulator_get_optional(dev, "hdmi-en");
|
||||
|
||||
if (PTR_ERR(hdata->reg_hdmi_en) == -ENODEV)
|
||||
return 0;
|
||||
|
||||
if (IS_ERR(hdata->reg_hdmi_en))
|
||||
return PTR_ERR(hdata->reg_hdmi_en);
|
||||
|
||||
ret = regulator_enable(hdata->reg_hdmi_en);
|
||||
if (ret)
|
||||
DRM_ERROR("failed to enable hdmi-en regulator\n");
|
||||
|
||||
return ret;
|
||||
fail:
|
||||
|
@ -1909,9 +1760,6 @@ fail:
|
|||
|
||||
static struct of_device_id hdmi_match_types[] = {
|
||||
{
|
||||
.compatible = "samsung,exynos5-hdmi",
|
||||
.data = &exynos5_hdmi_driver_data,
|
||||
}, {
|
||||
.compatible = "samsung,exynos4210-hdmi",
|
||||
.data = &exynos4210_hdmi_driver_data,
|
||||
}, {
|
||||
|
@ -2009,11 +1857,6 @@ static int hdmi_probe(struct platform_device *pdev)
|
|||
platform_set_drvdata(pdev, hdata);
|
||||
|
||||
hdata->dev = dev;
|
||||
hdata->hpd_gpio = of_get_named_gpio(dev->of_node, "hpd-gpio", 0);
|
||||
if (hdata->hpd_gpio < 0) {
|
||||
DRM_ERROR("cannot get hpd gpio property\n");
|
||||
return hdata->hpd_gpio;
|
||||
}
|
||||
|
||||
ret = hdmi_resources_init(hdata);
|
||||
if (ret) {
|
||||
|
@ -2028,12 +1871,6 @@ static int hdmi_probe(struct platform_device *pdev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
ret = devm_gpio_request(dev, hdata->hpd_gpio, "HPD");
|
||||
if (ret) {
|
||||
DRM_ERROR("failed to request HPD gpio\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ddc_node = hdmi_legacy_ddc_dt_binding(dev);
|
||||
if (ddc_node)
|
||||
goto out_get_ddc_adpt;
|
||||
|
@ -2081,13 +1918,6 @@ out_get_phy_port:
|
|||
}
|
||||
}
|
||||
|
||||
hdata->irq = gpio_to_irq(hdata->hpd_gpio);
|
||||
if (hdata->irq < 0) {
|
||||
DRM_ERROR("failed to get GPIO irq\n");
|
||||
ret = hdata->irq;
|
||||
goto err_hdmiphy;
|
||||
}
|
||||
|
||||
INIT_DELAYED_WORK(&hdata->hotplug_work, hdmi_hotplug_work_func);
|
||||
|
||||
ret = devm_request_threaded_irq(dev, hdata->irq, NULL,
|
||||
|
@ -2133,15 +1963,17 @@ static int hdmi_remove(struct platform_device *pdev)
|
|||
|
||||
cancel_delayed_work_sync(&hdata->hotplug_work);
|
||||
|
||||
if (hdata->res.reg_hdmi_en)
|
||||
regulator_disable(hdata->res.reg_hdmi_en);
|
||||
component_del(&pdev->dev, &hdmi_component_ops);
|
||||
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
|
||||
if (!IS_ERR(hdata->reg_hdmi_en))
|
||||
regulator_disable(hdata->reg_hdmi_en);
|
||||
|
||||
if (hdata->hdmiphy_port)
|
||||
put_device(&hdata->hdmiphy_port->dev);
|
||||
put_device(&hdata->ddc_adpt->dev);
|
||||
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
component_del(&pdev->dev, &hdmi_component_ops);
|
||||
put_device(&hdata->ddc_adpt->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -39,11 +39,10 @@
|
|||
#include "exynos_drm_crtc.h"
|
||||
#include "exynos_drm_plane.h"
|
||||
#include "exynos_drm_iommu.h"
|
||||
#include "exynos_mixer.h"
|
||||
|
||||
#define MIXER_WIN_NR 3
|
||||
#define MIXER_DEFAULT_WIN 0
|
||||
#define VP_DEFAULT_WIN 2
|
||||
#define CURSOR_WIN 1
|
||||
|
||||
/* The pixelformats that are natively supported by the mixer. */
|
||||
#define MXR_FORMAT_RGB565 4
|
||||
|
@ -600,7 +599,7 @@ static void mixer_graph_buffer(struct mixer_context *ctx,
|
|||
|
||||
/* setup display size */
|
||||
if (ctx->mxr_ver == MXR_VER_128_0_0_184 &&
|
||||
win == MIXER_DEFAULT_WIN) {
|
||||
win == DEFAULT_WIN) {
|
||||
val = MXR_MXR_RES_HEIGHT(mode->vdisplay);
|
||||
val |= MXR_MXR_RES_WIDTH(mode->hdisplay);
|
||||
mixer_reg_write(res, MXR_RESOLUTION, val);
|
||||
|
@ -652,7 +651,7 @@ static void vp_win_reset(struct mixer_context *ctx)
|
|||
/* waiting until VP_SRESET_PROCESSING is 0 */
|
||||
if (~vp_reg_read(res, VP_SRESET) & VP_SRESET_PROCESSING)
|
||||
break;
|
||||
usleep_range(10000, 12000);
|
||||
mdelay(10);
|
||||
}
|
||||
WARN(tries == 0, "failed to reset Video Processor\n");
|
||||
}
|
||||
|
@ -1096,8 +1095,10 @@ static void mixer_disable(struct exynos_drm_crtc *crtc)
|
|||
}
|
||||
|
||||
/* Only valid for Mixer version 16.0.33.0 */
|
||||
int mixer_check_mode(struct drm_display_mode *mode)
|
||||
static int mixer_atomic_check(struct exynos_drm_crtc *crtc,
|
||||
struct drm_crtc_state *state)
|
||||
{
|
||||
struct drm_display_mode *mode = &state->adjusted_mode;
|
||||
u32 w, h;
|
||||
|
||||
w = mode->hdisplay;
|
||||
|
@ -1123,6 +1124,7 @@ static const struct exynos_drm_crtc_ops mixer_crtc_ops = {
|
|||
.wait_for_vblank = mixer_wait_for_vblank,
|
||||
.update_plane = mixer_update_plane,
|
||||
.disable_plane = mixer_disable_plane,
|
||||
.atomic_check = mixer_atomic_check,
|
||||
};
|
||||
|
||||
static struct mixer_drv_data exynos5420_mxr_drv_data = {
|
||||
|
@ -1197,8 +1199,6 @@ static int mixer_bind(struct device *dev, struct device *manager, void *data)
|
|||
const uint32_t *formats;
|
||||
unsigned int fcount;
|
||||
|
||||
type = (zpos == MIXER_DEFAULT_WIN) ? DRM_PLANE_TYPE_PRIMARY :
|
||||
DRM_PLANE_TYPE_OVERLAY;
|
||||
if (zpos < VP_DEFAULT_WIN) {
|
||||
formats = mixer_formats;
|
||||
fcount = ARRAY_SIZE(mixer_formats);
|
||||
|
@ -1207,6 +1207,7 @@ static int mixer_bind(struct device *dev, struct device *manager, void *data)
|
|||
fcount = ARRAY_SIZE(vp_formats);
|
||||
}
|
||||
|
||||
type = exynos_plane_get_type(zpos, CURSOR_WIN);
|
||||
ret = exynos_plane_init(drm_dev, &ctx->planes[zpos],
|
||||
1 << ctx->pipe, type, formats, fcount,
|
||||
zpos);
|
||||
|
@ -1214,7 +1215,7 @@ static int mixer_bind(struct device *dev, struct device *manager, void *data)
|
|||
return ret;
|
||||
}
|
||||
|
||||
exynos_plane = &ctx->planes[MIXER_DEFAULT_WIN];
|
||||
exynos_plane = &ctx->planes[DEFAULT_WIN];
|
||||
ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base,
|
||||
ctx->pipe, EXYNOS_DISPLAY_TYPE_HDMI,
|
||||
&mixer_crtc_ops, ctx);
|
||||
|
|
|
@ -1,20 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2013 Google, Inc.
|
||||
*
|
||||
* This software is licensed under the terms of the GNU General Public
|
||||
* License version 2, as published by the Free Software Foundation, and
|
||||
* may be copied, distributed, and modified under those terms.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef _EXYNOS_MIXER_H_
|
||||
#define _EXYNOS_MIXER_H_
|
||||
|
||||
/* This function returns 0 if the given timing is valid for the mixer */
|
||||
int mixer_check_mode(struct drm_display_mode *mode);
|
||||
|
||||
#endif
|
|
@ -72,7 +72,6 @@
|
|||
#define HDMI_V13_V_SYNC_GEN_3_0 HDMI_CORE_BASE(0x0150)
|
||||
#define HDMI_V13_V_SYNC_GEN_3_1 HDMI_CORE_BASE(0x0154)
|
||||
#define HDMI_V13_V_SYNC_GEN_3_2 HDMI_CORE_BASE(0x0158)
|
||||
#define HDMI_V13_ACR_CON HDMI_CORE_BASE(0x0180)
|
||||
#define HDMI_V13_AVI_CON HDMI_CORE_BASE(0x0300)
|
||||
#define HDMI_V13_AVI_BYTE(n) HDMI_CORE_BASE(0x0320 + 4 * (n))
|
||||
#define HDMI_V13_DC_CONTROL HDMI_CORE_BASE(0x05C0)
|
||||
|
@ -171,7 +170,7 @@
|
|||
#define HDMI_HPD_ST HDMI_CTRL_BASE(0x0044)
|
||||
#define HDMI_HPD_TH_X HDMI_CTRL_BASE(0x0050)
|
||||
#define HDMI_AUDIO_CLKSEL HDMI_CTRL_BASE(0x0070)
|
||||
#define HDMI_PHY_RSTOUT HDMI_CTRL_BASE(0x0074)
|
||||
#define HDMI_V14_PHY_RSTOUT HDMI_CTRL_BASE(0x0074)
|
||||
#define HDMI_PHY_VPLL HDMI_CTRL_BASE(0x0078)
|
||||
#define HDMI_PHY_CMU HDMI_CTRL_BASE(0x007C)
|
||||
#define HDMI_CORE_RSTOUT HDMI_CTRL_BASE(0x0080)
|
||||
|
@ -277,16 +276,26 @@
|
|||
#define HDMI_ASP_CHCFG2 HDMI_CORE_BASE(0x0318)
|
||||
#define HDMI_ASP_CHCFG3 HDMI_CORE_BASE(0x031C)
|
||||
|
||||
#define HDMI_ACR_CON HDMI_CORE_BASE(0x0400)
|
||||
#define HDMI_ACR_MCTS0 HDMI_CORE_BASE(0x0410)
|
||||
#define HDMI_ACR_MCTS1 HDMI_CORE_BASE(0x0414)
|
||||
#define HDMI_ACR_MCTS2 HDMI_CORE_BASE(0x0418)
|
||||
#define HDMI_ACR_CTS0 HDMI_CORE_BASE(0x0420)
|
||||
#define HDMI_ACR_CTS1 HDMI_CORE_BASE(0x0424)
|
||||
#define HDMI_ACR_CTS2 HDMI_CORE_BASE(0x0428)
|
||||
#define HDMI_ACR_N0 HDMI_CORE_BASE(0x0430)
|
||||
#define HDMI_ACR_N1 HDMI_CORE_BASE(0x0434)
|
||||
#define HDMI_ACR_N2 HDMI_CORE_BASE(0x0438)
|
||||
#define HDMI_V13_ACR_CON HDMI_CORE_BASE(0x0180)
|
||||
#define HDMI_V13_ACR_MCTS0 HDMI_CORE_BASE(0x0184)
|
||||
#define HDMI_V13_ACR_MCTS1 HDMI_CORE_BASE(0x0188)
|
||||
#define HDMI_V13_ACR_MCTS2 HDMI_CORE_BASE(0x018C)
|
||||
#define HDMI_V13_ACR_CTS0 HDMI_CORE_BASE(0x0190)
|
||||
#define HDMI_V13_ACR_CTS1 HDMI_CORE_BASE(0x0194)
|
||||
#define HDMI_V13_ACR_CTS2 HDMI_CORE_BASE(0x0198)
|
||||
#define HDMI_V13_ACR_N0 HDMI_CORE_BASE(0x01A0)
|
||||
#define HDMI_V13_ACR_N1 HDMI_CORE_BASE(0x01A4)
|
||||
#define HDMI_V13_ACR_N2 HDMI_CORE_BASE(0x01A8)
|
||||
#define HDMI_V14_ACR_CON HDMI_CORE_BASE(0x0400)
|
||||
#define HDMI_V14_ACR_MCTS0 HDMI_CORE_BASE(0x0410)
|
||||
#define HDMI_V14_ACR_MCTS1 HDMI_CORE_BASE(0x0414)
|
||||
#define HDMI_V14_ACR_MCTS2 HDMI_CORE_BASE(0x0418)
|
||||
#define HDMI_V14_ACR_CTS0 HDMI_CORE_BASE(0x0420)
|
||||
#define HDMI_V14_ACR_CTS1 HDMI_CORE_BASE(0x0424)
|
||||
#define HDMI_V14_ACR_CTS2 HDMI_CORE_BASE(0x0428)
|
||||
#define HDMI_V14_ACR_N0 HDMI_CORE_BASE(0x0430)
|
||||
#define HDMI_V14_ACR_N1 HDMI_CORE_BASE(0x0434)
|
||||
#define HDMI_V14_ACR_N2 HDMI_CORE_BASE(0x0438)
|
||||
|
||||
/* Packet related registers */
|
||||
#define HDMI_ACP_CON HDMI_CORE_BASE(0x0500)
|
||||
|
|
|
@ -82,6 +82,8 @@
|
|||
|
||||
/* VIDCON0 */
|
||||
#define VIDCON0_SWRESET (1 << 28)
|
||||
#define VIDCON0_CLKVALUP (1 << 14)
|
||||
#define VIDCON0_VLCKFREE (1 << 5)
|
||||
#define VIDCON0_STOP_STATUS (1 << 2)
|
||||
#define VIDCON0_ENVID (1 << 1)
|
||||
#define VIDCON0_ENVID_F (1 << 0)
|
||||
|
@ -137,6 +139,13 @@
|
|||
/* DECON_UPDATE */
|
||||
#define STANDALONE_UPDATE_F (1 << 0)
|
||||
|
||||
/* DECON_VIDCON1 */
|
||||
#define VIDCON1_VCLK_MASK (0x3 << 9)
|
||||
#define VIDCON1_VCLK_RUN_VDEN_DISABLE (0x3 << 9)
|
||||
#define VIDCON1_VCLK_HOLD (0x0 << 9)
|
||||
#define VIDCON1_VCLK_RUN (0x1 << 9)
|
||||
|
||||
|
||||
/* DECON_VIDTCON00 */
|
||||
#define VIDTCON00_VBPD_F(x) (((x) & 0xfff) << 16)
|
||||
#define VIDTCON00_VFPD_F(x) ((x) & 0xfff)
|
||||
|
@ -159,7 +168,27 @@
|
|||
#define TRIGCON_TRIGEN_PER_F (1 << 31)
|
||||
#define TRIGCON_TRIGEN_F (1 << 30)
|
||||
#define TRIGCON_TE_AUTO_MASK (1 << 29)
|
||||
#define TRIGCON_WB_SWTRIGCMD (1 << 28)
|
||||
#define TRIGCON_SWTRIGCMD_W4BUF (1 << 26)
|
||||
#define TRIGCON_TRIGMODE_W4BUF (1 << 25)
|
||||
#define TRIGCON_SWTRIGCMD_W3BUF (1 << 21)
|
||||
#define TRIGCON_TRIGMODE_W3BUF (1 << 20)
|
||||
#define TRIGCON_SWTRIGCMD_W2BUF (1 << 16)
|
||||
#define TRIGCON_TRIGMODE_W2BUF (1 << 15)
|
||||
#define TRIGCON_SWTRIGCMD_W1BUF (1 << 11)
|
||||
#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_SWTRIGCMD (1 << 1)
|
||||
#define TRIGCON_SWTRIGEN (1 << 0)
|
||||
|
||||
/* DECON_CRCCTRL */
|
||||
#define CRCCTRL_CRCCLKEN (0x1 << 2)
|
||||
#define CRCCTRL_CRCSTART_F (0x1 << 1)
|
||||
#define CRCCTRL_CRCEN (0x1 << 0)
|
||||
#define CRCCTRL_MASK (0x7)
|
||||
|
||||
#endif /* EXYNOS_REGS_DECON_H */
|
||||
|
|
Загрузка…
Ссылка в новой задаче