Skip to content

Commit

Permalink
add layer1 rotation
Browse files Browse the repository at this point in the history
Signed-off-by: canaan <[email protected]>
  • Loading branch information
zhaoshuaiadada authored and RevySR committed Nov 25, 2024
1 parent c98f8bd commit f050fc6
Show file tree
Hide file tree
Showing 5 changed files with 209 additions and 5 deletions.
7 changes: 7 additions & 0 deletions drivers/gpu/drm/canaan/canaan_plane.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include <drm/drm_plane.h>
#include <drm/drm_plane_helper.h>
#include <drm/drm_probe_helper.h>
#include <drm/drm_blend.h>

#include "canaan_vo.h"
#include "canaan_crtc.h"
Expand Down Expand Up @@ -123,6 +124,12 @@ struct canaan_plane *canaan_plane_create(struct drm_device *drm_dev,
return ERR_PTR(ret);
}

if (config->supported_rotations) {
drm_plane_create_rotation_property(&canaan_plane->base, DRM_MODE_ROTATE_0,
DRM_MODE_ROTATE_0 |
config->supported_rotations);
}

drm_plane_helper_add(plane, &canaan_plane_helper_funcs);
canaan_plane->id = config->id;
canaan_plane->config = config;
Expand Down
1 change: 1 addition & 0 deletions drivers/gpu/drm/canaan/canaan_plane.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
struct canaan_plane_config {
char *name;
uint32_t id;
const uint32_t supported_rotations;
uint32_t possible_crtcs;
uint32_t num_formats;
const uint32_t *formats;
Expand Down
192 changes: 188 additions & 4 deletions drivers/gpu/drm/canaan/canaan_vo.c
Original file line number Diff line number Diff line change
Expand Up @@ -264,12 +264,168 @@ static void canaan_vo_update_osd(struct canaan_vo *vo,
VO_OSD0_7_STRIDE_REG_OFFSET));
}


static void canaan_vo_update_layer1(struct canaan_vo *vo,
struct canaan_plane *canaan_plane,
struct drm_display_mode *adj_mode)
{
uint32_t reg_val = 0x00;
struct drm_plane_state *plane_state = canaan_plane->base.state;
struct drm_framebuffer *fb = plane_state->fb;
struct drm_gem_dma_object *cma_obj = drm_fb_dma_get_gem_obj(fb, 0);
struct canaan_plane_config *config = canaan_plane->config;
uint32_t plane_offset = config->plane_offset;
uint32_t plane_enable_bit = config->plane_enable_bit;
uint32_t xctl_reg_offset = config->xctl_reg_offset;
uint32_t yctl_reg_offset = config->yctl_reg_offset;
uint32_t actual_w, start_w, offset_w;
uint32_t actual_h, start_h, offset_h;
uint32_t y_addr, uv_addr;
uint32_t stride = 0x00;
uint32_t disp_en = 0x00;

reg_val = readl(vo->reg_base + plane_offset + VO_LAYER1_CTL);
reg_val = (reg_val & ~(GENMASK(3, 0))) | (7 + (0 << 3));

switch (fb->format->format) {
case DRM_FORMAT_NV12:
reg_val = (reg_val & ~(GENMASK(9, 8))) | ((0 << 9) + (0 << 8));
break;
case DRM_FORMAT_NV21:
reg_val = (reg_val & ~(GENMASK(9, 8))) | ((1 << 9) + (0 << 8));
break;
case DRM_FORMAT_NV16:
reg_val = (reg_val & ~(GENMASK(9, 8))) | ((0 << 9) + (1 << 8));
break;
case DRM_FORMAT_NV61:
reg_val = (reg_val & ~(GENMASK(9, 8))) | ((1 << 9) + (1 << 8));
break;
default:
DRM_DEV_ERROR(vo->dev, "Invalid pixel format %d\n",
fb->format->format);
return;
}

switch (plane_state->rotation &
(DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y |
DRM_MODE_ROTATE_90 | DRM_MODE_ROTATE_270)) {

case DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y:
reg_val = (reg_val & ~(GENMASK(7, 4))) | ((0x3 << 6) + (0x0 << 4));

actual_w = plane_state->src_w >> 16;
actual_h = plane_state->src_h >> 16;
break;
case DRM_MODE_REFLECT_X | DRM_MODE_ROTATE_90:
reg_val = (reg_val & ~(GENMASK(7, 4))) | ((0x1 << 6) + (0x1 << 4));

actual_w = plane_state->src_h >> 16;
actual_h = plane_state->src_w >> 16;
break;
case DRM_MODE_REFLECT_X | DRM_MODE_ROTATE_270:
reg_val = (reg_val & ~(GENMASK(7, 4))) | ((0x1 << 6) + (0x2 << 4));

actual_w = plane_state->src_h >> 16;
actual_h = plane_state->src_w >> 16;
break;
case DRM_MODE_REFLECT_X:
reg_val = (reg_val & ~(GENMASK(7, 4))) | ((0x1 << 6) + (0x0 << 4));

actual_w = plane_state->src_w >> 16;
actual_h = plane_state->src_h >> 16;
break;
case DRM_MODE_REFLECT_Y:
reg_val = (reg_val & ~(GENMASK(7, 4))) | ((0x2 << 6) + (0x0 << 4));

actual_w = plane_state->src_w >> 16;
actual_h = plane_state->src_h >> 16;
break;
case DRM_MODE_ROTATE_90:
reg_val = (reg_val & ~(GENMASK(7, 4))) | ((0x0 << 6) + (0x1 << 4));

actual_w = plane_state->src_h >> 16;
actual_h = plane_state->src_w >> 16;
break;
case DRM_MODE_ROTATE_270:
reg_val = (reg_val & ~(GENMASK(7, 4))) | ((0x0 << 6) + (0x3 << 4));

actual_w = plane_state->src_h >> 16;
actual_h = plane_state->src_w >> 16;
break;
case 0:
reg_val = (reg_val & ~(GENMASK(7, 4))) | (0x0 << 4);

actual_w = plane_state->src_w >> 16;
actual_h = plane_state->src_h >> 16;
break;
}

writel(reg_val, vo->reg_base + plane_offset + VO_LAYER1_CTL);

reg_val = (actual_w) | (actual_h << 16);
writel(reg_val, vo->reg_base + plane_offset + VO_LAYER1_ACT_SIZE);

offset_w = plane_state->crtc_x;
start_w = readl(vo->reg_base + VO_DISP_XZONE_CTL) & 0x1fff;
reg_val = ((start_w + offset_w + (plane_state->src_w >> 16) - 1) << 16)
+ (start_w + offset_w);
writel(reg_val, vo->reg_base + xctl_reg_offset);

offset_h = plane_state->crtc_y;
start_h = readl(vo->reg_base + VO_DISP_YZONE_CTL) & 0x1fff;
reg_val = ((start_h + offset_h + (plane_state->src_h >> 16) - 1) << 16) +
(start_h + offset_h);
writel(reg_val, vo->reg_base + yctl_reg_offset);

y_addr = cma_obj->dma_addr;
writel(y_addr, vo->reg_base + plane_offset + VO_LAYER1_Y_ADDR0);
writel(y_addr, vo->reg_base + plane_offset + VO_LAYER1_Y_ADDR1);

uv_addr = cma_obj->dma_addr + fb->offsets[1];
writel(uv_addr,
vo->reg_base + plane_offset + VO_LAYER1_UV_ADDR0);
writel(uv_addr,
vo->reg_base + plane_offset + VO_LAYER1_UV_ADDR1);

stride = (actual_w) | (actual_w << 16);
writel(stride, vo->reg_base + plane_offset + VO_LAYER1_STRIDE);

disp_en = readl(vo->reg_base + VO_DISP_ENABLE);
disp_en |= 1 << plane_enable_bit;
writel(disp_en, vo->reg_base + VO_DISP_ENABLE);

writel(0x00010100, vo->reg_base + VO_LAYER1_OFFSET + VO_LAYER1_ADDR_SEL_MODE);

writel(0x11, vo->reg_base + VO_REG_LOAD_CTL);

DRM_DEBUG_DRIVER("VIDEO_CTL_REG: 0x%02x\n",
readl(vo->reg_base + plane_offset +
VO_LAYER2_3_CTL_REG_OFFSET));
DRM_DEBUG_DRIVER("VIDEO_ACT_SIZE_REG: 0x%02x\n",
readl(vo->reg_base + plane_offset +
VO_LAYER2_3_ACT_SIZE_REG_OFFSET));
DRM_DEBUG_DRIVER("VIDEO_Y_ADDR0_REG: 0x%02x\n",
readl(vo->reg_base + plane_offset +
VO_LAYER2_3_Y_ADDR0_REG_OFFSET));
DRM_DEBUG_DRIVER("VIDEO_UV_ADDR0_REG: 0x%02x\n",
readl(vo->reg_base + plane_offset +
VO_LAYER2_3_UV_ADDR0_REG_OFFSET));
DRM_DEBUG_DRIVER("VIDEO_STRIDE_REG: 0x%02x\n",
readl(vo->reg_base + plane_offset +
VO_LAYER2_3_STRIDE_REG_OFFSET));
}


#define FRAC_16_16(mult, div) (((mult) << 16) / (div))

int canaan_vo_check_plane(struct canaan_vo *vo,
struct canaan_plane *canaan_plane,
struct drm_plane_state *plane_state)
{
int ret = 0;
struct drm_crtc_state *crtc_state = NULL;
int min_scale = FRAC_16_16(1, 8);
int max_scale = FRAC_16_16(8, 1);

crtc_state = drm_atomic_get_crtc_state(plane_state->state,
plane_state->crtc);
Expand All @@ -279,8 +435,8 @@ int canaan_vo_check_plane(struct canaan_vo *vo,
}

ret = drm_atomic_helper_check_plane_state(plane_state, crtc_state,
DRM_PLANE_NO_SCALING,
DRM_PLANE_NO_SCALING, true,
min_scale,
max_scale, true,
true);
if (ret) {
DRM_DEV_ERROR(vo->dev, "Failed to check plane_state\n");
Expand All @@ -300,6 +456,8 @@ void canaan_vo_update_plane(struct canaan_vo *vo,
if ((vo->canaan_plane[0]->id == canaan_plane->id) ||
(vo->canaan_plane[5]->id == canaan_plane->id))
canaan_vo_update_video(vo, canaan_plane, adj_mode);
else if (vo->canaan_plane[6]->id == canaan_plane->id)
canaan_vo_update_layer1(vo, canaan_plane, adj_mode);
else
canaan_vo_update_osd(vo, canaan_plane, adj_mode);
}
Expand All @@ -310,6 +468,13 @@ void canaan_vo_disable_plane(struct canaan_vo *vo,
struct canaan_plane_config *config = canaan_plane->config;
uint32_t plane_enable_bit = config->plane_enable_bit;
uint32_t disp_en = 0x00;
uint32_t reg = 0;

if (vo->canaan_plane[6]->id == canaan_plane->id) {
reg = readl(vo->reg_base + 0xA3c);
reg = (reg & ~(BIT_MASK(16))) | (0 << 16);
writel(reg, vo->reg_base + 0xA3c);
}

disp_en = readl(vo->reg_base + VO_DISP_ENABLE);
disp_en &= ~(1 << plane_enable_bit);
Expand Down Expand Up @@ -488,8 +653,8 @@ static void canaan_vo_set_timing(struct canaan_vo *vo,
}

void canaan_vo_enable_crtc(struct canaan_vo *vo,
struct canaan_crtc *canaan_crtc,
struct drm_display_mode *adjusted_mode)
struct canaan_crtc *canaan_crtc,
struct drm_display_mode *adjusted_mode)
{
canaan_vo_init(vo);
// set timing
Expand Down Expand Up @@ -529,6 +694,7 @@ static struct canaan_plane_config
{
.id = 0,
.name = "video_3",
.supported_rotations = 0,
.formats = video_plane_formats,
.num_formats = ARRAY_SIZE(video_plane_formats),
.plane_type = DRM_PLANE_TYPE_OVERLAY,
Expand All @@ -540,6 +706,7 @@ static struct canaan_plane_config
{
.id = 1,
.name = "OSD4",
.supported_rotations = 0,
.formats = osd_plane_formats,
.num_formats = ARRAY_SIZE(osd_plane_formats),
.plane_type = DRM_PLANE_TYPE_PRIMARY,
Expand All @@ -551,6 +718,7 @@ static struct canaan_plane_config
{
.id = 2,
.name = "OSD5",
.supported_rotations = 0,
.formats = osd_plane_formats,
.num_formats = ARRAY_SIZE(osd_plane_formats),
.plane_type = DRM_PLANE_TYPE_CURSOR,
Expand All @@ -562,6 +730,7 @@ static struct canaan_plane_config
{
.id = 3,
.name = "OSD6",
.supported_rotations = 0,
.formats = osd_plane_formats,
.num_formats = ARRAY_SIZE(osd_plane_formats),
.plane_type = DRM_PLANE_TYPE_OVERLAY,
Expand All @@ -573,6 +742,7 @@ static struct canaan_plane_config
{
.id = 4,
.name = "OSD7",
.supported_rotations = 0,
.formats = osd_plane_formats,
.num_formats = ARRAY_SIZE(osd_plane_formats),
.plane_type = DRM_PLANE_TYPE_OVERLAY,
Expand All @@ -584,13 +754,27 @@ static struct canaan_plane_config
{
.id = 5,
.name = "video_2",
.supported_rotations = 0,
.formats = video_plane_formats,
.num_formats = ARRAY_SIZE(video_plane_formats),
.plane_type = DRM_PLANE_TYPE_OVERLAY,
.plane_offset = VO_LAYER2_OFFSET,
.plane_enable_bit = 2,
.xctl_reg_offset = VO_DISP_LAYER2_XCTL,
.yctl_reg_offset = VO_DISP_LAYER2_YCTL,
},
{
.id = 6,
.name = "video_3",
.supported_rotations = DRM_MODE_ROTATE_90 | DRM_MODE_ROTATE_270 |
DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y,
.formats = video_plane_formats,
.num_formats = ARRAY_SIZE(video_plane_formats),
.plane_type = DRM_PLANE_TYPE_OVERLAY,
.plane_offset = VO_LAYER1_OFFSET,
.plane_enable_bit = 1,
.xctl_reg_offset = VO_DISP_LAYER1_XCTL,
.yctl_reg_offset = VO_DISP_LAYER1_YCTL,
}
};

Expand Down
2 changes: 1 addition & 1 deletion drivers/gpu/drm/canaan/canaan_vo.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
#ifndef __CANAAN_VO_H__
#define __CANAAN_VO_H__

#define CANAAN_PLANE_NUMBER 6
#define CANAAN_PLANE_NUMBER 7

struct canaan_vo {
struct device *dev;
Expand Down
12 changes: 12 additions & 0 deletions drivers/gpu/drm/canaan/canaan_vo_regs.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,18 @@
#define VO_DISP_OSD7_XCTL 0x840
#define VO_DISP_OSD7_YCTL 0x844

#define VO_LAYER1_OFFSET 0xA20
#define VO_LAYER1_CTL 0x0
#define VO_LAYER1_ACT_SIZE 0x4
#define VO_LAYER1_STRIDE 0x8
#define VO_LAYER1_Y_ADDR0 0xc
#define VO_LAYER1_UV_ADDR0 0x10
#define VO_LAYER1_Y_ADDR1 0x14
#define VO_LAYER1_UV_ADDR1 0x18
#define VO_LAYER1_ADDR_SEL_MODE 0x1c



#define VO_LAYER2_OFFSET 0x200

#define VO_LAYER3_OFFSET 0x240
Expand Down

0 comments on commit f050fc6

Please sign in to comment.