// SPDX-License-Identifier: GPL-2.0-only /* * (C) COPYRIGHT 2016 ARM Limited. All rights reserved. * Author: Liviu Dudau <Liviu.Dudau@arm.com> * * ARM Mali DP500/DP550/DP650 hardware manipulation routines. This is where * the difference between various versions of the hardware is being dealt with * in an attempt to provide to the rest of the driver code a unified view
*/
enum {
MW_NOT_ENABLED = 0, /* SE writeback not enabled */
MW_ONESHOT, /* SE in one-shot mode for writeback */
MW_START, /* SE started writeback */
MW_RESTART, /* SE will start another writeback after this one */
MW_STOP, /* SE needs to stop after this writeback */
};
/* All 8 or 10 bit YUV 444 formats. */ /* In DP550, 10 bit YUV 420 format also supported */
DRM_FORMAT_MOD_ARM_AFBC(AFBC_SIZE_16X16 | AFBC_SPARSE | AFBC_SPLIT),
/* YUV 420, 422 P1 8 bit and YUV 444 8 bit/10 bit formats */
DRM_FORMAT_MOD_ARM_AFBC(AFBC_SIZE_16X16 | AFBC_SPARSE),
DRM_FORMAT_MOD_ARM_AFBC(AFBC_SIZE_16X16),
malidp_hw_setbits(hwdev, MALIDP500_DC_CONFIG_REQ, MALIDP500_DC_CONTROL); while (count) {
status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS); if ((status & MALIDP500_DC_CONFIG_REQ) == MALIDP500_DC_CONFIG_REQ) break; /* * entering config mode can take as long as the rendering * of a full frame, hence the long sleep here
*/
usleep_range(1000, 10000);
count--;
}
WARN(count == 0, "timeout while entering config mode");
}
/* * Program the RQoS register to avoid high resolutions flicker * issue on the LS1028A.
*/ if (hwdev->arqos_value) {
val = hwdev->arqos_value;
malidp_hw_setbits(hwdev, val, MALIDP500_RQOS_QUALITY);
}
}
int malidp_format_get_bpp(u32 fmt)
{ conststruct drm_format_info *info = drm_format_info(fmt); int bpp = info->cpp[0] * 8;
if (bpp == 0) { switch (fmt) { case DRM_FORMAT_VUY101010:
bpp = 30; break; case DRM_FORMAT_YUV420_10BIT:
bpp = 15; break; case DRM_FORMAT_YUV420_8BIT:
bpp = 12; break; default:
bpp = 0;
}
}
return bpp;
}
staticint malidp500_rotmem_required(struct malidp_hw_device *hwdev, u16 w,
u16 h, u32 fmt, bool has_modifier)
{ /* * Each layer needs enough rotation memory to fit 8 lines * worth of pixel data. Required size is then: * size = rotated_width * (bpp / 8) * 8;
*/ int bpp = malidp_format_get_bpp(fmt);
/* * mclk = max(a, 1.5) * pxlclk * * To avoid float calculaiton, using 15 instead of 1.5 and div by * 10 to get mclk.
*/ if (se_config->scale_enable) {
a = 15 * input_size / (htotal * se_config->output_h); if (a < 15)
a = 15;
}
mclk = a * pxlclk / 10;
ret = clk_get_rate(hwdev->mclk); if (ret < mclk) {
DRM_DEBUG_DRIVER("mclk requirement of %lu kHz can't be met.\n",
mclk / 1000); return -EINVAL;
} return ret;
}
/* restart the writeback if already enabled */ if (hwdev->mw_state != MW_NOT_ENABLED)
hwdev->mw_state = MW_RESTART; else
hwdev->mw_state = MW_START;
malidp_hw_write(hwdev, fmt_id, base + MALIDP_MW_FORMAT); switch (num_planes) { case 2:
malidp_hw_write(hwdev, lower_32_bits(addrs[1]), base + MALIDP_MW_P2_PTR_LOW);
malidp_hw_write(hwdev, upper_32_bits(addrs[1]), base + MALIDP_MW_P2_PTR_HIGH);
malidp_hw_write(hwdev, pitches[1], base + MALIDP_MW_P2_STRIDE);
fallthrough; case 1:
malidp_hw_write(hwdev, lower_32_bits(addrs[0]), base + MALIDP_MW_P1_PTR_LOW);
malidp_hw_write(hwdev, upper_32_bits(addrs[0]), base + MALIDP_MW_P1_PTR_HIGH);
malidp_hw_write(hwdev, pitches[0], base + MALIDP_MW_P1_STRIDE); break; default:
WARN(1, "Invalid number of planes");
}
switch (ln_size) { case 0:
hwdev->max_line_size = SZ_2K; /* two banks of 64KB for rotation memory */
rsize = 64; break; case 1:
hwdev->max_line_size = SZ_4K; /* two banks of 128KB for rotation memory */
rsize = 128; break; case 2:
hwdev->max_line_size = 1280; /* two banks of 40KB for rotation memory */
rsize = 40; break; case 3: /* reserved value */
hwdev->max_line_size = 0; return -EINVAL;
}
malidp_hw_setbits(hwdev, MALIDP550_DC_CONFIG_REQ, MALIDP550_DC_CONTROL); while (count) {
status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS); if ((status & MALIDP550_DC_CONFIG_REQ) == MALIDP550_DC_CONFIG_REQ) break; /* * entering config mode can take as long as the rendering * of a full frame, hence the long sleep here
*/
usleep_range(1000, 10000);
count--;
}
WARN(count == 0, "timeout while entering config mode");
}
malidp_hw_write(hwdev, hwdev->output_color_depth,
hwdev->hw->map.out_depth_base);
malidp_hw_write(hwdev, val, MALIDP550_DE_CONTROL); /* * Mali-DP550 and Mali-DP650 encode the background color like this: * - red @ MALIDP550_DE_BGND_COLOR[23:16] * - green @ MALIDP550_DE_BGND_COLOR[15:8] * - blue @ MALIDP550_DE_BGND_COLOR[7:0] * * We need to truncate the least significant 4 bits from the default * MALIDP_BGND_COLOR_x values
*/
val = (((MALIDP_BGND_COLOR_R >> 4) & 0xff) << 16) |
(((MALIDP_BGND_COLOR_G >> 4) & 0xff) << 8) |
((MALIDP_BGND_COLOR_B >> 4) & 0xff);
malidp_hw_write(hwdev, val, MALIDP550_DE_BGND_COLOR);
val = MALIDP_DE_H_FRONTPORCH(mode->hfront_porch) |
MALIDP_DE_H_BACKPORCH(mode->hback_porch);
malidp_hw_write(hwdev, val, MALIDP550_TIMINGS_BASE + MALIDP_DE_H_TIMINGS);
val = MALIDP550_DE_V_FRONTPORCH(mode->vfront_porch) |
MALIDP_DE_V_BACKPORCH(mode->vback_porch);
malidp_hw_write(hwdev, val, MALIDP550_TIMINGS_BASE + MALIDP_DE_V_TIMINGS);
val = MALIDP_DE_H_SYNCWIDTH(mode->hsync_len) |
MALIDP_DE_V_SYNCWIDTH(mode->vsync_len); if (mode->flags & DISPLAY_FLAGS_HSYNC_HIGH)
val |= MALIDP550_HSYNCPOL; if (mode->flags & DISPLAY_FLAGS_VSYNC_HIGH)
val |= MALIDP550_VSYNCPOL;
malidp_hw_write(hwdev, val, MALIDP550_TIMINGS_BASE + MALIDP_DE_SYNC_WIDTH);
val = MALIDP_DE_H_ACTIVE(mode->hactive) | MALIDP_DE_V_ACTIVE(mode->vactive);
malidp_hw_write(hwdev, val, MALIDP550_TIMINGS_BASE + MALIDP_DE_HV_ACTIVE);
switch (fmt) { /* 8 lines at 4 bytes per pixel */ case DRM_FORMAT_ARGB2101010: case DRM_FORMAT_ABGR2101010: case DRM_FORMAT_RGBA1010102: case DRM_FORMAT_BGRA1010102: case DRM_FORMAT_ARGB8888: case DRM_FORMAT_ABGR8888: case DRM_FORMAT_RGBA8888: case DRM_FORMAT_BGRA8888: case DRM_FORMAT_XRGB8888: case DRM_FORMAT_XBGR8888: case DRM_FORMAT_RGBX8888: case DRM_FORMAT_BGRX8888: case DRM_FORMAT_RGB888: case DRM_FORMAT_BGR888: /* 16 lines at 2 bytes per pixel */ case DRM_FORMAT_RGBA5551: case DRM_FORMAT_ABGR1555: case DRM_FORMAT_RGB565: case DRM_FORMAT_BGR565: case DRM_FORMAT_UYVY: case DRM_FORMAT_YUYV: case DRM_FORMAT_X0L0:
bytes_per_column = 32; break; /* 16 lines at 1.5 bytes per pixel */ case DRM_FORMAT_NV12: case DRM_FORMAT_YUV420: /* 8 lines at 3 bytes per pixel */ case DRM_FORMAT_VUY888: /* 16 lines at 12 bits per pixel */ case DRM_FORMAT_YUV420_8BIT: /* 8 lines at 3 bytes per pixel */ case DRM_FORMAT_P010:
bytes_per_column = 24; break; /* 8 lines at 30 bits per pixel */ case DRM_FORMAT_VUY101010: /* 16 lines at 15 bits per pixel */ case DRM_FORMAT_YUV420_10BIT:
bytes_per_column = 30; break; default: return -EINVAL;
}
malidp_hw_write(hwdev, fmt_id, base + MALIDP_MW_FORMAT); switch (num_planes) { case 2:
malidp_hw_write(hwdev, lower_32_bits(addrs[1]), base + MALIDP_MW_P2_PTR_LOW);
malidp_hw_write(hwdev, upper_32_bits(addrs[1]), base + MALIDP_MW_P2_PTR_HIGH);
malidp_hw_write(hwdev, pitches[1], base + MALIDP_MW_P2_STRIDE);
fallthrough; case 1:
malidp_hw_write(hwdev, lower_32_bits(addrs[0]), base + MALIDP_MW_P1_PTR_LOW);
malidp_hw_write(hwdev, upper_32_bits(addrs[0]), base + MALIDP_MW_P1_PTR_HIGH);
malidp_hw_write(hwdev, pitches[0], base + MALIDP_MW_P1_STRIDE); break; default:
WARN(1, "Invalid number of planes");
}
for (i = 0; i < map->n_pixel_formats; i++) { if (((map->pixel_formats[i].layer & layer_id) == layer_id) &&
(map->pixel_formats[i].format == format)) { /* * In some DP550 and DP650, DRM_FORMAT_YUYV + AFBC modifier * is supported by a different h/w format id than * DRM_FORMAT_YUYV (only).
*/ if (format == DRM_FORMAT_YUYV &&
(has_modifier) &&
(map->features & MALIDP_DEVICE_AFBC_YUYV_USE_422_P2)) return AFBC_YUV_422_FORMAT_ID; else return map->pixel_formats[i].id;
}
}
return MALIDP_INVALID_FORMAT_ID;
}
bool malidp_hw_format_is_linear_only(u32 format)
{ switch (format) { case DRM_FORMAT_ARGB2101010: case DRM_FORMAT_RGBA1010102: case DRM_FORMAT_BGRA1010102: case DRM_FORMAT_ARGB8888: case DRM_FORMAT_RGBA8888: case DRM_FORMAT_BGRA8888: case DRM_FORMAT_XBGR8888: case DRM_FORMAT_XRGB8888: case DRM_FORMAT_RGBX8888: case DRM_FORMAT_BGRX8888: case DRM_FORMAT_RGB888: case DRM_FORMAT_RGB565: case DRM_FORMAT_ARGB1555: case DRM_FORMAT_RGBA5551: case DRM_FORMAT_BGRA5551: case DRM_FORMAT_UYVY: case DRM_FORMAT_XYUV8888: case DRM_FORMAT_XVYU2101010: case DRM_FORMAT_X0L2: case DRM_FORMAT_X0L0: returntrue; default: returnfalse;
}
}
bool malidp_hw_format_is_afbc_only(u32 format)
{ switch (format) { case DRM_FORMAT_VUY888: case DRM_FORMAT_VUY101010: case DRM_FORMAT_YUV420_8BIT: case DRM_FORMAT_YUV420_10BIT: returntrue; default: returnfalse;
}
}
hwdev = malidp->dev;
hw = hwdev->hw;
de = &hw->map.de_irq_map;
/* * if we are suspended it is likely that we were invoked because * we share an interrupt line with some other driver, don't try * to read the hardware registers
*/ if (hwdev->pm_suspended) return IRQ_NONE;
/* first handle the config valid IRQ */
dc_status = malidp_hw_read(hwdev, hw->map.dc_base + MALIDP_REG_STATUS); if (dc_status & hw->map.dc_irq_map.vsync_irq) {
malidp_hw_clear_irq(hwdev, MALIDP_DC_BLOCK, dc_status); /* do we have a page flip event? */ if (malidp->event != NULL) {
spin_lock(&drm->event_lock);
drm_crtc_send_vblank_event(&malidp->crtc, malidp->event);
malidp->event = NULL;
spin_unlock(&drm->event_lock);
}
atomic_set(&malidp->config_valid, MALIDP_CONFIG_VALID_DONE);
ret = IRQ_WAKE_THREAD;
}
status = malidp_hw_read(hwdev, MALIDP_REG_STATUS); if (!(status & de->irq_mask)) return ret;
mask = malidp_hw_read(hwdev, MALIDP_REG_MASKIRQ); /* keep the status of the enabled interrupts, plus the error bits */
status &= (mask | de->err_mask); if ((status & de->vsync_irq) && malidp->crtc.enabled)
drm_crtc_handle_vblank(&malidp->crtc);
/* * if we are suspended it is likely that we were invoked because * we share an interrupt line with some other driver, don't try * to read the hardware registers
*/ if (hwdev->pm_suspended) return IRQ_NONE;
status = malidp_hw_read(hwdev, hw->map.se_base + MALIDP_REG_STATUS); if (!(status & (se->irq_mask | se->err_mask))) return IRQ_NONE;
#ifdef CONFIG_DEBUG_FS if (status & se->err_mask)
malidp_error(malidp, &malidp->se_errors, status,
drm_crtc_vblank_count(&malidp->crtc)); #endif
mask = malidp_hw_read(hwdev, hw->map.se_base + MALIDP_REG_MASKIRQ);
status &= mask;
if (status & se->vsync_irq) { switch (hwdev->mw_state) { case MW_ONESHOT:
drm_writeback_signal_completion(&malidp->mw_connector, 0); break; case MW_STOP:
drm_writeback_signal_completion(&malidp->mw_connector, 0); /* disable writeback after stop */
hwdev->mw_state = MW_NOT_ENABLED; break; case MW_RESTART:
drm_writeback_signal_completion(&malidp->mw_connector, 0);
fallthrough; /* to a new start */ case MW_START: /* writeback started, need to emulate one-shot mode */
hw->disable_memwrite(hwdev); /* * only set config_valid HW bit if there is no other update * in progress or if we raced ahead of the DE IRQ handler * and config_valid flag will not be update until later
*/
status = malidp_hw_read(hwdev, hw->map.dc_base + MALIDP_REG_STATUS); if ((atomic_read(&malidp->config_valid) != MALIDP_CONFIG_START) ||
(status & hw->map.dc_irq_map.vsync_irq))
hw->set_config_valid(hwdev, 1); break;
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.