diff options
Diffstat (limited to 'drivers/gpu/drm/arm')
17 files changed, 335 insertions, 151 deletions
diff --git a/drivers/gpu/drm/arm/display/Kconfig b/drivers/gpu/drm/arm/display/Kconfig index e87ff8623076..cec0639e3aa1 100644 --- a/drivers/gpu/drm/arm/display/Kconfig +++ b/drivers/gpu/drm/arm/display/Kconfig @@ -12,9 +12,3 @@ config DRM_KOMEDA Processor driver. It supports the D71 variants of the hardware. If compiled as a module it will be called komeda. - -config DRM_KOMEDA_ERROR_PRINT - bool "Enable komeda error print" - depends on DRM_KOMEDA - help - Choose this option to enable error printing. diff --git a/drivers/gpu/drm/arm/display/include/malidp_product.h b/drivers/gpu/drm/arm/display/include/malidp_product.h index 1053b11352eb..16a8a2c22c42 100644 --- a/drivers/gpu/drm/arm/display/include/malidp_product.h +++ b/drivers/gpu/drm/arm/display/include/malidp_product.h @@ -18,7 +18,8 @@ #define MALIDP_CORE_ID_STATUS(__core_id) (((__u32)(__core_id)) & 0xFF) /* Mali-display product IDs */ -#define MALIDP_D71_PRODUCT_ID 0x0071 +#define MALIDP_D71_PRODUCT_ID 0x0071 +#define MALIDP_D32_PRODUCT_ID 0x0032 union komeda_config_id { struct { diff --git a/drivers/gpu/drm/arm/display/komeda/Makefile b/drivers/gpu/drm/arm/display/komeda/Makefile index f095a1c68ac7..1931a7fa1a14 100644 --- a/drivers/gpu/drm/arm/display/komeda/Makefile +++ b/drivers/gpu/drm/arm/display/komeda/Makefile @@ -16,12 +16,11 @@ komeda-y := \ komeda_crtc.o \ komeda_plane.o \ komeda_wb_connector.o \ - komeda_private_obj.o + komeda_private_obj.o \ + komeda_event.o komeda-y += \ d71/d71_dev.o \ d71/d71_component.o -komeda-$(CONFIG_DRM_KOMEDA_ERROR_PRINT) += komeda_event.o - obj-$(CONFIG_DRM_KOMEDA) += komeda.o diff --git a/drivers/gpu/drm/arm/display/komeda/d71/d71_component.c b/drivers/gpu/drm/arm/display/komeda/d71/d71_component.c index f0ba26e282c3..8a02ade369db 100644 --- a/drivers/gpu/drm/arm/display/komeda/d71/d71_component.c +++ b/drivers/gpu/drm/arm/display/komeda/d71/d71_component.c @@ -1044,7 +1044,9 @@ static int d71_merger_init(struct d71_dev *d71, static void d71_improc_update(struct komeda_component *c, struct komeda_component_state *state) { + struct drm_crtc_state *crtc_st = state->crtc->state; struct komeda_improc_state *st = to_improc_st(state); + struct d71_pipeline *pipe = to_d71_pipeline(c->pipeline); u32 __iomem *reg = c->reg; u32 index, mask = 0, ctrl = 0; @@ -1055,6 +1057,24 @@ static void d71_improc_update(struct komeda_component *c, malidp_write32(reg, BLK_SIZE, HV_SIZE(st->hsize, st->vsize)); malidp_write32(reg, IPS_DEPTH, st->color_depth); + if (crtc_st->color_mgmt_changed) { + mask |= IPS_CTRL_FT | IPS_CTRL_RGB; + + if (crtc_st->gamma_lut) { + malidp_write_group(pipe->dou_ft_coeff_addr, FT_COEFF0, + KOMEDA_N_GAMMA_COEFFS, + st->fgamma_coeffs); + ctrl |= IPS_CTRL_FT; /* enable gamma */ + } + + if (crtc_st->ctm) { + malidp_write_group(reg, IPS_RGB_RGB_COEFF0, + KOMEDA_N_CTM_COEFFS, + st->ctm_coeffs); + ctrl |= IPS_CTRL_RGB; /* enable gamut */ + } + } + mask |= IPS_CTRL_YUV | IPS_CTRL_CHD422 | IPS_CTRL_CHD420; /* config color format */ @@ -1250,7 +1270,7 @@ static int d71_timing_ctrlr_init(struct d71_dev *d71, ctrlr = to_ctrlr(c); - ctrlr->supports_dual_link = true; + ctrlr->supports_dual_link = d71->supports_dual_link; return 0; } diff --git a/drivers/gpu/drm/arm/display/komeda/d71/d71_dev.c b/drivers/gpu/drm/arm/display/komeda/d71/d71_dev.c index 822b23a1ce75..00fa56c29b3e 100644 --- a/drivers/gpu/drm/arm/display/komeda/d71/d71_dev.c +++ b/drivers/gpu/drm/arm/display/komeda/d71/d71_dev.c @@ -20,8 +20,10 @@ static u64 get_lpu_event(struct d71_pipeline *d71_pipeline) evts |= KOMEDA_EVENT_IBSY; if (raw_status & LPU_IRQ_EOW) evts |= KOMEDA_EVENT_EOW; + if (raw_status & LPU_IRQ_OVR) + evts |= KOMEDA_EVENT_OVR; - if (raw_status & (LPU_IRQ_ERR | LPU_IRQ_IBSY)) { + if (raw_status & (LPU_IRQ_ERR | LPU_IRQ_IBSY | LPU_IRQ_OVR)) { u32 restore = 0, tbu_status; /* Check error of LPU status */ status = malidp_read32(reg, BLK_STATUS); @@ -45,6 +47,15 @@ static u64 get_lpu_event(struct d71_pipeline *d71_pipeline) restore |= LPU_STATUS_ACE3; evts |= KOMEDA_ERR_ACE3; } + if (status & LPU_STATUS_FEMPTY) { + restore |= LPU_STATUS_FEMPTY; + evts |= KOMEDA_EVENT_EMPTY; + } + if (status & LPU_STATUS_FFULL) { + restore |= LPU_STATUS_FFULL; + evts |= KOMEDA_EVENT_FULL; + } + if (restore != 0) malidp_write32_mask(reg, BLK_STATUS, restore, 0); @@ -371,23 +382,33 @@ static int d71_enum_resources(struct komeda_dev *mdev) goto err_cleanup; } - /* probe PERIPH */ + /* Only the legacy HW has the periph block, the newer merges the periph + * into GCU + */ value = malidp_read32(d71->periph_addr, BLK_BLOCK_INFO); - if (BLOCK_INFO_BLK_TYPE(value) != D71_BLK_TYPE_PERIPH) { - DRM_ERROR("access blk periph but got blk: %d.\n", - BLOCK_INFO_BLK_TYPE(value)); - err = -EINVAL; - goto err_cleanup; + if (BLOCK_INFO_BLK_TYPE(value) != D71_BLK_TYPE_PERIPH) + d71->periph_addr = NULL; + + if (d71->periph_addr) { + /* probe PERIPHERAL in legacy HW */ + value = malidp_read32(d71->periph_addr, PERIPH_CONFIGURATION_ID); + + d71->max_line_size = value & PERIPH_MAX_LINE_SIZE ? 4096 : 2048; + d71->max_vsize = 4096; + d71->num_rich_layers = value & PERIPH_NUM_RICH_LAYERS ? 2 : 1; + d71->supports_dual_link = !!(value & PERIPH_SPLIT_EN); + d71->integrates_tbu = !!(value & PERIPH_TBU_EN); + } else { + value = malidp_read32(d71->gcu_addr, GCU_CONFIGURATION_ID0); + d71->max_line_size = GCU_MAX_LINE_SIZE(value); + d71->max_vsize = GCU_MAX_NUM_LINES(value); + + value = malidp_read32(d71->gcu_addr, GCU_CONFIGURATION_ID1); + d71->num_rich_layers = GCU_NUM_RICH_LAYERS(value); + d71->supports_dual_link = GCU_DISPLAY_SPLIT_EN(value); + d71->integrates_tbu = GCU_DISPLAY_TBU_EN(value); } - value = malidp_read32(d71->periph_addr, PERIPH_CONFIGURATION_ID); - - d71->max_line_size = value & PERIPH_MAX_LINE_SIZE ? 4096 : 2048; - d71->max_vsize = 4096; - d71->num_rich_layers = value & PERIPH_NUM_RICH_LAYERS ? 2 : 1; - d71->supports_dual_link = value & PERIPH_SPLIT_EN ? true : false; - d71->integrates_tbu = value & PERIPH_TBU_EN ? true : false; - for (i = 0; i < d71->num_pipelines; i++) { pipe = komeda_pipeline_add(mdev, sizeof(struct d71_pipeline), &d71_pipeline_funcs); @@ -414,8 +435,11 @@ static int d71_enum_resources(struct komeda_dev *mdev) d71->pipes[i] = to_d71_pipeline(pipe); } - /* loop the register blks and probe */ - i = 2; /* exclude GCU and PERIPH */ + /* loop the register blks and probe. + * NOTE: d71->num_blocks includes reserved blocks. + * d71->num_blocks = GCU + valid blocks + reserved blocks + */ + i = 1; /* exclude GCU */ offset = D71_BLOCK_SIZE; /* skip GCU */ while (i < d71->num_blocks) { blk_base = mdev->reg_base + (offset >> 2); @@ -425,9 +449,9 @@ static int d71_enum_resources(struct komeda_dev *mdev) err = d71_probe_block(d71, &blk, blk_base); if (err) goto err_cleanup; - i++; } + i++; offset += D71_BLOCK_SIZE; } @@ -594,10 +618,26 @@ static const struct komeda_dev_funcs d71_chip_funcs = { const struct komeda_dev_funcs * d71_identify(u32 __iomem *reg_base, struct komeda_chip_info *chip) { + const struct komeda_dev_funcs *funcs; + u32 product_id; + + chip->core_id = malidp_read32(reg_base, GLB_CORE_ID); + + product_id = MALIDP_CORE_ID_PRODUCT_ID(chip->core_id); + + switch (product_id) { + case MALIDP_D71_PRODUCT_ID: + case MALIDP_D32_PRODUCT_ID: + funcs = &d71_chip_funcs; + break; + default: + DRM_ERROR("Unsupported product: 0x%x\n", product_id); + return NULL; + } + chip->arch_id = malidp_read32(reg_base, GLB_ARCH_ID); - chip->core_id = malidp_read32(reg_base, GLB_CORE_ID); chip->core_info = malidp_read32(reg_base, GLB_CORE_INFO); chip->bus_width = D71_BUS_WIDTH_16_BYTES; - return &d71_chip_funcs; + return funcs; } diff --git a/drivers/gpu/drm/arm/display/komeda/d71/d71_regs.h b/drivers/gpu/drm/arm/display/komeda/d71/d71_regs.h index 1727dc993909..e80172a0b320 100644 --- a/drivers/gpu/drm/arm/display/komeda/d71/d71_regs.h +++ b/drivers/gpu/drm/arm/display/komeda/d71/d71_regs.h @@ -72,6 +72,19 @@ #define GCU_CONTROL_MODE(x) ((x) & 0x7) #define GCU_CONTROL_SRST BIT(16) +/* GCU_CONFIGURATION registers */ +#define GCU_CONFIGURATION_ID0 0x100 +#define GCU_CONFIGURATION_ID1 0x104 + +/* GCU configuration */ +#define GCU_MAX_LINE_SIZE(x) ((x) & 0xFFFF) +#define GCU_MAX_NUM_LINES(x) ((x) >> 16) +#define GCU_NUM_RICH_LAYERS(x) ((x) & 0x7) +#define GCU_NUM_PIPELINES(x) (((x) >> 3) & 0x7) +#define GCU_NUM_SCALERS(x) (((x) >> 6) & 0x7) +#define GCU_DISPLAY_SPLIT_EN(x) (((x) >> 16) & 0x1) +#define GCU_DISPLAY_TBU_EN(x) (((x) >> 17) & 0x1) + /* GCU opmode */ #define INACTIVE_MODE 0 #define TBU_CONNECT_MODE 1 @@ -162,6 +175,7 @@ #define TBU_DOUTSTDCAPB_MASK 0x3F /* LPU_IRQ_BITS */ +#define LPU_IRQ_OVR BIT(9) #define LPU_IRQ_IBSY BIT(10) #define LPU_IRQ_ERR BIT(11) #define LPU_IRQ_EOW BIT(12) @@ -172,6 +186,8 @@ #define LPU_STATUS_AXIE BIT(4) #define LPU_STATUS_AXIRP BIT(5) #define LPU_STATUS_AXIWP BIT(6) +#define LPU_STATUS_FEMPTY BIT(11) +#define LPU_STATUS_FFULL BIT(14) #define LPU_STATUS_ACE0 BIT(16) #define LPU_STATUS_ACE1 BIT(17) #define LPU_STATUS_ACE2 BIT(18) diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_color_mgmt.c b/drivers/gpu/drm/arm/display/komeda/komeda_color_mgmt.c index 9d14a92dbb17..d8e449e6ebda 100644 --- a/drivers/gpu/drm/arm/display/komeda/komeda_color_mgmt.c +++ b/drivers/gpu/drm/arm/display/komeda/komeda_color_mgmt.c @@ -65,3 +65,69 @@ const s32 *komeda_select_yuv2rgb_coeffs(u32 color_encoding, u32 color_range) return coeffs; } + +struct gamma_curve_sector { + u32 boundary_start; + u32 num_of_segments; + u32 segment_width; +}; + +struct gamma_curve_segment { + u32 start; + u32 end; +}; + +static struct gamma_curve_sector sector_tbl[] = { + { 0, 4, 4 }, + { 16, 4, 4 }, + { 32, 4, 8 }, + { 64, 4, 16 }, + { 128, 4, 32 }, + { 256, 4, 64 }, + { 512, 16, 32 }, + { 1024, 24, 128 }, +}; + +static void +drm_lut_to_coeffs(struct drm_property_blob *lut_blob, u32 *coeffs, + struct gamma_curve_sector *sector_tbl, u32 num_sectors) +{ + struct drm_color_lut *lut; + u32 i, j, in, num = 0; + + if (!lut_blob) + return; + + lut = lut_blob->data; + + for (i = 0; i < num_sectors; i++) { + for (j = 0; j < sector_tbl[i].num_of_segments; j++) { + in = sector_tbl[i].boundary_start + + j * sector_tbl[i].segment_width; + + coeffs[num++] = drm_color_lut_extract(lut[in].red, + KOMEDA_COLOR_PRECISION); + } + } + + coeffs[num] = BIT(KOMEDA_COLOR_PRECISION); +} + +void drm_lut_to_fgamma_coeffs(struct drm_property_blob *lut_blob, u32 *coeffs) +{ + drm_lut_to_coeffs(lut_blob, coeffs, sector_tbl, ARRAY_SIZE(sector_tbl)); +} + +void drm_ctm_to_coeffs(struct drm_property_blob *ctm_blob, u32 *coeffs) +{ + struct drm_color_ctm *ctm; + u32 i; + + if (!ctm_blob) + return; + + ctm = ctm_blob->data; + + for (i = 0; i < KOMEDA_N_CTM_COEFFS; i++) + coeffs[i] = drm_color_ctm_s31_32_to_qm_n(ctm->matrix[i], 3, 12); +} diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_color_mgmt.h b/drivers/gpu/drm/arm/display/komeda/komeda_color_mgmt.h index a2df218f58e7..2f4668466112 100644 --- a/drivers/gpu/drm/arm/display/komeda/komeda_color_mgmt.h +++ b/drivers/gpu/drm/arm/display/komeda/komeda_color_mgmt.h @@ -11,7 +11,15 @@ #include <drm/drm_color_mgmt.h> #define KOMEDA_N_YUV2RGB_COEFFS 12 +#define KOMEDA_N_RGB2YUV_COEFFS 12 +#define KOMEDA_COLOR_PRECISION 12 +#define KOMEDA_N_GAMMA_COEFFS 65 +#define KOMEDA_COLOR_LUT_SIZE BIT(KOMEDA_COLOR_PRECISION) +#define KOMEDA_N_CTM_COEFFS 9 + +void drm_lut_to_fgamma_coeffs(struct drm_property_blob *lut_blob, u32 *coeffs); +void drm_ctm_to_coeffs(struct drm_property_blob *ctm_blob, u32 *coeffs); const s32 *komeda_select_yuv2rgb_coeffs(u32 color_encoding, u32 color_range); -#endif +#endif /*_KOMEDA_COLOR_MGMT_H_*/ diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c b/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c index 252015210fbc..56bd938961ee 100644 --- a/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c +++ b/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c @@ -5,6 +5,7 @@ * */ #include <linux/clk.h> +#include <linux/pm_runtime.h> #include <linux/spinlock.h> #include <drm/drm_atomic.h> @@ -274,6 +275,7 @@ static void komeda_crtc_atomic_enable(struct drm_crtc *crtc, struct drm_crtc_state *old) { + pm_runtime_get_sync(crtc->dev->dev); komeda_crtc_prepare(to_kcrtc(crtc)); drm_crtc_vblank_on(crtc); WARN_ON(drm_crtc_vblank_get(crtc)); @@ -372,6 +374,7 @@ komeda_crtc_atomic_disable(struct drm_crtc *crtc, drm_crtc_vblank_put(crtc); drm_crtc_vblank_off(crtc); komeda_crtc_unprepare(kcrtc); + pm_runtime_put(crtc->dev->dev); } static void @@ -617,6 +620,8 @@ static int komeda_crtc_add(struct komeda_kms_dev *kms, crtc->port = kcrtc->master->of_output_port; + drm_crtc_enable_color_mgmt(crtc, 0, true, KOMEDA_COLOR_LUT_SIZE); + return err; } diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_dev.c b/drivers/gpu/drm/arm/display/komeda/komeda_dev.c index 937a6d4c4865..1d767473ba8a 100644 --- a/drivers/gpu/drm/arm/display/komeda/komeda_dev.c +++ b/drivers/gpu/drm/arm/display/komeda/komeda_dev.c @@ -10,6 +10,7 @@ #include <linux/of_graph.h> #include <linux/of_reserved_mem.h> #include <linux/platform_device.h> +#include <linux/pm_runtime.h> #include <linux/dma-mapping.h> #ifdef CONFIG_DEBUG_FS #include <linux/debugfs.h> @@ -27,12 +28,16 @@ static int komeda_register_show(struct seq_file *sf, void *x) seq_puts(sf, "\n====== Komeda register dump =========\n"); + pm_runtime_get_sync(mdev->dev); + if (mdev->funcs->dump_register) mdev->funcs->dump_register(mdev, sf); for (i = 0; i < mdev->n_pipelines; i++) komeda_pipeline_dump_register(mdev->pipelines[i], sf); + pm_runtime_put(mdev->dev); + return 0; } @@ -58,6 +63,8 @@ static void komeda_debugfs_init(struct komeda_dev *mdev) mdev->debugfs_root = debugfs_create_dir("komeda", NULL); debugfs_create_file("register", 0444, mdev->debugfs_root, mdev, &komeda_register_fops); + debugfs_create_x16("err_verbosity", 0664, mdev->debugfs_root, + &mdev->err_verbosity); } #endif @@ -113,22 +120,14 @@ static struct attribute_group komeda_sysfs_attr_group = { .attrs = komeda_sysfs_entries, }; -static int komeda_parse_pipe_dt(struct komeda_dev *mdev, struct device_node *np) +static int komeda_parse_pipe_dt(struct komeda_pipeline *pipe) { - struct komeda_pipeline *pipe; + struct device_node *np = pipe->of_node; struct clk *clk; - u32 pipe_id; - int ret = 0; - - ret = of_property_read_u32(np, "reg", &pipe_id); - if (ret != 0 || pipe_id >= mdev->n_pipelines) - return -EINVAL; - - pipe = mdev->pipelines[pipe_id]; clk = of_clk_get_by_name(np, "pxclk"); if (IS_ERR(clk)) { - DRM_ERROR("get pxclk for pipeline %d failed!\n", pipe_id); + DRM_ERROR("get pxclk for pipeline %d failed!\n", pipe->id); return PTR_ERR(clk); } pipe->pxlclk = clk; @@ -142,7 +141,6 @@ static int komeda_parse_pipe_dt(struct komeda_dev *mdev, struct device_node *np) of_graph_get_port_by_id(np, KOMEDA_OF_PORT_OUTPUT); pipe->dual_link = pipe->of_output_links[0] && pipe->of_output_links[1]; - pipe->of_node = of_node_get(np); return 0; } @@ -151,7 +149,9 @@ static int komeda_parse_dt(struct device *dev, struct komeda_dev *mdev) { struct platform_device *pdev = to_platform_device(dev); struct device_node *child, *np = dev->of_node; - int ret; + struct komeda_pipeline *pipe; + u32 pipe_id = U32_MAX; + int ret = -1; mdev->irq = platform_get_irq(pdev, 0); if (mdev->irq < 0) { @@ -166,37 +166,44 @@ static int komeda_parse_dt(struct device *dev, struct komeda_dev *mdev) ret = 0; for_each_available_child_of_node(np, child) { - if (of_node_cmp(child->name, "pipeline") == 0) { - ret = komeda_parse_pipe_dt(mdev, child); - if (ret) { - DRM_ERROR("parse pipeline dt error!\n"); - of_node_put(child); - break; + if (of_node_name_eq(child, "pipeline")) { + of_property_read_u32(child, "reg", &pipe_id); + if (pipe_id >= mdev->n_pipelines) { + DRM_WARN("Skip the redundant DT node: pipeline-%u.\n", + pipe_id); + continue; } + mdev->pipelines[pipe_id]->of_node = of_node_get(child); } } - return ret; + for (pipe_id = 0; pipe_id < mdev->n_pipelines; pipe_id++) { + pipe = mdev->pipelines[pipe_id]; + + if (!pipe->of_node) { + DRM_ERROR("Pipeline-%d doesn't have a DT node.\n", + pipe->id); + return -EINVAL; + } + ret = komeda_parse_pipe_dt(pipe); + if (ret) + return ret; + } + + return 0; } struct komeda_dev *komeda_dev_create(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); - const struct komeda_product_data *product; + komeda_identify_func komeda_identify; struct komeda_dev *mdev; - struct resource *io_res; int err = 0; - product = of_device_get_match_data(dev); - if (!product) + komeda_identify = of_device_get_match_data(dev); + if (!komeda_identify) return ERR_PTR(-ENODEV); - io_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!io_res) { - DRM_ERROR("No registers defined.\n"); - return ERR_PTR(-ENODEV); - } - mdev = devm_kzalloc(dev, sizeof(*mdev), GFP_KERNEL); if (!mdev) return ERR_PTR(-ENOMEM); @@ -204,7 +211,7 @@ struct komeda_dev *komeda_dev_create(struct device *dev) mutex_init(&mdev->lock); mdev->dev = dev; - mdev->reg_base = devm_ioremap_resource(dev, io_res); + mdev->reg_base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(mdev->reg_base)) { DRM_ERROR("Map register space failed.\n"); err = PTR_ERR(mdev->reg_base); @@ -222,11 +229,9 @@ struct komeda_dev *komeda_dev_create(struct device *dev) clk_prepare_enable(mdev->aclk); - mdev->funcs = product->identify(mdev->reg_base, &mdev->chip); - if (!komeda_product_match(mdev, product->product_id)) { - DRM_ERROR("DT configured %x mismatch with real HW %x.\n", - product->product_id, - MALIDP_CORE_ID_PRODUCT_ID(mdev->chip.core_id)); + mdev->funcs = komeda_identify(mdev->reg_base, &mdev->chip); + if (!mdev->funcs) { + DRM_ERROR("Failed to identify the HW.\n"); err = -ENODEV; goto disable_clk; } @@ -263,15 +268,6 @@ struct komeda_dev *komeda_dev_create(struct device *dev) if (!mdev->iommu) DRM_INFO("continue without IOMMU support!\n"); - if (mdev->iommu && mdev->funcs->connect_iommu) { - err = mdev->funcs->connect_iommu(mdev); - if (err) { - DRM_ERROR("connect iommu failed.\n"); - mdev->iommu = NULL; - goto disable_clk; - } - } - clk_disable_unprepare(mdev->aclk); err = sysfs_create_group(&dev->kobj, &komeda_sysfs_attr_group); @@ -280,6 +276,8 @@ struct komeda_dev *komeda_dev_create(struct device *dev) goto err_cleanup; } + mdev->err_verbosity = KOMEDA_DEV_PRINT_ERR_EVENTS; + #ifdef CONFIG_DEBUG_FS komeda_debugfs_init(mdev); #endif @@ -308,11 +306,6 @@ void komeda_dev_destroy(struct komeda_dev *mdev) if (mdev->aclk) clk_prepare_enable(mdev->aclk); - if (mdev->iommu && mdev->funcs->disconnect_iommu) - if (mdev->funcs->disconnect_iommu(mdev)) - DRM_ERROR("disconnect iommu failed.\n"); - mdev->iommu = NULL; - for (i = 0; i < mdev->n_pipelines; i++) { komeda_pipeline_destroy(mdev, mdev->pipelines[i]); mdev->pipelines[i] = NULL; @@ -341,44 +334,26 @@ void komeda_dev_destroy(struct komeda_dev *mdev) int komeda_dev_resume(struct komeda_dev *mdev) { - int ret = 0; - clk_prepare_enable(mdev->aclk); - if (mdev->iommu && mdev->funcs->connect_iommu) { - ret = mdev->funcs->connect_iommu(mdev); - if (ret < 0) { - DRM_ERROR("connect iommu failed.\n"); - goto disable_clk; - } - } - - ret = mdev->funcs->enable_irq(mdev); + mdev->funcs->enable_irq(mdev); -disable_clk: - clk_disable_unprepare(mdev->aclk); + if (mdev->iommu && mdev->funcs->connect_iommu) + if (mdev->funcs->connect_iommu(mdev)) + DRM_ERROR("connect iommu failed.\n"); - return ret; + return 0; } int komeda_dev_suspend(struct komeda_dev *mdev) { - int ret = 0; - - clk_prepare_enable(mdev->aclk); - - if (mdev->iommu && mdev->funcs->disconnect_iommu) { - ret = mdev->funcs->disconnect_iommu(mdev); - if (ret < 0) { + if (mdev->iommu && mdev->funcs->disconnect_iommu) + if (mdev->funcs->disconnect_iommu(mdev)) DRM_ERROR("disconnect iommu failed.\n"); - goto disable_clk; - } - } - ret = mdev->funcs->disable_irq(mdev); + mdev->funcs->disable_irq(mdev); -disable_clk: clk_disable_unprepare(mdev->aclk); - return ret; + return 0; } diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_dev.h b/drivers/gpu/drm/arm/display/komeda/komeda_dev.h index 414200233b64..ce27f2f27c24 100644 --- a/drivers/gpu/drm/arm/display/komeda/komeda_dev.h +++ b/drivers/gpu/drm/arm/display/komeda/komeda_dev.h @@ -20,6 +20,8 @@ #define KOMEDA_EVENT_OVR BIT_ULL(4) #define KOMEDA_EVENT_EOW BIT_ULL(5) #define KOMEDA_EVENT_MODE BIT_ULL(6) +#define KOMEDA_EVENT_FULL BIT_ULL(7) +#define KOMEDA_EVENT_EMPTY BIT_ULL(8) #define KOMEDA_ERR_TETO BIT_ULL(14) #define KOMEDA_ERR_TEMR BIT_ULL(15) @@ -49,12 +51,15 @@ KOMEDA_ERR_ZME | KOMEDA_ERR_MERR | KOMEDA_ERR_TCF |\ KOMEDA_ERR_TTNG | KOMEDA_ERR_TTF) -#define KOMEDA_WARN_EVENTS KOMEDA_ERR_CSCE +#define KOMEDA_WARN_EVENTS \ + (KOMEDA_ERR_CSCE | KOMEDA_EVENT_FULL | KOMEDA_EVENT_EMPTY) -/* malidp device id */ -enum { - MALI_D71 = 0, -}; +#define KOMEDA_INFO_EVENTS (0 \ + | KOMEDA_EVENT_VSYNC \ + | KOMEDA_EVENT_FLIP \ + | KOMEDA_EVENT_EOW \ + | KOMEDA_EVENT_MODE \ + ) /* pipeline DT ports */ enum { @@ -69,12 +74,6 @@ struct komeda_chip_info { u32 bus_width; }; -struct komeda_product_data { - u32 product_id; - const struct komeda_dev_funcs *(*identify)(u32 __iomem *reg, - struct komeda_chip_info *info); -}; - struct komeda_dev; struct komeda_events { @@ -202,6 +201,23 @@ struct komeda_dev { /** @debugfs_root: root directory of komeda debugfs */ struct dentry *debugfs_root; + /** + * @err_verbosity: bitmask for how much extra info to print on error + * + * See KOMEDA_DEV_* macros for details. Low byte contains the debug + * level categories, the high byte contains extra debug options. + */ + u16 err_verbosity; + /* Print a single line per error per frame with error events. */ +#define KOMEDA_DEV_PRINT_ERR_EVENTS BIT(0) + /* Print a single line per warning per frame with error events. */ +#define KOMEDA_DEV_PRINT_WARN_EVENTS BIT(1) + /* Print a single line per info event per frame with error events. */ +#define KOMEDA_DEV_PRINT_INFO_EVENTS BIT(2) + /* Dump DRM state on an error or warning event. */ +#define KOMEDA_DEV_PRINT_DUMP_STATE_ON_EVENT BIT(8) + /* Disable rate limiting of event prints (normally one per commit) */ +#define KOMEDA_DEV_PRINT_DISABLE_RATELIMIT BIT(12) }; static inline bool @@ -210,6 +226,9 @@ komeda_product_match(struct komeda_dev *mdev, u32 target) return MALIDP_CORE_ID_PRODUCT_ID(mdev->chip.core_id) == target; } +typedef const struct komeda_dev_funcs * +(*komeda_identify_func)(u32 __iomem *reg, struct komeda_chip_info *chip); + const struct komeda_dev_funcs * d71_identify(u32 __iomem *reg, struct komeda_chip_info *chip); @@ -218,11 +237,7 @@ void komeda_dev_destroy(struct komeda_dev *mdev); struct komeda_dev *dev_to_mdev(struct device *dev); -#ifdef CONFIG_DRM_KOMEDA_ERROR_PRINT -void komeda_print_events(struct komeda_events *evts); -#else -static inline void komeda_print_events(struct komeda_events *evts) {} -#endif +void komeda_print_events(struct komeda_events *evts, struct drm_device *dev); int komeda_dev_resume(struct komeda_dev *mdev); int komeda_dev_suspend(struct komeda_dev *mdev); diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_drv.c b/drivers/gpu/drm/arm/display/komeda/komeda_drv.c index d6c2222c5d33..ea5cd1e17304 100644 --- a/drivers/gpu/drm/arm/display/komeda/komeda_drv.c +++ b/drivers/gpu/drm/arm/display/komeda/komeda_drv.c @@ -33,6 +33,12 @@ static void komeda_unbind(struct device *dev) return; komeda_kms_detach(mdrv->kms); + + if (pm_runtime_enabled(dev)) + pm_runtime_disable(dev); + else + komeda_dev_suspend(mdrv->mdev); + komeda_dev_destroy(mdrv->mdev); dev_set_drvdata(dev, NULL); @@ -54,6 +60,10 @@ static int komeda_bind(struct device *dev) goto free_mdrv; } + pm_runtime_enable(dev); + if (!pm_runtime_enabled(dev)) + komeda_dev_resume(mdrv->mdev); + mdrv->kms = komeda_kms_attach(mdrv->mdev); if (IS_ERR(mdrv->kms)) { err = PTR_ERR(mdrv->kms); @@ -65,6 +75,11 @@ static int komeda_bind(struct device *dev) return 0; destroy_mdev: + if (pm_runtime_enabled(dev)) + pm_runtime_disable(dev); + else + komeda_dev_suspend(mdrv->mdev); + komeda_dev_destroy(mdrv->mdev); free_mdrv: @@ -123,29 +138,37 @@ static int komeda_platform_remove(struct platform_device *pdev) return 0; } -static const struct komeda_product_data komeda_products[] = { - [MALI_D71] = { - .product_id = MALIDP_D71_PRODUCT_ID, - .identify = d71_identify, - }, -}; - static const struct of_device_id komeda_of_match[] = { - { .compatible = "arm,mali-d71", .data = &komeda_products[MALI_D71], }, + { .compatible = "arm,mali-d71", .data = d71_identify, }, + { .compatible = "arm,mali-d32", .data = d71_identify, }, {}, }; MODULE_DEVICE_TABLE(of, komeda_of_match); +static int komeda_rt_pm_suspend(struct device *dev) +{ + struct komeda_drv *mdrv = dev_get_drvdata(dev); + + return komeda_dev_suspend(mdrv->mdev); +} + +static int komeda_rt_pm_resume(struct device *dev) +{ + struct komeda_drv *mdrv = dev_get_drvdata(dev); + + return komeda_dev_resume(mdrv->mdev); +} + static int __maybe_unused komeda_pm_suspend(struct device *dev) { struct komeda_drv *mdrv = dev_get_drvdata(dev); - struct drm_device *drm = &mdrv->kms->base; int res; - res = drm_mode_config_helper_suspend(drm); + res = drm_mode_config_helper_suspend(&mdrv->kms->base); - komeda_dev_suspend(mdrv->mdev); + if (!pm_runtime_status_suspended(dev)) + komeda_dev_suspend(mdrv->mdev); return res; } @@ -153,15 +176,16 @@ static int __maybe_unused komeda_pm_suspend(struct device *dev) static int __maybe_unused komeda_pm_resume(struct device *dev) { struct komeda_drv *mdrv = dev_get_drvdata(dev); - struct drm_device *drm = &mdrv->kms->base; - komeda_dev_resume(mdrv->mdev); + if (!pm_runtime_status_suspended(dev)) + komeda_dev_resume(mdrv->mdev); - return drm_mode_config_helper_resume(drm); + return drm_mode_config_helper_resume(&mdrv->kms->base); } static const struct dev_pm_ops komeda_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(komeda_pm_suspend, komeda_pm_resume) + SET_RUNTIME_PM_OPS(komeda_rt_pm_suspend, komeda_rt_pm_resume, NULL) }; static struct platform_driver komeda_platform_driver = { diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_event.c b/drivers/gpu/drm/arm/display/komeda/komeda_event.c index a36fb86cc054..53f944e66dfc 100644 --- a/drivers/gpu/drm/arm/display/komeda/komeda_event.c +++ b/drivers/gpu/drm/arm/display/komeda/komeda_event.c @@ -4,6 +4,7 @@ * Author: James.Qian.Wang <james.qian.wang@arm.com> * */ +#include <drm/drm_atomic.h> #include <drm/drm_print.h> #include "komeda_dev.h" @@ -16,6 +17,7 @@ struct komeda_str { /* return 0 on success, < 0 on no space. */ +__printf(2, 3) static int komeda_sprintf(struct komeda_str *str, const char *fmt, ...) { va_list args; @@ -76,6 +78,8 @@ static void evt_str(struct komeda_str *str, u64 events) /* LPU errors or events */ evt_sprintf(str, events & KOMEDA_EVENT_IBSY, "IBSY|"); + evt_sprintf(str, events & KOMEDA_EVENT_EMPTY, "EMPTY|"); + evt_sprintf(str, events & KOMEDA_EVENT_FULL, "FULL|"); evt_sprintf(str, events & KOMEDA_ERR_AXIE, "AXIE|"); evt_sprintf(str, events & KOMEDA_ERR_ACE0, "ACE0|"); evt_sprintf(str, events & KOMEDA_ERR_ACE1, "ACE1|"); @@ -107,20 +111,31 @@ static bool is_new_frame(struct komeda_events *a) (KOMEDA_EVENT_FLIP | KOMEDA_EVENT_EOW); } -void komeda_print_events(struct komeda_events *evts) +void komeda_print_events(struct komeda_events *evts, struct drm_device *dev) { - u64 print_evts = KOMEDA_ERR_EVENTS; + u64 print_evts = 0; static bool en_print = true; + struct komeda_dev *mdev = dev->dev_private; + u16 const err_verbosity = mdev->err_verbosity; + u64 evts_mask = evts->global | evts->pipes[0] | evts->pipes[1]; /* reduce the same msg print, only print the first evt for one frame */ if (evts->global || is_new_frame(evts)) en_print = true; - if (!en_print) + if (!(err_verbosity & KOMEDA_DEV_PRINT_DISABLE_RATELIMIT) && !en_print) return; - if ((evts->global | evts->pipes[0] | evts->pipes[1]) & print_evts) { + if (err_verbosity & KOMEDA_DEV_PRINT_ERR_EVENTS) + print_evts |= KOMEDA_ERR_EVENTS; + if (err_verbosity & KOMEDA_DEV_PRINT_WARN_EVENTS) + print_evts |= KOMEDA_WARN_EVENTS; + if (err_verbosity & KOMEDA_DEV_PRINT_INFO_EVENTS) + print_evts |= KOMEDA_INFO_EVENTS; + + if (evts_mask & print_evts) { char msg[256]; struct komeda_str str; + struct drm_printer p = drm_info_printer(dev->dev); str.str = msg; str.sz = sizeof(msg); @@ -134,6 +149,9 @@ void komeda_print_events(struct komeda_events *evts) evt_str(&str, evts->pipes[1]); DRM_ERROR("err detect: %s\n", msg); + if ((err_verbosity & KOMEDA_DEV_PRINT_DUMP_STATE_ON_EVENT) && + (evts_mask & (KOMEDA_ERR_EVENTS | KOMEDA_WARN_EVENTS))) + drm_state_dump(dev, &p); en_print = false; } diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_kms.c b/drivers/gpu/drm/arm/display/komeda/komeda_kms.c index 52648b4008bc..442d4656150a 100644 --- a/drivers/gpu/drm/arm/display/komeda/komeda_kms.c +++ b/drivers/gpu/drm/arm/display/komeda/komeda_kms.c @@ -48,7 +48,7 @@ static irqreturn_t komeda_kms_irq_handler(int irq, void *data) memset(&evts, 0, sizeof(evts)); status = mdev->funcs->irq_handler(mdev, &evts); - komeda_print_events(&evts); + komeda_print_events(&evts, drm); /* Notify the crtc to handle the events */ for (i = 0; i < kms->n_crtcs; i++) @@ -308,10 +308,6 @@ struct komeda_kms_dev *komeda_kms_attach(struct komeda_dev *mdev) if (err) goto free_component_binding; - err = mdev->funcs->enable_irq(mdev); - if (err) - goto free_component_binding; - drm->irq_enabled = true; drm_kms_helper_poll_init(drm); @@ -325,7 +321,6 @@ struct komeda_kms_dev *komeda_kms_attach(struct komeda_dev *mdev) free_interrupts: drm_kms_helper_poll_fini(drm); drm->irq_enabled = false; - mdev->funcs->disable_irq(mdev); free_component_binding: component_unbind_all(mdev->dev, drm); cleanup_mode_config: @@ -347,7 +342,6 @@ void komeda_kms_detach(struct komeda_kms_dev *kms) drm_kms_helper_poll_fini(drm); drm_atomic_helper_shutdown(drm); drm->irq_enabled = false; - mdev->funcs->disable_irq(mdev); component_unbind_all(mdev->dev, drm); drm_mode_config_cleanup(drm); komeda_kms_cleanup_private_objs(kms); diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h index bd6ca7c87037..ac8725e24853 100644 --- a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h +++ b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h @@ -11,6 +11,7 @@ #include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> #include "malidp_utils.h" +#include "komeda_color_mgmt.h" #define KOMEDA_MAX_PIPELINES 2 #define KOMEDA_PIPELINE_MAX_LAYERS 4 @@ -327,6 +328,8 @@ struct komeda_improc_state { struct komeda_component_state base; u8 color_format, color_depth; u16 hsize, vsize; + u32 fgamma_coeffs[KOMEDA_N_GAMMA_COEFFS]; + u32 ctm_coeffs[KOMEDA_N_CTM_COEFFS]; }; /* display timing controller */ diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline_state.c b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline_state.c index 52750116aa19..8f32ae7c25d0 100644 --- a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline_state.c +++ b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline_state.c @@ -802,6 +802,12 @@ komeda_improc_validate(struct komeda_improc *improc, st->color_format = BIT(__ffs(avail_formats)); } + if (kcrtc_st->base.color_mgmt_changed) { + drm_lut_to_fgamma_coeffs(kcrtc_st->base.gamma_lut, + st->fgamma_coeffs); + drm_ctm_to_coeffs(kcrtc_st->base.ctm, st->ctm_coeffs); + } + komeda_component_add_input(&st->base, &dflow->input, 0); komeda_component_set_output(&dflow->input, &improc->base, 0); diff --git a/drivers/gpu/drm/arm/malidp_planes.c b/drivers/gpu/drm/arm/malidp_planes.c index 3c70a53813bf..37715cc6064e 100644 --- a/drivers/gpu/drm/arm/malidp_planes.c +++ b/drivers/gpu/drm/arm/malidp_planes.c @@ -512,7 +512,7 @@ static int malidp_de_plane_check(struct drm_plane *plane, int i, ret; unsigned int block_w, block_h; - if (!state->crtc || !state->fb) + if (!state->crtc || WARN_ON(!state->fb)) return 0; fb = state->fb; |