162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2017 Free Electrons 462306a36Sopenharmony_ci * Maxime Ripard <maxime.ripard@free-electrons.com> 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <linux/clk.h> 862306a36Sopenharmony_ci#include <linux/component.h> 962306a36Sopenharmony_ci#include <linux/module.h> 1062306a36Sopenharmony_ci#include <linux/of.h> 1162306a36Sopenharmony_ci#include <linux/platform_device.h> 1262306a36Sopenharmony_ci#include <linux/pm_runtime.h> 1362306a36Sopenharmony_ci#include <linux/regmap.h> 1462306a36Sopenharmony_ci#include <linux/reset.h> 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#include <drm/drm_device.h> 1762306a36Sopenharmony_ci#include <drm/drm_fb_dma_helper.h> 1862306a36Sopenharmony_ci#include <drm/drm_fourcc.h> 1962306a36Sopenharmony_ci#include <drm/drm_framebuffer.h> 2062306a36Sopenharmony_ci#include <drm/drm_gem_dma_helper.h> 2162306a36Sopenharmony_ci#include <drm/drm_plane.h> 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#include "sun4i_drv.h" 2462306a36Sopenharmony_ci#include "sun4i_frontend.h" 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_cistatic const u32 sun4i_frontend_vert_coef[32] = { 2762306a36Sopenharmony_ci 0x00004000, 0x000140ff, 0x00033ffe, 0x00043ffd, 2862306a36Sopenharmony_ci 0x00063efc, 0xff083dfc, 0x000a3bfb, 0xff0d39fb, 2962306a36Sopenharmony_ci 0xff0f37fb, 0xff1136fa, 0xfe1433fb, 0xfe1631fb, 3062306a36Sopenharmony_ci 0xfd192ffb, 0xfd1c2cfb, 0xfd1f29fb, 0xfc2127fc, 3162306a36Sopenharmony_ci 0xfc2424fc, 0xfc2721fc, 0xfb291ffd, 0xfb2c1cfd, 3262306a36Sopenharmony_ci 0xfb2f19fd, 0xfb3116fe, 0xfb3314fe, 0xfa3611ff, 3362306a36Sopenharmony_ci 0xfb370fff, 0xfb390dff, 0xfb3b0a00, 0xfc3d08ff, 3462306a36Sopenharmony_ci 0xfc3e0600, 0xfd3f0400, 0xfe3f0300, 0xff400100, 3562306a36Sopenharmony_ci}; 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_cistatic const u32 sun4i_frontend_horz_coef[64] = { 3862306a36Sopenharmony_ci 0x40000000, 0x00000000, 0x40fe0000, 0x0000ff03, 3962306a36Sopenharmony_ci 0x3ffd0000, 0x0000ff05, 0x3ffc0000, 0x0000ff06, 4062306a36Sopenharmony_ci 0x3efb0000, 0x0000ff08, 0x3dfb0000, 0x0000ff09, 4162306a36Sopenharmony_ci 0x3bfa0000, 0x0000fe0d, 0x39fa0000, 0x0000fe0f, 4262306a36Sopenharmony_ci 0x38fa0000, 0x0000fe10, 0x36fa0000, 0x0000fe12, 4362306a36Sopenharmony_ci 0x33fa0000, 0x0000fd16, 0x31fa0000, 0x0000fd18, 4462306a36Sopenharmony_ci 0x2ffa0000, 0x0000fd1a, 0x2cfa0000, 0x0000fc1e, 4562306a36Sopenharmony_ci 0x29fa0000, 0x0000fc21, 0x27fb0000, 0x0000fb23, 4662306a36Sopenharmony_ci 0x24fb0000, 0x0000fb26, 0x21fb0000, 0x0000fb29, 4762306a36Sopenharmony_ci 0x1ffc0000, 0x0000fa2b, 0x1cfc0000, 0x0000fa2e, 4862306a36Sopenharmony_ci 0x19fd0000, 0x0000fa30, 0x16fd0000, 0x0000fa33, 4962306a36Sopenharmony_ci 0x14fd0000, 0x0000fa35, 0x11fe0000, 0x0000fa37, 5062306a36Sopenharmony_ci 0x0ffe0000, 0x0000fa39, 0x0dfe0000, 0x0000fa3b, 5162306a36Sopenharmony_ci 0x0afe0000, 0x0000fa3e, 0x08ff0000, 0x0000fb3e, 5262306a36Sopenharmony_ci 0x06ff0000, 0x0000fb40, 0x05ff0000, 0x0000fc40, 5362306a36Sopenharmony_ci 0x03ff0000, 0x0000fd41, 0x01ff0000, 0x0000fe42, 5462306a36Sopenharmony_ci}; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci/* 5762306a36Sopenharmony_ci * These coefficients are taken from the A33 BSP from Allwinner. 5862306a36Sopenharmony_ci * 5962306a36Sopenharmony_ci * The first three values of each row are coded as 13-bit signed fixed-point 6062306a36Sopenharmony_ci * numbers, with 10 bits for the fractional part. The fourth value is a 6162306a36Sopenharmony_ci * constant coded as a 14-bit signed fixed-point number with 4 bits for the 6262306a36Sopenharmony_ci * fractional part. 6362306a36Sopenharmony_ci * 6462306a36Sopenharmony_ci * The values in table order give the following colorspace translation: 6562306a36Sopenharmony_ci * G = 1.164 * Y - 0.391 * U - 0.813 * V + 135 6662306a36Sopenharmony_ci * R = 1.164 * Y + 1.596 * V - 222 6762306a36Sopenharmony_ci * B = 1.164 * Y + 2.018 * U + 276 6862306a36Sopenharmony_ci * 6962306a36Sopenharmony_ci * This seems to be a conversion from Y[16:235] UV[16:240] to RGB[0:255], 7062306a36Sopenharmony_ci * following the BT601 spec. 7162306a36Sopenharmony_ci */ 7262306a36Sopenharmony_ciconst u32 sunxi_bt601_yuv2rgb_coef[12] = { 7362306a36Sopenharmony_ci 0x000004a7, 0x00001e6f, 0x00001cbf, 0x00000877, 7462306a36Sopenharmony_ci 0x000004a7, 0x00000000, 0x00000662, 0x00003211, 7562306a36Sopenharmony_ci 0x000004a7, 0x00000812, 0x00000000, 0x00002eb1, 7662306a36Sopenharmony_ci}; 7762306a36Sopenharmony_ciEXPORT_SYMBOL(sunxi_bt601_yuv2rgb_coef); 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_cistatic void sun4i_frontend_scaler_init(struct sun4i_frontend *frontend) 8062306a36Sopenharmony_ci{ 8162306a36Sopenharmony_ci int i; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci if (frontend->data->has_coef_access_ctrl) 8462306a36Sopenharmony_ci regmap_write_bits(frontend->regs, SUN4I_FRONTEND_FRM_CTRL_REG, 8562306a36Sopenharmony_ci SUN4I_FRONTEND_FRM_CTRL_COEF_ACCESS_CTRL, 8662306a36Sopenharmony_ci SUN4I_FRONTEND_FRM_CTRL_COEF_ACCESS_CTRL); 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci for (i = 0; i < 32; i++) { 8962306a36Sopenharmony_ci regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_HORZCOEF0_REG(i), 9062306a36Sopenharmony_ci sun4i_frontend_horz_coef[2 * i]); 9162306a36Sopenharmony_ci regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_HORZCOEF0_REG(i), 9262306a36Sopenharmony_ci sun4i_frontend_horz_coef[2 * i]); 9362306a36Sopenharmony_ci regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_HORZCOEF1_REG(i), 9462306a36Sopenharmony_ci sun4i_frontend_horz_coef[2 * i + 1]); 9562306a36Sopenharmony_ci regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_HORZCOEF1_REG(i), 9662306a36Sopenharmony_ci sun4i_frontend_horz_coef[2 * i + 1]); 9762306a36Sopenharmony_ci regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_VERTCOEF_REG(i), 9862306a36Sopenharmony_ci sun4i_frontend_vert_coef[i]); 9962306a36Sopenharmony_ci regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_VERTCOEF_REG(i), 10062306a36Sopenharmony_ci sun4i_frontend_vert_coef[i]); 10162306a36Sopenharmony_ci } 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci if (frontend->data->has_coef_rdy) 10462306a36Sopenharmony_ci regmap_write_bits(frontend->regs, 10562306a36Sopenharmony_ci SUN4I_FRONTEND_FRM_CTRL_REG, 10662306a36Sopenharmony_ci SUN4I_FRONTEND_FRM_CTRL_COEF_RDY, 10762306a36Sopenharmony_ci SUN4I_FRONTEND_FRM_CTRL_COEF_RDY); 10862306a36Sopenharmony_ci} 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ciint sun4i_frontend_init(struct sun4i_frontend *frontend) 11162306a36Sopenharmony_ci{ 11262306a36Sopenharmony_ci return pm_runtime_get_sync(frontend->dev); 11362306a36Sopenharmony_ci} 11462306a36Sopenharmony_ciEXPORT_SYMBOL(sun4i_frontend_init); 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_civoid sun4i_frontend_exit(struct sun4i_frontend *frontend) 11762306a36Sopenharmony_ci{ 11862306a36Sopenharmony_ci pm_runtime_put(frontend->dev); 11962306a36Sopenharmony_ci} 12062306a36Sopenharmony_ciEXPORT_SYMBOL(sun4i_frontend_exit); 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_cistatic bool sun4i_frontend_format_chroma_requires_swap(uint32_t fmt) 12362306a36Sopenharmony_ci{ 12462306a36Sopenharmony_ci switch (fmt) { 12562306a36Sopenharmony_ci case DRM_FORMAT_YVU411: 12662306a36Sopenharmony_ci case DRM_FORMAT_YVU420: 12762306a36Sopenharmony_ci case DRM_FORMAT_YVU422: 12862306a36Sopenharmony_ci case DRM_FORMAT_YVU444: 12962306a36Sopenharmony_ci return true; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci default: 13262306a36Sopenharmony_ci return false; 13362306a36Sopenharmony_ci } 13462306a36Sopenharmony_ci} 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_cistatic bool sun4i_frontend_format_supports_tiling(uint32_t fmt) 13762306a36Sopenharmony_ci{ 13862306a36Sopenharmony_ci switch (fmt) { 13962306a36Sopenharmony_ci case DRM_FORMAT_NV12: 14062306a36Sopenharmony_ci case DRM_FORMAT_NV16: 14162306a36Sopenharmony_ci case DRM_FORMAT_NV21: 14262306a36Sopenharmony_ci case DRM_FORMAT_NV61: 14362306a36Sopenharmony_ci case DRM_FORMAT_YUV411: 14462306a36Sopenharmony_ci case DRM_FORMAT_YUV420: 14562306a36Sopenharmony_ci case DRM_FORMAT_YUV422: 14662306a36Sopenharmony_ci case DRM_FORMAT_YVU420: 14762306a36Sopenharmony_ci case DRM_FORMAT_YVU422: 14862306a36Sopenharmony_ci case DRM_FORMAT_YVU411: 14962306a36Sopenharmony_ci return true; 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci default: 15262306a36Sopenharmony_ci return false; 15362306a36Sopenharmony_ci } 15462306a36Sopenharmony_ci} 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_civoid sun4i_frontend_update_buffer(struct sun4i_frontend *frontend, 15762306a36Sopenharmony_ci struct drm_plane *plane) 15862306a36Sopenharmony_ci{ 15962306a36Sopenharmony_ci struct drm_plane_state *state = plane->state; 16062306a36Sopenharmony_ci struct drm_framebuffer *fb = state->fb; 16162306a36Sopenharmony_ci unsigned int strides[3] = {}; 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci dma_addr_t dma_addr; 16462306a36Sopenharmony_ci bool swap; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci if (fb->modifier == DRM_FORMAT_MOD_ALLWINNER_TILED) { 16762306a36Sopenharmony_ci unsigned int width = state->src_w >> 16; 16862306a36Sopenharmony_ci unsigned int offset; 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci strides[0] = SUN4I_FRONTEND_LINESTRD_TILED(fb->pitches[0]); 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci /* 17362306a36Sopenharmony_ci * The X1 offset is the offset to the bottom-right point in the 17462306a36Sopenharmony_ci * end tile, which is the final pixel (at offset width - 1) 17562306a36Sopenharmony_ci * within the end tile (with a 32-byte mask). 17662306a36Sopenharmony_ci */ 17762306a36Sopenharmony_ci offset = (width - 1) & (32 - 1); 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci regmap_write(frontend->regs, SUN4I_FRONTEND_TB_OFF0_REG, 18062306a36Sopenharmony_ci SUN4I_FRONTEND_TB_OFF_X1(offset)); 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci if (fb->format->num_planes > 1) { 18362306a36Sopenharmony_ci strides[1] = 18462306a36Sopenharmony_ci SUN4I_FRONTEND_LINESTRD_TILED(fb->pitches[1]); 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci regmap_write(frontend->regs, SUN4I_FRONTEND_TB_OFF1_REG, 18762306a36Sopenharmony_ci SUN4I_FRONTEND_TB_OFF_X1(offset)); 18862306a36Sopenharmony_ci } 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci if (fb->format->num_planes > 2) { 19162306a36Sopenharmony_ci strides[2] = 19262306a36Sopenharmony_ci SUN4I_FRONTEND_LINESTRD_TILED(fb->pitches[2]); 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci regmap_write(frontend->regs, SUN4I_FRONTEND_TB_OFF2_REG, 19562306a36Sopenharmony_ci SUN4I_FRONTEND_TB_OFF_X1(offset)); 19662306a36Sopenharmony_ci } 19762306a36Sopenharmony_ci } else { 19862306a36Sopenharmony_ci strides[0] = fb->pitches[0]; 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci if (fb->format->num_planes > 1) 20162306a36Sopenharmony_ci strides[1] = fb->pitches[1]; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci if (fb->format->num_planes > 2) 20462306a36Sopenharmony_ci strides[2] = fb->pitches[2]; 20562306a36Sopenharmony_ci } 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci /* Set the line width */ 20862306a36Sopenharmony_ci DRM_DEBUG_DRIVER("Frontend stride: %d bytes\n", fb->pitches[0]); 20962306a36Sopenharmony_ci regmap_write(frontend->regs, SUN4I_FRONTEND_LINESTRD0_REG, 21062306a36Sopenharmony_ci strides[0]); 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci if (fb->format->num_planes > 1) 21362306a36Sopenharmony_ci regmap_write(frontend->regs, SUN4I_FRONTEND_LINESTRD1_REG, 21462306a36Sopenharmony_ci strides[1]); 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci if (fb->format->num_planes > 2) 21762306a36Sopenharmony_ci regmap_write(frontend->regs, SUN4I_FRONTEND_LINESTRD2_REG, 21862306a36Sopenharmony_ci strides[2]); 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci /* Some planar formats require chroma channel swapping by hand. */ 22162306a36Sopenharmony_ci swap = sun4i_frontend_format_chroma_requires_swap(fb->format->format); 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci /* Set the physical address of the buffer in memory */ 22462306a36Sopenharmony_ci dma_addr = drm_fb_dma_get_gem_addr(fb, state, 0); 22562306a36Sopenharmony_ci DRM_DEBUG_DRIVER("Setting buffer #0 address to %pad\n", &dma_addr); 22662306a36Sopenharmony_ci regmap_write(frontend->regs, SUN4I_FRONTEND_BUF_ADDR0_REG, dma_addr); 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci if (fb->format->num_planes > 1) { 22962306a36Sopenharmony_ci dma_addr = drm_fb_dma_get_gem_addr(fb, state, swap ? 2 : 1); 23062306a36Sopenharmony_ci DRM_DEBUG_DRIVER("Setting buffer #1 address to %pad\n", 23162306a36Sopenharmony_ci &dma_addr); 23262306a36Sopenharmony_ci regmap_write(frontend->regs, SUN4I_FRONTEND_BUF_ADDR1_REG, 23362306a36Sopenharmony_ci dma_addr); 23462306a36Sopenharmony_ci } 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci if (fb->format->num_planes > 2) { 23762306a36Sopenharmony_ci dma_addr = drm_fb_dma_get_gem_addr(fb, state, swap ? 1 : 2); 23862306a36Sopenharmony_ci DRM_DEBUG_DRIVER("Setting buffer #2 address to %pad\n", 23962306a36Sopenharmony_ci &dma_addr); 24062306a36Sopenharmony_ci regmap_write(frontend->regs, SUN4I_FRONTEND_BUF_ADDR2_REG, 24162306a36Sopenharmony_ci dma_addr); 24262306a36Sopenharmony_ci } 24362306a36Sopenharmony_ci} 24462306a36Sopenharmony_ciEXPORT_SYMBOL(sun4i_frontend_update_buffer); 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_cistatic int 24762306a36Sopenharmony_cisun4i_frontend_drm_format_to_input_fmt(const struct drm_format_info *format, 24862306a36Sopenharmony_ci u32 *val) 24962306a36Sopenharmony_ci{ 25062306a36Sopenharmony_ci if (!format->is_yuv) 25162306a36Sopenharmony_ci *val = SUN4I_FRONTEND_INPUT_FMT_DATA_FMT_RGB; 25262306a36Sopenharmony_ci else if (drm_format_info_is_yuv_sampling_411(format)) 25362306a36Sopenharmony_ci *val = SUN4I_FRONTEND_INPUT_FMT_DATA_FMT_YUV411; 25462306a36Sopenharmony_ci else if (drm_format_info_is_yuv_sampling_420(format)) 25562306a36Sopenharmony_ci *val = SUN4I_FRONTEND_INPUT_FMT_DATA_FMT_YUV420; 25662306a36Sopenharmony_ci else if (drm_format_info_is_yuv_sampling_422(format)) 25762306a36Sopenharmony_ci *val = SUN4I_FRONTEND_INPUT_FMT_DATA_FMT_YUV422; 25862306a36Sopenharmony_ci else if (drm_format_info_is_yuv_sampling_444(format)) 25962306a36Sopenharmony_ci *val = SUN4I_FRONTEND_INPUT_FMT_DATA_FMT_YUV444; 26062306a36Sopenharmony_ci else 26162306a36Sopenharmony_ci return -EINVAL; 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci return 0; 26462306a36Sopenharmony_ci} 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_cistatic int 26762306a36Sopenharmony_cisun4i_frontend_drm_format_to_input_mode(const struct drm_format_info *format, 26862306a36Sopenharmony_ci uint64_t modifier, u32 *val) 26962306a36Sopenharmony_ci{ 27062306a36Sopenharmony_ci bool tiled = (modifier == DRM_FORMAT_MOD_ALLWINNER_TILED); 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci switch (format->num_planes) { 27362306a36Sopenharmony_ci case 1: 27462306a36Sopenharmony_ci *val = SUN4I_FRONTEND_INPUT_FMT_DATA_MOD_PACKED; 27562306a36Sopenharmony_ci return 0; 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci case 2: 27862306a36Sopenharmony_ci *val = tiled ? SUN4I_FRONTEND_INPUT_FMT_DATA_MOD_MB32_SEMIPLANAR 27962306a36Sopenharmony_ci : SUN4I_FRONTEND_INPUT_FMT_DATA_MOD_SEMIPLANAR; 28062306a36Sopenharmony_ci return 0; 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci case 3: 28362306a36Sopenharmony_ci *val = tiled ? SUN4I_FRONTEND_INPUT_FMT_DATA_MOD_MB32_PLANAR 28462306a36Sopenharmony_ci : SUN4I_FRONTEND_INPUT_FMT_DATA_MOD_PLANAR; 28562306a36Sopenharmony_ci return 0; 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci default: 28862306a36Sopenharmony_ci return -EINVAL; 28962306a36Sopenharmony_ci } 29062306a36Sopenharmony_ci} 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_cistatic int 29362306a36Sopenharmony_cisun4i_frontend_drm_format_to_input_sequence(const struct drm_format_info *format, 29462306a36Sopenharmony_ci u32 *val) 29562306a36Sopenharmony_ci{ 29662306a36Sopenharmony_ci /* Planar formats have an explicit input sequence. */ 29762306a36Sopenharmony_ci if (drm_format_info_is_yuv_planar(format)) { 29862306a36Sopenharmony_ci *val = 0; 29962306a36Sopenharmony_ci return 0; 30062306a36Sopenharmony_ci } 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci switch (format->format) { 30362306a36Sopenharmony_ci case DRM_FORMAT_BGRX8888: 30462306a36Sopenharmony_ci *val = SUN4I_FRONTEND_INPUT_FMT_DATA_PS_BGRX; 30562306a36Sopenharmony_ci return 0; 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci case DRM_FORMAT_NV12: 30862306a36Sopenharmony_ci *val = SUN4I_FRONTEND_INPUT_FMT_DATA_PS_UV; 30962306a36Sopenharmony_ci return 0; 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci case DRM_FORMAT_NV16: 31262306a36Sopenharmony_ci *val = SUN4I_FRONTEND_INPUT_FMT_DATA_PS_UV; 31362306a36Sopenharmony_ci return 0; 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci case DRM_FORMAT_NV21: 31662306a36Sopenharmony_ci *val = SUN4I_FRONTEND_INPUT_FMT_DATA_PS_VU; 31762306a36Sopenharmony_ci return 0; 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci case DRM_FORMAT_NV61: 32062306a36Sopenharmony_ci *val = SUN4I_FRONTEND_INPUT_FMT_DATA_PS_VU; 32162306a36Sopenharmony_ci return 0; 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci case DRM_FORMAT_UYVY: 32462306a36Sopenharmony_ci *val = SUN4I_FRONTEND_INPUT_FMT_DATA_PS_UYVY; 32562306a36Sopenharmony_ci return 0; 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci case DRM_FORMAT_VYUY: 32862306a36Sopenharmony_ci *val = SUN4I_FRONTEND_INPUT_FMT_DATA_PS_VYUY; 32962306a36Sopenharmony_ci return 0; 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci case DRM_FORMAT_XRGB8888: 33262306a36Sopenharmony_ci *val = SUN4I_FRONTEND_INPUT_FMT_DATA_PS_XRGB; 33362306a36Sopenharmony_ci return 0; 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci case DRM_FORMAT_YUYV: 33662306a36Sopenharmony_ci *val = SUN4I_FRONTEND_INPUT_FMT_DATA_PS_YUYV; 33762306a36Sopenharmony_ci return 0; 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci case DRM_FORMAT_YVYU: 34062306a36Sopenharmony_ci *val = SUN4I_FRONTEND_INPUT_FMT_DATA_PS_YVYU; 34162306a36Sopenharmony_ci return 0; 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci default: 34462306a36Sopenharmony_ci return -EINVAL; 34562306a36Sopenharmony_ci } 34662306a36Sopenharmony_ci} 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_cistatic int sun4i_frontend_drm_format_to_output_fmt(uint32_t fmt, u32 *val) 34962306a36Sopenharmony_ci{ 35062306a36Sopenharmony_ci switch (fmt) { 35162306a36Sopenharmony_ci case DRM_FORMAT_BGRX8888: 35262306a36Sopenharmony_ci *val = SUN4I_FRONTEND_OUTPUT_FMT_DATA_FMT_BGRX8888; 35362306a36Sopenharmony_ci return 0; 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci case DRM_FORMAT_XRGB8888: 35662306a36Sopenharmony_ci *val = SUN4I_FRONTEND_OUTPUT_FMT_DATA_FMT_XRGB8888; 35762306a36Sopenharmony_ci return 0; 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci default: 36062306a36Sopenharmony_ci return -EINVAL; 36162306a36Sopenharmony_ci } 36262306a36Sopenharmony_ci} 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_cistatic const uint32_t sun4i_frontend_formats[] = { 36562306a36Sopenharmony_ci DRM_FORMAT_BGRX8888, 36662306a36Sopenharmony_ci DRM_FORMAT_NV12, 36762306a36Sopenharmony_ci DRM_FORMAT_NV16, 36862306a36Sopenharmony_ci DRM_FORMAT_NV21, 36962306a36Sopenharmony_ci DRM_FORMAT_NV61, 37062306a36Sopenharmony_ci DRM_FORMAT_UYVY, 37162306a36Sopenharmony_ci DRM_FORMAT_VYUY, 37262306a36Sopenharmony_ci DRM_FORMAT_XRGB8888, 37362306a36Sopenharmony_ci DRM_FORMAT_YUV411, 37462306a36Sopenharmony_ci DRM_FORMAT_YUV420, 37562306a36Sopenharmony_ci DRM_FORMAT_YUV422, 37662306a36Sopenharmony_ci DRM_FORMAT_YUV444, 37762306a36Sopenharmony_ci DRM_FORMAT_YUYV, 37862306a36Sopenharmony_ci DRM_FORMAT_YVU411, 37962306a36Sopenharmony_ci DRM_FORMAT_YVU420, 38062306a36Sopenharmony_ci DRM_FORMAT_YVU422, 38162306a36Sopenharmony_ci DRM_FORMAT_YVU444, 38262306a36Sopenharmony_ci DRM_FORMAT_YVYU, 38362306a36Sopenharmony_ci}; 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_cibool sun4i_frontend_format_is_supported(uint32_t fmt, uint64_t modifier) 38662306a36Sopenharmony_ci{ 38762306a36Sopenharmony_ci unsigned int i; 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci if (modifier == DRM_FORMAT_MOD_ALLWINNER_TILED) 39062306a36Sopenharmony_ci return sun4i_frontend_format_supports_tiling(fmt); 39162306a36Sopenharmony_ci else if (modifier != DRM_FORMAT_MOD_LINEAR) 39262306a36Sopenharmony_ci return false; 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(sun4i_frontend_formats); i++) 39562306a36Sopenharmony_ci if (sun4i_frontend_formats[i] == fmt) 39662306a36Sopenharmony_ci return true; 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci return false; 39962306a36Sopenharmony_ci} 40062306a36Sopenharmony_ciEXPORT_SYMBOL(sun4i_frontend_format_is_supported); 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ciint sun4i_frontend_update_formats(struct sun4i_frontend *frontend, 40362306a36Sopenharmony_ci struct drm_plane *plane, uint32_t out_fmt) 40462306a36Sopenharmony_ci{ 40562306a36Sopenharmony_ci struct drm_plane_state *state = plane->state; 40662306a36Sopenharmony_ci struct drm_framebuffer *fb = state->fb; 40762306a36Sopenharmony_ci const struct drm_format_info *format = fb->format; 40862306a36Sopenharmony_ci uint64_t modifier = fb->modifier; 40962306a36Sopenharmony_ci unsigned int ch1_phase_idx; 41062306a36Sopenharmony_ci u32 out_fmt_val; 41162306a36Sopenharmony_ci u32 in_fmt_val, in_mod_val, in_ps_val; 41262306a36Sopenharmony_ci unsigned int i; 41362306a36Sopenharmony_ci u32 bypass; 41462306a36Sopenharmony_ci int ret; 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci ret = sun4i_frontend_drm_format_to_input_fmt(format, &in_fmt_val); 41762306a36Sopenharmony_ci if (ret) { 41862306a36Sopenharmony_ci DRM_DEBUG_DRIVER("Invalid input format\n"); 41962306a36Sopenharmony_ci return ret; 42062306a36Sopenharmony_ci } 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci ret = sun4i_frontend_drm_format_to_input_mode(format, modifier, 42362306a36Sopenharmony_ci &in_mod_val); 42462306a36Sopenharmony_ci if (ret) { 42562306a36Sopenharmony_ci DRM_DEBUG_DRIVER("Invalid input mode\n"); 42662306a36Sopenharmony_ci return ret; 42762306a36Sopenharmony_ci } 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci ret = sun4i_frontend_drm_format_to_input_sequence(format, &in_ps_val); 43062306a36Sopenharmony_ci if (ret) { 43162306a36Sopenharmony_ci DRM_DEBUG_DRIVER("Invalid pixel sequence\n"); 43262306a36Sopenharmony_ci return ret; 43362306a36Sopenharmony_ci } 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci ret = sun4i_frontend_drm_format_to_output_fmt(out_fmt, &out_fmt_val); 43662306a36Sopenharmony_ci if (ret) { 43762306a36Sopenharmony_ci DRM_DEBUG_DRIVER("Invalid output format\n"); 43862306a36Sopenharmony_ci return ret; 43962306a36Sopenharmony_ci } 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci /* 44262306a36Sopenharmony_ci * I have no idea what this does exactly, but it seems to be 44362306a36Sopenharmony_ci * related to the scaler FIR filter phase parameters. 44462306a36Sopenharmony_ci */ 44562306a36Sopenharmony_ci ch1_phase_idx = (format->num_planes > 1) ? 1 : 0; 44662306a36Sopenharmony_ci regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_HORZPHASE_REG, 44762306a36Sopenharmony_ci frontend->data->ch_phase[0]); 44862306a36Sopenharmony_ci regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_HORZPHASE_REG, 44962306a36Sopenharmony_ci frontend->data->ch_phase[ch1_phase_idx]); 45062306a36Sopenharmony_ci regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_VERTPHASE0_REG, 45162306a36Sopenharmony_ci frontend->data->ch_phase[0]); 45262306a36Sopenharmony_ci regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_VERTPHASE0_REG, 45362306a36Sopenharmony_ci frontend->data->ch_phase[ch1_phase_idx]); 45462306a36Sopenharmony_ci regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_VERTPHASE1_REG, 45562306a36Sopenharmony_ci frontend->data->ch_phase[0]); 45662306a36Sopenharmony_ci regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_VERTPHASE1_REG, 45762306a36Sopenharmony_ci frontend->data->ch_phase[ch1_phase_idx]); 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci /* 46062306a36Sopenharmony_ci * Checking the input format is sufficient since we currently only 46162306a36Sopenharmony_ci * support RGB output formats to the backend. If YUV output formats 46262306a36Sopenharmony_ci * ever get supported, an YUV input and output would require bypassing 46362306a36Sopenharmony_ci * the CSC engine too. 46462306a36Sopenharmony_ci */ 46562306a36Sopenharmony_ci if (format->is_yuv) { 46662306a36Sopenharmony_ci /* Setup the CSC engine for YUV to RGB conversion. */ 46762306a36Sopenharmony_ci bypass = 0; 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(sunxi_bt601_yuv2rgb_coef); i++) 47062306a36Sopenharmony_ci regmap_write(frontend->regs, 47162306a36Sopenharmony_ci SUN4I_FRONTEND_CSC_COEF_REG(i), 47262306a36Sopenharmony_ci sunxi_bt601_yuv2rgb_coef[i]); 47362306a36Sopenharmony_ci } else { 47462306a36Sopenharmony_ci bypass = SUN4I_FRONTEND_BYPASS_CSC_EN; 47562306a36Sopenharmony_ci } 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci regmap_update_bits(frontend->regs, SUN4I_FRONTEND_BYPASS_REG, 47862306a36Sopenharmony_ci SUN4I_FRONTEND_BYPASS_CSC_EN, bypass); 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci regmap_write(frontend->regs, SUN4I_FRONTEND_INPUT_FMT_REG, 48162306a36Sopenharmony_ci in_mod_val | in_fmt_val | in_ps_val); 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci /* 48462306a36Sopenharmony_ci * TODO: It look like the A31 and A80 at least will need the 48562306a36Sopenharmony_ci * bit 7 (ALPHA_EN) enabled when using a format with alpha (so 48662306a36Sopenharmony_ci * ARGB8888). 48762306a36Sopenharmony_ci */ 48862306a36Sopenharmony_ci regmap_write(frontend->regs, SUN4I_FRONTEND_OUTPUT_FMT_REG, 48962306a36Sopenharmony_ci out_fmt_val); 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci return 0; 49262306a36Sopenharmony_ci} 49362306a36Sopenharmony_ciEXPORT_SYMBOL(sun4i_frontend_update_formats); 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_civoid sun4i_frontend_update_coord(struct sun4i_frontend *frontend, 49662306a36Sopenharmony_ci struct drm_plane *plane) 49762306a36Sopenharmony_ci{ 49862306a36Sopenharmony_ci struct drm_plane_state *state = plane->state; 49962306a36Sopenharmony_ci struct drm_framebuffer *fb = state->fb; 50062306a36Sopenharmony_ci uint32_t luma_width, luma_height; 50162306a36Sopenharmony_ci uint32_t chroma_width, chroma_height; 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci /* Set height and width */ 50462306a36Sopenharmony_ci DRM_DEBUG_DRIVER("Frontend size W: %u H: %u\n", 50562306a36Sopenharmony_ci state->crtc_w, state->crtc_h); 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci luma_width = state->src_w >> 16; 50862306a36Sopenharmony_ci luma_height = state->src_h >> 16; 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci chroma_width = DIV_ROUND_UP(luma_width, fb->format->hsub); 51162306a36Sopenharmony_ci chroma_height = DIV_ROUND_UP(luma_height, fb->format->vsub); 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_INSIZE_REG, 51462306a36Sopenharmony_ci SUN4I_FRONTEND_INSIZE(luma_height, luma_width)); 51562306a36Sopenharmony_ci regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_INSIZE_REG, 51662306a36Sopenharmony_ci SUN4I_FRONTEND_INSIZE(chroma_height, chroma_width)); 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_OUTSIZE_REG, 51962306a36Sopenharmony_ci SUN4I_FRONTEND_OUTSIZE(state->crtc_h, state->crtc_w)); 52062306a36Sopenharmony_ci regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_OUTSIZE_REG, 52162306a36Sopenharmony_ci SUN4I_FRONTEND_OUTSIZE(state->crtc_h, state->crtc_w)); 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_HORZFACT_REG, 52462306a36Sopenharmony_ci (luma_width << 16) / state->crtc_w); 52562306a36Sopenharmony_ci regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_HORZFACT_REG, 52662306a36Sopenharmony_ci (chroma_width << 16) / state->crtc_w); 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_VERTFACT_REG, 52962306a36Sopenharmony_ci (luma_height << 16) / state->crtc_h); 53062306a36Sopenharmony_ci regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_VERTFACT_REG, 53162306a36Sopenharmony_ci (chroma_height << 16) / state->crtc_h); 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci regmap_write_bits(frontend->regs, SUN4I_FRONTEND_FRM_CTRL_REG, 53462306a36Sopenharmony_ci SUN4I_FRONTEND_FRM_CTRL_REG_RDY, 53562306a36Sopenharmony_ci SUN4I_FRONTEND_FRM_CTRL_REG_RDY); 53662306a36Sopenharmony_ci} 53762306a36Sopenharmony_ciEXPORT_SYMBOL(sun4i_frontend_update_coord); 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ciint sun4i_frontend_enable(struct sun4i_frontend *frontend) 54062306a36Sopenharmony_ci{ 54162306a36Sopenharmony_ci regmap_write_bits(frontend->regs, SUN4I_FRONTEND_FRM_CTRL_REG, 54262306a36Sopenharmony_ci SUN4I_FRONTEND_FRM_CTRL_FRM_START, 54362306a36Sopenharmony_ci SUN4I_FRONTEND_FRM_CTRL_FRM_START); 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci return 0; 54662306a36Sopenharmony_ci} 54762306a36Sopenharmony_ciEXPORT_SYMBOL(sun4i_frontend_enable); 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_cistatic const struct regmap_config sun4i_frontend_regmap_config = { 55062306a36Sopenharmony_ci .reg_bits = 32, 55162306a36Sopenharmony_ci .val_bits = 32, 55262306a36Sopenharmony_ci .reg_stride = 4, 55362306a36Sopenharmony_ci .max_register = 0x0a14, 55462306a36Sopenharmony_ci}; 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_cistatic int sun4i_frontend_bind(struct device *dev, struct device *master, 55762306a36Sopenharmony_ci void *data) 55862306a36Sopenharmony_ci{ 55962306a36Sopenharmony_ci struct platform_device *pdev = to_platform_device(dev); 56062306a36Sopenharmony_ci struct sun4i_frontend *frontend; 56162306a36Sopenharmony_ci struct drm_device *drm = data; 56262306a36Sopenharmony_ci struct sun4i_drv *drv = drm->dev_private; 56362306a36Sopenharmony_ci void __iomem *regs; 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci frontend = devm_kzalloc(dev, sizeof(*frontend), GFP_KERNEL); 56662306a36Sopenharmony_ci if (!frontend) 56762306a36Sopenharmony_ci return -ENOMEM; 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci dev_set_drvdata(dev, frontend); 57062306a36Sopenharmony_ci frontend->dev = dev; 57162306a36Sopenharmony_ci frontend->node = dev->of_node; 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci frontend->data = of_device_get_match_data(dev); 57462306a36Sopenharmony_ci if (!frontend->data) 57562306a36Sopenharmony_ci return -ENODEV; 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci regs = devm_platform_ioremap_resource(pdev, 0); 57862306a36Sopenharmony_ci if (IS_ERR(regs)) 57962306a36Sopenharmony_ci return PTR_ERR(regs); 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci frontend->regs = devm_regmap_init_mmio(dev, regs, 58262306a36Sopenharmony_ci &sun4i_frontend_regmap_config); 58362306a36Sopenharmony_ci if (IS_ERR(frontend->regs)) { 58462306a36Sopenharmony_ci dev_err(dev, "Couldn't create the frontend regmap\n"); 58562306a36Sopenharmony_ci return PTR_ERR(frontend->regs); 58662306a36Sopenharmony_ci } 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci frontend->reset = devm_reset_control_get(dev, NULL); 58962306a36Sopenharmony_ci if (IS_ERR(frontend->reset)) { 59062306a36Sopenharmony_ci dev_err(dev, "Couldn't get our reset line\n"); 59162306a36Sopenharmony_ci return PTR_ERR(frontend->reset); 59262306a36Sopenharmony_ci } 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci frontend->bus_clk = devm_clk_get(dev, "ahb"); 59562306a36Sopenharmony_ci if (IS_ERR(frontend->bus_clk)) { 59662306a36Sopenharmony_ci dev_err(dev, "Couldn't get our bus clock\n"); 59762306a36Sopenharmony_ci return PTR_ERR(frontend->bus_clk); 59862306a36Sopenharmony_ci } 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci frontend->mod_clk = devm_clk_get(dev, "mod"); 60162306a36Sopenharmony_ci if (IS_ERR(frontend->mod_clk)) { 60262306a36Sopenharmony_ci dev_err(dev, "Couldn't get our mod clock\n"); 60362306a36Sopenharmony_ci return PTR_ERR(frontend->mod_clk); 60462306a36Sopenharmony_ci } 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci frontend->ram_clk = devm_clk_get(dev, "ram"); 60762306a36Sopenharmony_ci if (IS_ERR(frontend->ram_clk)) { 60862306a36Sopenharmony_ci dev_err(dev, "Couldn't get our ram clock\n"); 60962306a36Sopenharmony_ci return PTR_ERR(frontend->ram_clk); 61062306a36Sopenharmony_ci } 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci list_add_tail(&frontend->list, &drv->frontend_list); 61362306a36Sopenharmony_ci pm_runtime_enable(dev); 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci return 0; 61662306a36Sopenharmony_ci} 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_cistatic void sun4i_frontend_unbind(struct device *dev, struct device *master, 61962306a36Sopenharmony_ci void *data) 62062306a36Sopenharmony_ci{ 62162306a36Sopenharmony_ci struct sun4i_frontend *frontend = dev_get_drvdata(dev); 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci list_del(&frontend->list); 62462306a36Sopenharmony_ci pm_runtime_force_suspend(dev); 62562306a36Sopenharmony_ci} 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_cistatic const struct component_ops sun4i_frontend_ops = { 62862306a36Sopenharmony_ci .bind = sun4i_frontend_bind, 62962306a36Sopenharmony_ci .unbind = sun4i_frontend_unbind, 63062306a36Sopenharmony_ci}; 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_cistatic int sun4i_frontend_probe(struct platform_device *pdev) 63362306a36Sopenharmony_ci{ 63462306a36Sopenharmony_ci return component_add(&pdev->dev, &sun4i_frontend_ops); 63562306a36Sopenharmony_ci} 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_cistatic void sun4i_frontend_remove(struct platform_device *pdev) 63862306a36Sopenharmony_ci{ 63962306a36Sopenharmony_ci component_del(&pdev->dev, &sun4i_frontend_ops); 64062306a36Sopenharmony_ci} 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_cistatic int sun4i_frontend_runtime_resume(struct device *dev) 64362306a36Sopenharmony_ci{ 64462306a36Sopenharmony_ci struct sun4i_frontend *frontend = dev_get_drvdata(dev); 64562306a36Sopenharmony_ci int ret; 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci clk_set_rate(frontend->mod_clk, 300000000); 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci clk_prepare_enable(frontend->bus_clk); 65062306a36Sopenharmony_ci clk_prepare_enable(frontend->mod_clk); 65162306a36Sopenharmony_ci clk_prepare_enable(frontend->ram_clk); 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci ret = reset_control_reset(frontend->reset); 65462306a36Sopenharmony_ci if (ret) { 65562306a36Sopenharmony_ci dev_err(dev, "Couldn't reset our device\n"); 65662306a36Sopenharmony_ci return ret; 65762306a36Sopenharmony_ci } 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci regmap_update_bits(frontend->regs, SUN4I_FRONTEND_EN_REG, 66062306a36Sopenharmony_ci SUN4I_FRONTEND_EN_EN, 66162306a36Sopenharmony_ci SUN4I_FRONTEND_EN_EN); 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci sun4i_frontend_scaler_init(frontend); 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci return 0; 66662306a36Sopenharmony_ci} 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_cistatic int sun4i_frontend_runtime_suspend(struct device *dev) 66962306a36Sopenharmony_ci{ 67062306a36Sopenharmony_ci struct sun4i_frontend *frontend = dev_get_drvdata(dev); 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci clk_disable_unprepare(frontend->ram_clk); 67362306a36Sopenharmony_ci clk_disable_unprepare(frontend->mod_clk); 67462306a36Sopenharmony_ci clk_disable_unprepare(frontend->bus_clk); 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci reset_control_assert(frontend->reset); 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci return 0; 67962306a36Sopenharmony_ci} 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_cistatic const struct dev_pm_ops sun4i_frontend_pm_ops = { 68262306a36Sopenharmony_ci .runtime_resume = sun4i_frontend_runtime_resume, 68362306a36Sopenharmony_ci .runtime_suspend = sun4i_frontend_runtime_suspend, 68462306a36Sopenharmony_ci}; 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_cistatic const struct sun4i_frontend_data sun4i_a10_frontend = { 68762306a36Sopenharmony_ci .ch_phase = { 0x000, 0xfc000 }, 68862306a36Sopenharmony_ci .has_coef_rdy = true, 68962306a36Sopenharmony_ci}; 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_cistatic const struct sun4i_frontend_data sun8i_a33_frontend = { 69262306a36Sopenharmony_ci .ch_phase = { 0x400, 0xfc400 }, 69362306a36Sopenharmony_ci .has_coef_access_ctrl = true, 69462306a36Sopenharmony_ci}; 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ciconst struct of_device_id sun4i_frontend_of_table[] = { 69762306a36Sopenharmony_ci { 69862306a36Sopenharmony_ci .compatible = "allwinner,sun4i-a10-display-frontend", 69962306a36Sopenharmony_ci .data = &sun4i_a10_frontend 70062306a36Sopenharmony_ci }, 70162306a36Sopenharmony_ci { 70262306a36Sopenharmony_ci .compatible = "allwinner,sun7i-a20-display-frontend", 70362306a36Sopenharmony_ci .data = &sun4i_a10_frontend 70462306a36Sopenharmony_ci }, 70562306a36Sopenharmony_ci { 70662306a36Sopenharmony_ci .compatible = "allwinner,sun8i-a23-display-frontend", 70762306a36Sopenharmony_ci .data = &sun8i_a33_frontend 70862306a36Sopenharmony_ci }, 70962306a36Sopenharmony_ci { 71062306a36Sopenharmony_ci .compatible = "allwinner,sun8i-a33-display-frontend", 71162306a36Sopenharmony_ci .data = &sun8i_a33_frontend 71262306a36Sopenharmony_ci }, 71362306a36Sopenharmony_ci { } 71462306a36Sopenharmony_ci}; 71562306a36Sopenharmony_ciEXPORT_SYMBOL(sun4i_frontend_of_table); 71662306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, sun4i_frontend_of_table); 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_cistatic struct platform_driver sun4i_frontend_driver = { 71962306a36Sopenharmony_ci .probe = sun4i_frontend_probe, 72062306a36Sopenharmony_ci .remove_new = sun4i_frontend_remove, 72162306a36Sopenharmony_ci .driver = { 72262306a36Sopenharmony_ci .name = "sun4i-frontend", 72362306a36Sopenharmony_ci .of_match_table = sun4i_frontend_of_table, 72462306a36Sopenharmony_ci .pm = &sun4i_frontend_pm_ops, 72562306a36Sopenharmony_ci }, 72662306a36Sopenharmony_ci}; 72762306a36Sopenharmony_cimodule_platform_driver(sun4i_frontend_driver); 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ciMODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>"); 73062306a36Sopenharmony_ciMODULE_DESCRIPTION("Allwinner A10 Display Engine Frontend Driver"); 73162306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 732