cregit-Linux how code gets into the kernel

Release 4.11 drivers/gpu/drm/zte/zx_vou.c

/*
 * Copyright 2016 Linaro Ltd.
 * Copyright 2016 ZTE Corporation.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 */

#include <linux/clk.h>
#include <linux/component.h>
#include <linux/of_address.h>
#include <video/videomode.h>

#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_fb_cma_helper.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_gem_cma_helper.h>
#include <drm/drm_of.h>
#include <drm/drm_plane_helper.h>
#include <drm/drmP.h>

#include "zx_drm_drv.h"
#include "zx_plane.h"
#include "zx_vou.h"
#include "zx_vou_regs.h"


#define GL_NUM	2

#define VL_NUM	3


enum vou_chn_type {
	
VOU_CHN_MAIN,
	
VOU_CHN_AUX,
};


struct zx_crtc_regs {
	
u32 fir_active;
	
u32 fir_htiming;
	
u32 fir_vtiming;
	
u32 sec_vtiming;
	
u32 timing_shift;
	
u32 timing_pi_shift;
};


static const struct zx_crtc_regs main_crtc_regs = {
	.fir_active = FIR_MAIN_ACTIVE,
	.fir_htiming = FIR_MAIN_H_TIMING,
	.fir_vtiming = FIR_MAIN_V_TIMING,
	.sec_vtiming = SEC_MAIN_V_TIMING,
	.timing_shift = TIMING_MAIN_SHIFT,
	.timing_pi_shift = TIMING_MAIN_PI_SHIFT,
};


static const struct zx_crtc_regs aux_crtc_regs = {
	.fir_active = FIR_AUX_ACTIVE,
	.fir_htiming = FIR_AUX_H_TIMING,
	.fir_vtiming = FIR_AUX_V_TIMING,
	.sec_vtiming = SEC_AUX_V_TIMING,
	.timing_shift = TIMING_AUX_SHIFT,
	.timing_pi_shift = TIMING_AUX_PI_SHIFT,
};


struct zx_crtc_bits {
	
u32 polarity_mask;
	
u32 polarity_shift;
	
u32 int_frame_mask;
	
u32 tc_enable;
	
u32 sec_vactive_shift;
	
u32 sec_vactive_mask;
	
u32 interlace_select;
	
u32 pi_enable;
	
u32 div_vga_shift;
	
u32 div_pic_shift;
	
u32 div_tvenc_shift;
	
u32 div_hdmi_pnx_shift;
	
u32 div_hdmi_shift;
	
u32 div_inf_shift;
	
u32 div_layer_shift;
};


static const struct zx_crtc_bits main_crtc_bits = {
	.polarity_mask = MAIN_POL_MASK,
	.polarity_shift = MAIN_POL_SHIFT,
	.int_frame_mask = TIMING_INT_MAIN_FRAME,
	.tc_enable = MAIN_TC_EN,
	.sec_vactive_shift = SEC_VACT_MAIN_SHIFT,
	.sec_vactive_mask = SEC_VACT_MAIN_MASK,
	.interlace_select = MAIN_INTERLACE_SEL,
	.pi_enable = MAIN_PI_EN,
	.div_vga_shift = VGA_MAIN_DIV_SHIFT,
	.div_pic_shift = PIC_MAIN_DIV_SHIFT,
	.div_tvenc_shift = TVENC_MAIN_DIV_SHIFT,
	.div_hdmi_pnx_shift = HDMI_MAIN_PNX_DIV_SHIFT,
	.div_hdmi_shift = HDMI_MAIN_DIV_SHIFT,
	.div_inf_shift = INF_MAIN_DIV_SHIFT,
	.div_layer_shift = LAYER_MAIN_DIV_SHIFT,
};


static const struct zx_crtc_bits aux_crtc_bits = {
	.polarity_mask = AUX_POL_MASK,
	.polarity_shift = AUX_POL_SHIFT,
	.int_frame_mask = TIMING_INT_AUX_FRAME,
	.tc_enable = AUX_TC_EN,
	.sec_vactive_shift = SEC_VACT_AUX_SHIFT,
	.sec_vactive_mask = SEC_VACT_AUX_MASK,
	.interlace_select = AUX_INTERLACE_SEL,
	.pi_enable = AUX_PI_EN,
	.div_vga_shift = VGA_AUX_DIV_SHIFT,
	.div_pic_shift = PIC_AUX_DIV_SHIFT,
	.div_tvenc_shift = TVENC_AUX_DIV_SHIFT,
	.div_hdmi_pnx_shift = HDMI_AUX_PNX_DIV_SHIFT,
	.div_hdmi_shift = HDMI_AUX_DIV_SHIFT,
	.div_inf_shift = INF_AUX_DIV_SHIFT,
	.div_layer_shift = LAYER_AUX_DIV_SHIFT,
};


struct zx_crtc {
	
struct drm_crtc crtc;
	
struct drm_plane *primary;
	
struct zx_vou_hw *vou;
	
void __iomem *chnreg;
	
const struct zx_crtc_regs *regs;
	
const struct zx_crtc_bits *bits;
	
enum vou_chn_type chn_type;
	
struct clk *pixclk;
};


#define to_zx_crtc(x) container_of(x, struct zx_crtc, crtc)


struct vou_layer_bits {
	
u32 enable;
	
u32 chnsel;
	
u32 clksel;
};


static const struct vou_layer_bits zx_gl_bits[GL_NUM] = {
	{
		.enable = OSD_CTRL0_GL0_EN,
		.chnsel = OSD_CTRL0_GL0_SEL,
		.clksel = VOU_CLK_GL0_SEL,
        }, {
		.enable = OSD_CTRL0_GL1_EN,
		.chnsel = OSD_CTRL0_GL1_SEL,
		.clksel = VOU_CLK_GL1_SEL,
        },
};


static const struct vou_layer_bits zx_vl_bits[VL_NUM] = {
	{
		.enable = OSD_CTRL0_VL0_EN,
		.chnsel = OSD_CTRL0_VL0_SEL,
		.clksel = VOU_CLK_VL0_SEL,
        }, {
		.enable = OSD_CTRL0_VL1_EN,
		.chnsel = OSD_CTRL0_VL1_SEL,
		.clksel = VOU_CLK_VL1_SEL,
        }, {
		.enable = OSD_CTRL0_VL2_EN,
		.chnsel = OSD_CTRL0_VL2_SEL,
		.clksel = VOU_CLK_VL2_SEL,
        },
};


struct zx_vou_hw {
	
struct device *dev;
	
void __iomem *osd;
	
void __iomem *timing;
	
void __iomem *vouctl;
	
void __iomem *otfppu;
	
void __iomem *dtrc;
	
struct clk *axi_clk;
	
struct clk *ppu_clk;
	
struct clk *main_clk;
	
struct clk *aux_clk;
	
struct zx_crtc *main_crtc;
	
struct zx_crtc *aux_crtc;
};


enum vou_inf_data_sel {
	
VOU_YUV444	= 0,
	
VOU_RGB_101010	= 1,
	
VOU_RGB_888	= 2,
	
VOU_RGB_666	= 3,
};


struct vou_inf {
	
enum vou_inf_id id;
	
enum vou_inf_data_sel data_sel;
	
u32 clocks_en_bits;
	
u32 clocks_sel_bits;
};


static struct vou_inf vou_infs[] = {
	[VOU_HDMI] = {
		.data_sel = VOU_YUV444,
		.clocks_en_bits = BIT(24) | BIT(18) | BIT(6),
		.clocks_sel_bits = BIT(13) | BIT(2),
        },
	[VOU_TV_ENC] = {
		.data_sel = VOU_YUV444,
		.clocks_en_bits = BIT(15),
		.clocks_sel_bits = BIT(11) | BIT(0),
        },
};


static inline struct zx_vou_hw *crtc_to_vou(struct drm_crtc *crtc) { struct zx_crtc *zcrtc = to_zx_crtc(crtc); return zcrtc->vou; }

Contributors

PersonTokensPropCommitsCommitProp
Shawn Guo29100.00%1100.00%
Total29100.00%1100.00%


void vou_inf_hdmi_audio_sel(struct drm_crtc *crtc, enum vou_inf_hdmi_audio aud) { struct zx_crtc *zcrtc = to_zx_crtc(crtc); struct zx_vou_hw *vou = zcrtc->vou; zx_writel_mask(vou->vouctl + VOU_INF_HDMI_CTRL, VOU_HDMI_AUD_MASK, aud); }

Contributors

PersonTokensPropCommitsCommitProp
Shawn Guo46100.00%1100.00%
Total46100.00%1100.00%


void vou_inf_enable(enum vou_inf_id id, struct drm_crtc *crtc) { struct zx_crtc *zcrtc = to_zx_crtc(crtc); struct zx_vou_hw *vou = zcrtc->vou; struct vou_inf *inf = &vou_infs[id]; bool is_main = zcrtc->chn_type == VOU_CHN_MAIN; u32 data_sel_shift = id << 1; /* Select data format */ zx_writel_mask(vou->vouctl + VOU_INF_DATA_SEL, 0x3 << data_sel_shift, inf->data_sel << data_sel_shift); /* Select channel */ zx_writel_mask(vou->vouctl + VOU_INF_CH_SEL, 0x1 << id, zcrtc->chn_type << id); /* Select interface clocks */ zx_writel_mask(vou->vouctl + VOU_CLK_SEL, inf->clocks_sel_bits, is_main ? 0 : inf->clocks_sel_bits); /* Enable interface clocks */ zx_writel_mask(vou->vouctl + VOU_CLK_EN, inf->clocks_en_bits, inf->clocks_en_bits); /* Enable the device */ zx_writel_mask(vou->vouctl + VOU_INF_EN, 1 << id, 1 << id); }

Contributors

PersonTokensPropCommitsCommitProp
Shawn Guo158100.00%2100.00%
Total158100.00%2100.00%


void vou_inf_disable(enum vou_inf_id id, struct drm_crtc *crtc) { struct zx_vou_hw *vou = crtc_to_vou(crtc); struct vou_inf *inf = &vou_infs[id]; /* Disable the device */ zx_writel_mask(vou->vouctl + VOU_INF_EN, 1 << id, 0); /* Disable interface clocks */ zx_writel_mask(vou->vouctl + VOU_CLK_EN, inf->clocks_en_bits, 0); }

Contributors

PersonTokensPropCommitsCommitProp
Shawn Guo67100.00%2100.00%
Total67100.00%2100.00%


void zx_vou_config_dividers(struct drm_crtc *crtc, struct vou_div_config *configs, int num) { struct zx_crtc *zcrtc = to_zx_crtc(crtc); struct zx_vou_hw *vou = zcrtc->vou; const struct zx_crtc_bits *bits = zcrtc->bits; int i; /* Clear update flag bit */ zx_writel_mask(vou->vouctl + VOU_DIV_PARA, DIV_PARA_UPDATE, 0); for (i = 0; i < num; i++) { struct vou_div_config *cfg = configs + i; u32 reg, shift; switch (cfg->id) { case VOU_DIV_VGA: reg = VOU_CLK_SEL; shift = bits->div_vga_shift; break; case VOU_DIV_PIC: reg = VOU_CLK_SEL; shift = bits->div_pic_shift; break; case VOU_DIV_TVENC: reg = VOU_DIV_PARA; shift = bits->div_tvenc_shift; break; case VOU_DIV_HDMI_PNX: reg = VOU_DIV_PARA; shift = bits->div_hdmi_pnx_shift; break; case VOU_DIV_HDMI: reg = VOU_DIV_PARA; shift = bits->div_hdmi_shift; break; case VOU_DIV_INF: reg = VOU_DIV_PARA; shift = bits->div_inf_shift; break; case VOU_DIV_LAYER: reg = VOU_DIV_PARA; shift = bits->div_layer_shift; break; default: continue; } /* Each divider occupies 3 bits */ zx_writel_mask(vou->vouctl + reg, 0x7 << shift, cfg->val << shift); } /* Set update flag bit to get dividers effected */ zx_writel_mask(vou->vouctl + VOU_DIV_PARA, DIV_PARA_UPDATE, DIV_PARA_UPDATE); }

Contributors

PersonTokensPropCommitsCommitProp
Shawn Guo235100.00%2100.00%
Total235100.00%2100.00%


static inline void vou_chn_set_update(struct zx_crtc *zcrtc) { zx_writel(zcrtc->chnreg + CHN_UPDATE, 1); }

Contributors

PersonTokensPropCommitsCommitProp
Shawn Guo23100.00%1100.00%
Total23100.00%1100.00%


static void zx_crtc_enable(struct drm_crtc *crtc) { struct drm_display_mode *mode = &crtc->state->adjusted_mode; bool interlaced = mode->flags & DRM_MODE_FLAG_INTERLACE; struct zx_crtc *zcrtc = to_zx_crtc(crtc); struct zx_vou_hw *vou = zcrtc->vou; const struct zx_crtc_regs *regs = zcrtc->regs; const struct zx_crtc_bits *bits = zcrtc->bits; struct videomode vm; u32 scan_mask; u32 pol = 0; u32 val; int ret; drm_display_mode_to_videomode(mode, &vm); /* Set up timing parameters */ val = V_ACTIVE((interlaced ? vm.vactive / 2 : vm.vactive) - 1); val |= H_ACTIVE(vm.hactive - 1); zx_writel(vou->timing + regs->fir_active, val); val = SYNC_WIDE(vm.hsync_len - 1); val |= BACK_PORCH(vm.hback_porch - 1); val |= FRONT_PORCH(vm.hfront_porch - 1); zx_writel(vou->timing + regs->fir_htiming, val); val = SYNC_WIDE(vm.vsync_len - 1); val |= BACK_PORCH(vm.vback_porch - 1); val |= FRONT_PORCH(vm.vfront_porch - 1); zx_writel(vou->timing + regs->fir_vtiming, val); if (interlaced) { u32 shift = bits->sec_vactive_shift; u32 mask = bits->sec_vactive_mask; val = zx_readl(vou->timing + SEC_V_ACTIVE); val &= ~mask; val |= ((vm.vactive / 2 - 1) << shift) & mask; zx_writel(vou->timing + SEC_V_ACTIVE, val); val = SYNC_WIDE(vm.vsync_len - 1); /* * The vback_porch for the second field needs to shift one on * the value for the first field. */ val |= BACK_PORCH(vm.vback_porch); val |= FRONT_PORCH(vm.vfront_porch - 1); zx_writel(vou->timing + regs->sec_vtiming, val); } /* Set up polarities */ if (vm.flags & DISPLAY_FLAGS_VSYNC_LOW) pol |= 1 << POL_VSYNC_SHIFT; if (vm.flags & DISPLAY_FLAGS_HSYNC_LOW) pol |= 1 << POL_HSYNC_SHIFT; zx_writel_mask(vou->timing + TIMING_CTRL, bits->polarity_mask, pol << bits->polarity_shift); /* Setup SHIFT register by following what ZTE BSP does */ val = H_SHIFT_VAL; if (interlaced) val |= V_SHIFT_VAL << 16; zx_writel(vou->timing + regs->timing_shift, val); zx_writel(vou->timing + regs->timing_pi_shift, H_PI_SHIFT_VAL); /* Progressive or interlace scan select */ scan_mask = bits->interlace_select | bits->pi_enable; zx_writel_mask(vou->timing + SCAN_CTRL, scan_mask, interlaced ? scan_mask : 0); /* Enable TIMING_CTRL */ zx_writel_mask(vou->timing + TIMING_TC_ENABLE, bits->tc_enable, bits->tc_enable); /* Configure channel screen size */ zx_writel_mask(zcrtc->chnreg + CHN_CTRL1, CHN_SCREEN_W_MASK, vm.hactive << CHN_SCREEN_W_SHIFT); zx_writel_mask(zcrtc->chnreg + CHN_CTRL1, CHN_SCREEN_H_MASK, vm.vactive << CHN_SCREEN_H_SHIFT); /* Configure channel interlace buffer control */ zx_writel_mask(zcrtc->chnreg + CHN_INTERLACE_BUF_CTRL, CHN_INTERLACE_EN, interlaced ? CHN_INTERLACE_EN : 0); /* Update channel */ vou_chn_set_update(zcrtc); /* Enable channel */ zx_writel_mask(zcrtc->chnreg + CHN_CTRL0, CHN_ENABLE, CHN_ENABLE); drm_crtc_vblank_on(crtc); ret = clk_set_rate(zcrtc->pixclk, mode->clock * 1000); if (ret) { DRM_DEV_ERROR(vou->dev, "failed to set pixclk rate: %d\n", ret); return; } ret = clk_prepare_enable(zcrtc->pixclk); if (ret) DRM_DEV_ERROR(vou->dev, "failed to enable pixclk: %d\n", ret); }

Contributors

PersonTokensPropCommitsCommitProp
Shawn Guo615100.00%2100.00%
Total615100.00%2100.00%


static void zx_crtc_disable(struct drm_crtc *crtc) { struct zx_crtc *zcrtc = to_zx_crtc(crtc); const struct zx_crtc_bits *bits = zcrtc->bits; struct zx_vou_hw *vou = zcrtc->vou; clk_disable_unprepare(zcrtc->pixclk); drm_crtc_vblank_off(crtc); /* Disable channel */ zx_writel_mask(zcrtc->chnreg + CHN_CTRL0, CHN_ENABLE, 0); /* Disable TIMING_CTRL */ zx_writel_mask(vou->timing + TIMING_TC_ENABLE, bits->tc_enable, 0); }

Contributors

PersonTokensPropCommitsCommitProp
Shawn Guo82100.00%1100.00%
Total82100.00%1100.00%


static void zx_crtc_atomic_flush(struct drm_crtc *crtc, struct drm_crtc_state *old_state) { struct drm_pending_vblank_event *event = crtc->state->event; if (!event) return; crtc->state->event = NULL; spin_lock_irq(&crtc->dev->event_lock); if (drm_crtc_vblank_get(crtc) == 0) drm_crtc_arm_vblank_event(crtc, event); else drm_crtc_send_vblank_event(crtc, event); spin_unlock_irq(&crtc->dev->event_lock); }

Contributors

PersonTokensPropCommitsCommitProp
Shawn Guo85100.00%1100.00%
Total85100.00%1100.00%

static const struct drm_crtc_helper_funcs zx_crtc_helper_funcs = { .enable = zx_crtc_enable, .disable = zx_crtc_disable, .atomic_flush = zx_crtc_atomic_flush, }; static const struct drm_crtc_funcs zx_crtc_funcs = { .destroy = drm_crtc_cleanup, .set_config = drm_atomic_helper_set_config, .page_flip = drm_atomic_helper_page_flip, .reset = drm_atomic_helper_crtc_reset, .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, };
static int zx_crtc_init(struct drm_device *drm, struct zx_vou_hw *vou, enum vou_chn_type chn_type) { struct device *dev = vou->dev; struct zx_plane *zplane; struct zx_crtc *zcrtc; int ret; zcrtc = devm_kzalloc(dev, sizeof(*zcrtc), GFP_KERNEL); if (!zcrtc) return -ENOMEM; zcrtc->vou = vou; zcrtc->chn_type = chn_type; zplane = devm_kzalloc(dev, sizeof(*zplane), GFP_KERNEL); if (!zplane) return -ENOMEM; zplane->dev = dev; if (chn_type == VOU_CHN_MAIN) { zplane->layer = vou->osd + MAIN_GL_OFFSET; zplane->csc = vou->osd + MAIN_CSC_OFFSET; zplane->hbsc = vou->osd + MAIN_HBSC_OFFSET; zplane->rsz = vou->otfppu + MAIN_RSZ_OFFSET; zplane->bits = &zx_gl_bits[0]; zcrtc->chnreg = vou->osd + OSD_MAIN_CHN; zcrtc->regs = &main_crtc_regs; zcrtc->bits = &main_crtc_bits; } else { zplane->layer = vou->osd + AUX_GL_OFFSET; zplane->csc = vou->osd + AUX_CSC_OFFSET; zplane->hbsc = vou->osd + AUX_HBSC_OFFSET; zplane->rsz = vou->otfppu + AUX_RSZ_OFFSET; zplane->bits = &zx_gl_bits[1]; zcrtc->chnreg = vou->osd + OSD_AUX_CHN; zcrtc->regs = &aux_crtc_regs; zcrtc->bits = &aux_crtc_bits; } zcrtc->pixclk = devm_clk_get(dev, (chn_type == VOU_CHN_MAIN) ? "main_wclk" : "aux_wclk"); if (IS_ERR(zcrtc->pixclk)) { ret = PTR_ERR(zcrtc->pixclk); DRM_DEV_ERROR(dev, "failed to get pix clk: %d\n", ret); return ret; } ret = zx_plane_init(drm, zplane, DRM_PLANE_TYPE_PRIMARY); if (ret) { DRM_DEV_ERROR(dev, "failed to init primary plane: %d\n", ret); return ret; } zcrtc->primary = &zplane->plane; ret = drm_crtc_init_with_planes(drm, &zcrtc->crtc, zcrtc->primary, NULL, &zx_crtc_funcs, NULL); if (ret) { DRM_DEV_ERROR(dev, "failed to init drm crtc: %d\n", ret); return ret; } drm_crtc_helper_add(&zcrtc->crtc, &zx_crtc_helper_funcs); if (chn_type == VOU_CHN_MAIN) vou->main_crtc = zcrtc; else vou->aux_crtc = zcrtc; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Shawn Guo430100.00%3100.00%
Total430100.00%3100.00%


int zx_vou_enable_vblank(struct drm_device *drm, unsigned int pipe) { struct drm_crtc *crtc; struct zx_crtc *zcrtc; struct zx_vou_hw *vou; u32 int_frame_mask; crtc = drm_crtc_from_index(drm, pipe); if (!crtc) return 0; vou = crtc_to_vou(crtc); zcrtc = to_zx_crtc(crtc); int_frame_mask = zcrtc->bits->int_frame_mask; zx_writel_mask(vou->timing + TIMING_INT_CTRL, int_frame_mask, int_frame_mask); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Shawn Guo8698.85%150.00%
Dave Airlie11.15%150.00%
Total87100.00%2100.00%


void zx_vou_disable_vblank(struct drm_device *drm, unsigned int pipe) { struct drm_crtc *crtc; struct zx_crtc *zcrtc; struct zx_vou_hw *vou; crtc = drm_crtc_from_index(drm, pipe); if (!crtc) return; vou = crtc_to_vou(crtc); zcrtc = to_zx_crtc(crtc); zx_writel_mask(vou->timing + TIMING_INT_CTRL, zcrtc->bits->int_frame_mask, 0); }

Contributors

PersonTokensPropCommitsCommitProp
Shawn Guo7498.67%150.00%
Dave Airlie11.33%150.00%
Total75100.00%2100.00%


void zx_vou_layer_enable(struct drm_plane *plane) { struct zx_crtc *zcrtc = to_zx_crtc(plane->state->crtc); struct zx_vou_hw *vou = zcrtc->vou; struct zx_plane *zplane = to_zx_plane(plane); const struct vou_layer_bits *bits = zplane->bits; if (zcrtc->chn_type == VOU_CHN_MAIN) { zx_writel_mask(vou->osd + OSD_CTRL0, bits->chnsel, 0); zx_writel_mask(vou->vouctl + VOU_CLK_SEL, bits->clksel, 0); } else { zx_writel_mask(vou->osd + OSD_CTRL0, bits->chnsel, bits->chnsel); zx_writel_mask(vou->vouctl + VOU_CLK_SEL, bits->clksel, bits->clksel); } zx_writel_mask(vou->osd + OSD_CTRL0, bits->enable, bits->enable); }

Contributors

PersonTokensPropCommitsCommitProp
Shawn Guo147100.00%1100.00%
Total147100.00%1100.00%


void zx_vou_layer_disable(struct drm_plane *plane) { struct zx_crtc *zcrtc = to_zx_crtc(plane->crtc); struct zx_vou_hw *vou = zcrtc->vou; struct zx_plane *zplane = to_zx_plane(plane); const struct vou_layer_bits *bits = zplane->bits; zx_writel_mask(vou->osd + OSD_CTRL0, bits->enable, 0); }

Contributors

PersonTokensPropCommitsCommitProp
Shawn Guo66100.00%1100.00%
Total66100.00%1100.00%


static void zx_overlay_init(struct drm_device *drm, struct zx_vou_hw *vou) { struct device *dev = vou->dev; struct zx_plane *zplane; int i; int ret; /* * VL0 has some quirks on scaling support which need special handling. * Let's leave it out for now. */ for (i = 1; i < VL_NUM; i++) { zplane = devm_kzalloc(dev, sizeof(*zplane), GFP_KERNEL); if (!zplane) { DRM_DEV_ERROR(dev, "failed to allocate zplane %d\n", i); return; } zplane->layer = vou->osd + OSD_VL_OFFSET(i); zplane->hbsc = vou->osd + HBSC_VL_OFFSET(i); zplane->rsz = vou->otfppu + RSZ_VL_OFFSET(i); zplane->bits = &zx_vl_bits[i]; ret = zx_plane_init(drm, zplane, DRM_PLANE_TYPE_OVERLAY); if (ret) { DRM_DEV_ERROR(dev, "failed to init overlay %d\n", i); continue; } } }

Contributors

PersonTokensPropCommitsCommitProp
Shawn Guo160100.00%2100.00%
Total160100.00%2100.00%


static inline void zx_osd_int_update(struct zx_crtc *zcrtc) { struct drm_crtc *crtc = &zcrtc->crtc; struct drm_plane *plane; vou_chn_set_update(zcrtc); drm_for_each_plane_mask(plane, crtc->dev, crtc->state->plane_mask) zx_plane_set_update(plane); }

Contributors

PersonTokensPropCommitsCommitProp
Shawn Guo45100.00%2100.00%
Total45100.00%2100.00%


static irqreturn_t vou_irq_handler(int irq, void *dev_id) { struct zx_vou_hw *vou = dev_id; u32 state; /* Handle TIMING_CTRL frame interrupts */ state = zx_readl(vou->timing + TIMING_INT_STATE); zx_writel(vou->timing + TIMING_INT_STATE, state); if (state & TIMING_INT_MAIN_FRAME) drm_crtc_handle_vblank(&vou->main_crtc->crtc); if (state & TIMING_INT_AUX_FRAME) drm_crtc_handle_vblank(&vou->aux_crtc->crtc); /* Handle OSD interrupts */ state = zx_readl(vou->osd + OSD_INT_STA); zx_writel(vou->osd + OSD_INT_CLRSTA, state); if (state & OSD_INT_MAIN_UPT) zx_osd_int_update(vou->main_crtc); if (state & OSD_INT_AUX_UPT) zx_osd_int_update(vou->aux_crtc); if (state & OSD_INT_ERROR) DRM_DEV_ERROR(vou->dev, "OSD ERROR: 0x%08x!\n", state); return IRQ_HANDLED; }

Contributors

PersonTokensPropCommitsCommitProp
Shawn Guo147100.00%2100.00%
Total147100.00%2100.00%


static void vou_dtrc_init(struct zx_vou_hw *vou) { /* Clear bit for bypass by ID */ zx_writel_mask(vou->dtrc + DTRC_DETILE_CTRL, TILE2RASTESCAN_BYPASS_MODE, 0); /* Select ARIDR mode */ zx_writel_mask(vou->dtrc + DTRC_DETILE_CTRL, DETILE_ARIDR_MODE_MASK, DETILE_ARID_IN_ARIDR); /* Bypass decompression for both frames */ zx_writel_mask(vou->dtrc + DTRC_F0_CTRL, DTRC_DECOMPRESS_BYPASS, DTRC_DECOMPRESS_BYPASS); zx_writel_mask(vou->dtrc + DTRC_F1_CTRL, DTRC_DECOMPRESS_BYPASS, DTRC_DECOMPRESS_BYPASS); /* Set up ARID register */ zx_writel(vou->dtrc + DTRC_ARID, DTRC_ARID3(0xf) | DTRC_ARID2(0xe) | DTRC_ARID1(0xf) | DTRC_ARID0(0xe)); }

Contributors

PersonTokensPropCommitsCommitProp
Shawn Guo96100.00%1100.00%
Total96100.00%1100.00%


static void vou_hw_init(struct zx_vou_hw *vou) { /* Release reset for all VOU modules */ zx_writel(vou->vouctl + VOU_SOFT_RST, ~0); /* Enable clock auto-gating for all VOU modules */ zx_writel(vou->vouctl + VOU_CLK_REQEN, ~0); /* Enable all VOU module clocks */ zx_writel(vou->vouctl + VOU_CLK_EN, ~0); /* Clear both OSD and TIMING_CTRL interrupt state */ zx_writel(vou->osd + OSD_INT_CLRSTA, ~0); zx_writel(vou->timing + TIMING_INT_STATE, ~0); /* Enable OSD and TIMING_CTRL interrrupts */ zx_writel(vou->osd + OSD_INT_MSK, OSD_INT_ENABLE); zx_writel(vou->timing + TIMING_INT_CTRL, TIMING_INT_ENABLE); /* Select GPC as input to gl/vl scaler as a sane default setting */ zx_writel(vou->otfppu + OTFPPU_RSZ_DATA_SOURCE, 0x2a); /* * Needs to reset channel and layer logic per frame when frame starts * to get VOU work properly. */ zx_writel_mask(vou->osd + OSD_RST_CLR, RST_PER_FRAME, RST_PER_FRAME); vou_dtrc_init(vou); }

Contributors

PersonTokensPropCommitsCommitProp
Shawn Guo129100.00%1100.00%
Total129100.00%1100.00%


static int zx_crtc_bind(struct device *dev, struct device *master, void *data) { struct platform_device *pdev = to_platform_device(dev); struct drm_device *drm = data; struct zx_vou_hw *vou; struct resource *res; int irq; int ret; vou = devm_kzalloc(dev, sizeof(*vou), GFP_KERNEL); if (!vou) return -ENOMEM; res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "osd"); vou->osd = devm_ioremap_resource(dev, res); if (IS_ERR(vou->osd)) { ret = PTR_ERR(vou->osd); DRM_DEV_ERROR(dev, "failed to remap osd region: %d\n", ret); return ret; } res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "timing_ctrl"); vou->timing = devm_ioremap_resource(dev, res); if (IS_ERR(vou->timing)) { ret = PTR_ERR(vou->timing); DRM_DEV_ERROR(dev, "failed to remap timing_ctrl region: %d\n", ret); return ret; } res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dtrc"); vou->dtrc = devm_ioremap_resource(dev, res); if (IS_ERR(vou->dtrc)) { ret = PTR_ERR(vou->dtrc); DRM_DEV_ERROR(dev, "failed to remap dtrc region: %d\n", ret); return ret; } res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vou_ctrl"); vou->vouctl = devm_ioremap_resource(dev, res); if (IS_ERR(vou->vouctl)) { ret = PTR_ERR(vou->vouctl); DRM_DEV_ERROR(dev, "failed to remap vou_ctrl region: %d\n", ret); return ret; } res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "otfppu"); vou->otfppu = devm_ioremap_resource(dev, res); if (IS_ERR(vou->otfppu)) { ret = PTR_ERR(vou->otfppu); DRM_DEV_ERROR(dev, "failed to remap otfppu region: %d\n", ret); return ret; } irq = platform_get_irq(pdev, 0); if (irq < 0) return irq; vou->axi_clk = devm_clk_get(dev, "aclk"); if (IS_ERR(vou->axi_clk)) { ret = PTR_ERR(vou->axi_clk); DRM_DEV_ERROR(dev, "failed to get axi_clk: %d\n", ret); return ret; } vou->ppu_clk = devm_clk_get(dev, "ppu_wclk"); if (IS_ERR(vou->ppu_clk)) { ret = PTR_ERR(vou->ppu_clk); DRM_DEV_ERROR(dev, "failed to get ppu_clk: %d\n", ret); return ret; } ret = clk_prepare_enable(vou->axi_clk); if (ret) { DRM_DEV_ERROR(dev, "failed to enable axi_clk: %d\n", ret); return ret; } clk_prepare_enable(vou->ppu_clk); if (ret) { DRM_DEV_ERROR(dev, "failed to enable ppu_clk: %d\n", ret); goto disable_axi_clk; } vou->dev = dev; dev_set_drvdata(dev, vou); vou_hw_init(vou); ret = devm_request_irq(dev, irq, vou_irq_handler, 0, "zx_vou", vou); if (ret < 0) { DRM_DEV_ERROR(dev, "failed to request vou irq: %d\n", ret); goto disable_ppu_clk; } ret = zx_crtc_init(drm, vou, VOU_CHN_MAIN); if (ret) { DRM_DEV_ERROR(dev, "failed to init main channel crtc: %d\n", ret); goto disable_ppu_clk; } ret = zx_crtc_init(drm, vou, VOU_CHN_AUX); if (ret) { DRM_DEV_ERROR(dev, "failed to init aux channel crtc: %d\n", ret); goto disable_ppu_clk; } zx_overlay_init(drm, vou); return 0; disable_ppu_clk: clk_disable_unprepare(vou->ppu_clk); disable_axi_clk: clk_disable_unprepare(vou->axi_clk); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Shawn Guo647100.00%2100.00%
Total647100.00%2100.00%


static void zx_crtc_unbind(struct device *dev, struct device *master, void *data) { struct zx_vou_hw *vou = dev_get_drvdata(dev); clk_disable_unprepare(vou->axi_clk); clk_disable_unprepare(vou->ppu_clk); }

Contributors

PersonTokensPropCommitsCommitProp
Shawn Guo44100.00%1100.00%
Total44100.00%1100.00%

static const struct component_ops zx_crtc_component_ops = { .bind = zx_crtc_bind, .unbind = zx_crtc_unbind, };
static int zx_crtc_probe(struct platform_device *pdev) { return component_add(&pdev->dev, &zx_crtc_component_ops); }

Contributors

PersonTokensPropCommitsCommitProp
Shawn Guo23100.00%1100.00%
Total23100.00%1100.00%


static int zx_crtc_remove(struct platform_device *pdev) { component_del(&pdev->dev, &zx_crtc_component_ops); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Shawn Guo25100.00%1100.00%
Total25100.00%1100.00%

static const struct of_device_id zx_crtc_of_match[] = { { .compatible = "zte,zx296718-dpc", }, { /* end */ }, }; MODULE_DEVICE_TABLE(of, zx_crtc_of_match); struct platform_driver zx_crtc_driver = { .probe = zx_crtc_probe, .remove = zx_crtc_remove, .driver = { .name = "zx-crtc", .of_match_table = zx_crtc_of_match, }, };

Overall Contributors

PersonTokensPropCommitsCommitProp
Shawn Guo433899.95%990.00%
Dave Airlie20.05%110.00%
Total4340100.00%10100.00%
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.