[PATCH] MAINTAINERS: Add Mihail to Komeda DRM driver
I'll be the main point of contact. Cc: James Qian Wang (Arm Technology China) Cc: Liviu Dudau Signed-off-by: Mihail Atanassov --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 94fb077c0817..d32f263f0022 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1251,6 +1251,7 @@ F: Documentation/devicetree/bindings/display/arm,hdlcd.txt ARM KOMEDA DRM-KMS DRIVER M: James (Qian) Wang M: Liviu Dudau +M: Mihail Atanassov L: Mali DP Maintainers S: Supported T: git git://anongit.freedesktop.org/drm/drm-misc -- 2.23.0
Re: drm/komeda: Dump SC_ENH_* registers from scaler block
On Wednesday, 16 October 2019 09:17:39 BST james qian wang (Arm Technology China) wrote: > On Tue, Oct 15, 2019 at 11:00:01AM +0000, Mihail Atanassov wrote: > > Signed-off-by: Mihail Atanassov > > --- > > .../gpu/drm/arm/display/komeda/d71/d71_component.c | 14 +- > > 1 file changed, 13 insertions(+), 1 deletion(-) > > > > 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 c3d29c0b051b..7252fc387fba 100644 > > --- a/drivers/gpu/drm/arm/display/komeda/d71/d71_component.c > > +++ b/drivers/gpu/drm/arm/display/komeda/d71/d71_component.c > > @@ -703,7 +703,7 @@ static void d71_scaler_update(struct komeda_component > > *c, > > > > static void d71_scaler_dump(struct komeda_component *c, struct seq_file > > *sf) > > { > > - u32 v[9]; > > + u32 v[10]; > > > > dump_block_header(sf, c->reg); > > > > @@ -723,6 +723,18 @@ static void d71_scaler_dump(struct komeda_component > > *c, struct seq_file *sf) > > seq_printf(sf, "SC_H_DELTA_PH:\t\t0x%X\n", v[6]); > > seq_printf(sf, "SC_V_INIT_PH:\t\t0x%X\n", v[7]); > > seq_printf(sf, "SC_V_DELTA_PH:\t\t0x%X\n", v[8]); > > + > > + get_values_from_reg(c->reg, 0x130, 10, v); > > + seq_printf(sf, "SC_ENH_LIMITS:\t\t0x%X\n", v[0]); > > + seq_printf(sf, "SC_ENH_COEFF0:\t\t0x%X\n", v[1]); > > + seq_printf(sf, "SC_ENH_COEFF1:\t\t0x%X\n", v[2]); > > + seq_printf(sf, "SC_ENH_COEFF2:\t\t0x%X\n", v[3]); > > + seq_printf(sf, "SC_ENH_COEFF3:\t\t0x%X\n", v[4]); > > + seq_printf(sf, "SC_ENH_COEFF4:\t\t0x%X\n", v[5]); > > + seq_printf(sf, "SC_ENH_COEFF5:\t\t0x%X\n", v[6]); > > + seq_printf(sf, "SC_ENH_COEFF6:\t\t0x%X\n", v[7]); > > + seq_printf(sf, "SC_ENH_COEFF7:\t\t0x%X\n", v[8]); > > + seq_printf(sf, "SC_ENH_COEFF8:\t\t0x%X\n", v[9]); > > } > > > > Looks good to me. > > Reviewed-by: James Qian Wang (Arm Technology China) Thanks, applied to drm-misc-next - 2b6f5883edcc47ef6146832112a0125810d28f78. > > > static const struct komeda_component_funcs d71_scaler_funcs = { > -- Mihail
Re: [PATCH v2 1/4] drm: Add a new helper drm_color_ctm_s31_32_to_qm_n()
Hi James, On Friday, 11 October 2019 06:45:27 BST james qian wang (Arm Technology China) wrote: > Add a new helper function drm_color_ctm_s31_32_to_qm_n() for driver to > convert S31.32 sign-magnitude to Qm.n 2's complement that supported by > hardware. > > Signed-off-by: james qian wang (Arm Technology China) > > --- > drivers/gpu/drm/drm_color_mgmt.c | 23 +++ > include/drm/drm_color_mgmt.h | 2 ++ > 2 files changed, 25 insertions(+) > > diff --git a/drivers/gpu/drm/drm_color_mgmt.c > b/drivers/gpu/drm/drm_color_mgmt.c > index 4ce5c6d8de99..3d533d0b45af 100644 > --- a/drivers/gpu/drm/drm_color_mgmt.c > +++ b/drivers/gpu/drm/drm_color_mgmt.c > @@ -132,6 +132,29 @@ uint32_t drm_color_lut_extract(uint32_t user_input, > uint32_t bit_precision) > } > EXPORT_SYMBOL(drm_color_lut_extract); > > +/** > + * drm_color_ctm_s31_32_to_qm_n > + * > + * @user_input: input value > + * @m: number of integer bits > + * @n: number of fractinal bits > + * > + * Convert and clamp S31.32 sign-magnitude to Qm.n 2's complement. > + */ > +uint64_t drm_color_ctm_s31_32_to_qm_n(uint64_t user_input, > + uint32_t m, uint32_t n) > +{ > + u64 mag = (user_input & ~BIT_ULL(63)) >> (32 - n); This doesn't account for n > 32, which is perfectly possible (e.g. Q1.63). > + bool negative = !!(user_input & BIT_ULL(63)); > + s64 val; > + > + /* the range of signed 2s complement is [-2^n+m, 2^n+m - 1] */ > + val = clamp_val(mag, 0, negative ? BIT(n + m) : BIT(n + m) - 1); This also doesn't account for n + m == 64. > + > + return negative ? 0ll - val : val; > +} > +EXPORT_SYMBOL(drm_color_ctm_s31_32_to_qm_n); > + > /** > * drm_crtc_enable_color_mgmt - enable color management properties > * @crtc: DRM CRTC > diff --git a/include/drm/drm_color_mgmt.h b/include/drm/drm_color_mgmt.h > index d1c662d92ab7..60fea5501886 100644 > --- a/include/drm/drm_color_mgmt.h > +++ b/include/drm/drm_color_mgmt.h > @@ -30,6 +30,8 @@ struct drm_crtc; > struct drm_plane; > > uint32_t drm_color_lut_extract(uint32_t user_input, uint32_t bit_precision); > +uint64_t drm_color_ctm_s31_32_to_qm_n(uint64_t user_input, > + uint32_t m, uint32_t n); > > void drm_crtc_enable_color_mgmt(struct drm_crtc *crtc, > uint degamma_lut_size, > -- > 2.20.1 > -- Mihail
Re: [PATCH] drm/komeda: Reordered the komeda's de-init functions
On Tuesday, 20 August 2019 18:46:19 BST Ayan Halder wrote: > The de-init routine should be doing the following in order:- > 1. Unregister the drm device > 2. Shut down the crtcs - failing to do this might cause a connector leakage > See the 'commit 109c4d18e574 ("drm/arm/malidp: Ensure that the crtcs are > shutdown before removing any encoder/connector")' > 3. Disable the interrupts > 4. Unbind the components > 5. Free up DRM mode_config info > > Signed-off-by: Ayan Kumar Halder > --- > .../gpu/drm/arm/display/komeda/komeda_kms.c | 20 +-- > 1 file changed, 14 insertions(+), 6 deletions(-) > > diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_kms.c > b/drivers/gpu/drm/arm/display/komeda/komeda_kms.c > index 89191a555c84..e219d1b67100 100644 > --- a/drivers/gpu/drm/arm/display/komeda/komeda_kms.c > +++ b/drivers/gpu/drm/arm/display/komeda/komeda_kms.c > @@ -13,6 +13,7 @@ > #include > #include > #include > +#include Can we keep the include list in alphabetical order? > #include > #include > > @@ -304,24 +305,30 @@ struct komeda_kms_dev *komeda_kms_attach(struct > komeda_dev *mdev) > komeda_kms_irq_handler, IRQF_SHARED, > drm->driver->name, drm); > if (err) > - goto cleanup_mode_config; > + goto free_component_binding; > > err = mdev->funcs->enable_irq(mdev); > if (err) > - goto cleanup_mode_config; > + goto free_component_binding; > > drm->irq_enabled = true; > > err = drm_dev_register(drm, 0); > if (err) > - goto cleanup_mode_config; > + goto free_interrupts; > > return kms; > > -cleanup_mode_config: > +free_interrupts: > drm->irq_enabled = false; > + mdev->funcs->disable_irq(mdev); > +free_component_binding: > + component_unbind_all(mdev->dev, drm); > +cleanup_mode_config: > drm_mode_config_cleanup(drm); > komeda_kms_cleanup_private_objs(kms); > + drm->dev_private = NULL; > + drm_dev_put(drm); > free_kms: > kfree(kms); > return ERR_PTR(err); > @@ -332,12 +339,13 @@ void komeda_kms_detach(struct komeda_kms_dev *kms) > struct drm_device *drm = &kms->base; > struct komeda_dev *mdev = drm->dev_private; > > + drm_dev_unregister(drm); > + drm_atomic_helper_shutdown(drm); > drm->irq_enabled = false; > mdev->funcs->disable_irq(mdev); > - drm_dev_unregister(drm); > component_unbind_all(mdev->dev, drm); > - komeda_kms_cleanup_private_objs(kms); > drm_mode_config_cleanup(drm); > + komeda_kms_cleanup_private_objs(kms); > drm->dev_private = NULL; > drm_dev_put(drm); > } > Thanks. See my include order comment above, with that fixed: Reviewed-by: Mihail Atanassov -- Mihail
[PATCH] drm/komeda: Add missing of_node_get() call
komeda_pipeline_destroy has the matching of_node_put(). Fixes: 29e56aec911dd ("drm/komeda: Add DT parsing") Signed-off-by: Mihail Atanassov --- drivers/gpu/drm/arm/display/komeda/komeda_dev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_dev.c b/drivers/gpu/drm/arm/display/komeda/komeda_dev.c index 0142ee991957..ca64a129c594 100644 --- a/drivers/gpu/drm/arm/display/komeda/komeda_dev.c +++ b/drivers/gpu/drm/arm/display/komeda/komeda_dev.c @@ -130,7 +130,7 @@ 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 = np; + pipe->of_node = of_node_get(np); return 0; } -- 2.22.0
Re: [PATCH] drm/komeda: Adds error event print functionality
On Friday, 2 August 2019 10:43:10 BST Lowry Li (Arm Technology China) wrote: > From: "Lowry Li (Arm Technology China)" > > Adds to print the event message when error happens and the same event > will not be printed until next vsync. > > Changes since v2: > 1. Refine komeda_sprintf(); > 2. Not using STR_SZ macro for the string size in komeda_print_events(). > > Changes since v1: > 1. Handling the event print by CONFIG_KOMEDA_ERROR_PRINT; > 2. Changing the max string size to 256. > > Signed-off-by: Lowry Li (Arm Technology China) Reviewed-by: Mihail Atanassov BR, Mihail > --- > drivers/gpu/drm/arm/display/Kconfig | 6 + > drivers/gpu/drm/arm/display/komeda/Makefile | 2 + > drivers/gpu/drm/arm/display/komeda/komeda_dev.h | 15 +++ > drivers/gpu/drm/arm/display/komeda/komeda_event.c | 140 > ++ drivers/gpu/drm/arm/display/komeda/komeda_kms.c | > 4 + > 5 files changed, 167 insertions(+) > create mode 100644 drivers/gpu/drm/arm/display/komeda/komeda_event.c > > diff --git a/drivers/gpu/drm/arm/display/Kconfig > b/drivers/gpu/drm/arm/display/Kconfig index cec0639..e87ff86 100644 > --- a/drivers/gpu/drm/arm/display/Kconfig > +++ b/drivers/gpu/drm/arm/display/Kconfig > @@ -12,3 +12,9 @@ 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/komeda/Makefile > b/drivers/gpu/drm/arm/display/komeda/Makefile index 5c3900c..f095a1c 100644 > --- a/drivers/gpu/drm/arm/display/komeda/Makefile > +++ b/drivers/gpu/drm/arm/display/komeda/Makefile > @@ -22,4 +22,6 @@ 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/komeda_dev.h > b/drivers/gpu/drm/arm/display/komeda/komeda_dev.h index d1c86b6..e28e7e6 > 100644 > --- a/drivers/gpu/drm/arm/display/komeda/komeda_dev.h > +++ b/drivers/gpu/drm/arm/display/komeda/komeda_dev.h > @@ -40,6 +40,17 @@ > #define KOMEDA_ERR_TTNG BIT_ULL(30) > #define KOMEDA_ERR_TTF BIT_ULL(31) > > +#define KOMEDA_ERR_EVENTS\ > + (KOMEDA_EVENT_URUN | KOMEDA_EVENT_IBSY | KOMEDA_EVENT_OVR | \ > + KOMEDA_ERR_TETO | KOMEDA_ERR_TEMR | KOMEDA_ERR_TITR |\ > + KOMEDA_ERR_CPE | KOMEDA_ERR_CFGE | KOMEDA_ERR_AXIE |\ > + KOMEDA_ERR_ACE0 | KOMEDA_ERR_ACE1 | KOMEDA_ERR_ACE2 |\ > + KOMEDA_ERR_ACE3 | KOMEDA_ERR_DRIFTTO| KOMEDA_ERR_FRAMETO |\ > + KOMEDA_ERR_ZME | KOMEDA_ERR_MERR | KOMEDA_ERR_TCF |\ > + KOMEDA_ERR_TTNG | KOMEDA_ERR_TTF) > + > +#define KOMEDA_WARN_EVENTS KOMEDA_ERR_CSCE > + > /* malidp device id */ > enum { > MALI_D71 = 0, > @@ -207,4 +218,8 @@ struct komeda_dev { > > struct komeda_dev *dev_to_mdev(struct device *dev); > > +#ifdef CONFIG_DRM_KOMEDA_ERROR_PRINT > +void komeda_print_events(struct komeda_events *evts); > +#endif > + > #endif /*_KOMEDA_DEV_H_*/ > diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_event.c > b/drivers/gpu/drm/arm/display/komeda/komeda_event.c new file mode 100644 > index 000..a36fb86 > --- /dev/null > +++ b/drivers/gpu/drm/arm/display/komeda/komeda_event.c > @@ -0,0 +1,140 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * (C) COPYRIGHT 2019 ARM Limited. All rights reserved. > + * Author: James.Qian.Wang > + * > + */ > +#include > + > +#include "komeda_dev.h" > + > +struct komeda_str { > + char *str; > + u32 sz; > + u32 len; > +}; > + > +/* return 0 on success, < 0 on no space. > + */ > +static int komeda_sprintf(struct komeda_str *str, const char *fmt, ...) > +{ > + va_list args; > + int num, free_sz; > + int err; > + > + free_sz = str->sz - str->len - 1; > + if (free_sz <= 0) > + return -ENOSPC; > + > + va_start(args, fmt); > + > + num = vsnprintf(str->str + str->len, free_sz, fmt, args); > + > + va_end(args); > + > + if (num < free_sz) { > + str->len += num; > + err = 0; > + } else { > + str->len = str->sz - 1; > + err = -ENOSPC; > + } > + > + return err; > +} &
[PATCH] drm: mali-dp: add atomic_print_state for planes
Print all the extra fields of malidp_plane_state. Signed-off-by: Mihail Atanassov --- drivers/gpu/drm/arm/malidp_planes.c | 13 + 1 file changed, 13 insertions(+) diff --git a/drivers/gpu/drm/arm/malidp_planes.c b/drivers/gpu/drm/arm/malidp_planes.c index 414aada..3879dc5 100644 --- a/drivers/gpu/drm/arm/malidp_planes.c +++ b/drivers/gpu/drm/arm/malidp_planes.c @@ -16,6 +16,7 @@ #include #include #include +#include #include "malidp_hw.h" #include "malidp_drv.h" @@ -88,6 +89,17 @@ static void malidp_destroy_plane_state(struct drm_plane *plane, kfree(m_state); } +static void malidp_plane_atomic_print_state(struct drm_printer *p, + const struct drm_plane_state *state) +{ + struct malidp_plane_state *ms = to_malidp_plane_state(state); + struct malidp_plane *mp = to_malidp_plane(state->plane); + + drm_printf(p, "\trotmem_size=%u\n", ms->rotmem_size); + drm_printf(p, "\tformat_id=%u\n", ms->format); + drm_printf(p, "\tn_planes=%u\n", ms->n_planes); +} + static const struct drm_plane_funcs malidp_de_plane_funcs = { .update_plane = drm_atomic_helper_update_plane, .disable_plane = drm_atomic_helper_disable_plane, @@ -96,6 +108,7 @@ static void malidp_destroy_plane_state(struct drm_plane *plane, .reset = drm_atomic_helper_plane_reset, .atomic_duplicate_state = malidp_duplicate_plane_state, .atomic_destroy_state = malidp_destroy_plane_state, + .atomic_print_state = malidp_plane_atomic_print_state, }; static int malidp_de_plane_check(struct drm_plane *plane, -- 1.9.1
[PATCH v2] drm: mali-dp: Add CTM support
All DPs have a COLORADJ matrix which is applied prior to output gamma. Attach that to the CTM property. Also, ensure the input CTM's coefficients can fit in the DP registers' Q3.12 format. Signed-off-by: Mihail Atanassov --- Link to v1: https://lkml.org/lkml/2017/2/1/254 Changes since v1: - Rebased and fixed conflicts - Improved clarity of overflow check (+comment) - Moved call to malidp_atomic_commit_update_coloradj in the existing crtc for-each loop This patch depends on "[PATCH v3 2/2] drm: mali-dp: enable gamma support", sent out on 7 Feb (https://lkml.org/lkml/2017/2/7/547). drivers/gpu/drm/arm/malidp_crtc.c | 58 +-- drivers/gpu/drm/arm/malidp_drv.c | 36 +++- drivers/gpu/drm/arm/malidp_drv.h | 1 + drivers/gpu/drm/arm/malidp_regs.h | 2 ++ 4 files changed, 94 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/arm/malidp_crtc.c b/drivers/gpu/drm/arm/malidp_crtc.c index 6a46520..7414540 100644 --- a/drivers/gpu/drm/arm/malidp_crtc.c +++ b/drivers/gpu/drm/arm/malidp_crtc.c @@ -192,6 +192,58 @@ static int malidp_crtc_atomic_check_gamma(struct drm_crtc *crtc, return 0; } +/* + * Check if there is a new CTM and if it contains valid input. Valid here means + * that the number is inside the representable range for a Q3.12 number, + * excluding truncating the fractional part of the input data. + * + * The COLORADJ registers can be changed atomically. + */ +static int malidp_crtc_atomic_check_ctm(struct drm_crtc *crtc, + struct drm_crtc_state *state) +{ + struct malidp_crtc_state *mc = to_malidp_crtc_state(state); + struct drm_color_ctm *ctm; + int i; + + if (!state->color_mgmt_changed) + return 0; + + if (!state->ctm) + return 0; + + if (crtc->state->ctm && (crtc->state->ctm->base.id == +state->ctm->base.id)) + return 0; + + /* +* The size of the ctm is checked in +* drm_atomic_replace_property_blob_from_id. +*/ + ctm = (struct drm_color_ctm *)state->ctm->data; + for (i = 0; i < ARRAY_SIZE(ctm->matrix); ++i) { + /* Convert from S31.32 to Q3.12. */ + s64 val = ctm->matrix[i]; + u32 mag = u64)val) & ~BIT_ULL(63)) >> 20) & + GENMASK_ULL(14, 0); + + /* +* Convert to 2s complement and check the destination's top bit +* for overflow. NB: Can't check before converting or it'd +* incorrectly reject the case: +* sign == 1 +* mag == 0x2000 +*/ + if (val & BIT_ULL(63)) + mag = ~mag + 1; + if (!!(val & BIT_ULL(63)) != !!(mag & BIT(14))) + return -EINVAL; + mc->coloradj_coeffs[i] = mag; + } + + return 0; +} + static int malidp_crtc_atomic_check(struct drm_crtc *crtc, struct drm_crtc_state *state) { @@ -269,6 +321,7 @@ static int malidp_crtc_atomic_check(struct drm_crtc *crtc, } ret = malidp_crtc_atomic_check_gamma(crtc, state); + ret = ret ? ret : malidp_crtc_atomic_check_ctm(crtc, state); return ret; } @@ -288,6 +341,7 @@ static struct drm_crtc_state *malidp_crtc_duplicate_state(struct drm_crtc *crtc) __drm_atomic_helper_crtc_duplicate_state(crtc, &state->base); memcpy(state->gamma_coeffs, cs->gamma_coeffs, sizeof(state->gamma_coeffs)); + memcpy(state->coloradj_coeffs, cs->coloradj_coeffs, sizeof(state->coloradj_coeffs)); return &state->base; } @@ -358,8 +412,8 @@ int malidp_crtc_init(struct drm_device *drm) drm_crtc_helper_add(&malidp->crtc, &malidp_crtc_helper_funcs); drm_mode_crtc_set_gamma_size(&malidp->crtc, MALIDP_GAMMA_LUT_SIZE); - /* No inverse-gamma and color adjustments yet. */ - drm_crtc_enable_color_mgmt(&malidp->crtc, 0, false, MALIDP_GAMMA_LUT_SIZE); + /* No inverse-gamma: it is per-plane. */ + drm_crtc_enable_color_mgmt(&malidp->crtc, 0, true, MALIDP_GAMMA_LUT_SIZE); return 0; crtc_cleanup_planes: diff --git a/drivers/gpu/drm/arm/malidp_drv.c b/drivers/gpu/drm/arm/malidp_drv.c index ce741c3..15f0f91 100644 --- a/drivers/gpu/drm/arm/malidp_drv.c +++ b/drivers/gpu/drm/arm/malidp_drv.c @@ -77,6 +77,37 @@ static void malidp_atomic_commit_update_gamma(struct drm_crtc *crtc, } } +static +void malidp_atomic_commit_update_coloradj(struct drm_crtc *crtc, + struct drm_crtc_state *old_state) +{ + struct malidp_drm *malidp = crtc_to_malidp_device(c
[RFC] drm: Helper macro for drm state duplication
Hi, I was working on a few patches adding fields to struct malidp_crtc_state and found myself writing memcpy multiple times in the ->atomic_duplicate_state hook because I wanted to avoid copying the drm_crtc_state twice (__drm_atomic_helper_crtc_duplicate_state copies it already). I figured this also applies to the other drm_*_state derivatives, so I concocted a macro helper to do the copy in one chunk (two if you count the __drm_atomic_helper* one). I'd appreciate some comments on whether anyone else might find this macro useful. Thanks! Mihail Atanassov (1): drm: Add helper macro for duplicating custom drm_*_state include/drm/drm_atomic_helper.h | 33 + 1 file changed, 33 insertions(+) -- Mihail Atanassov
[PATCH] drm: Add helper macro for duplicating custom drm_*_state
Assuming a derived struct of the form: struct foo_bar_state { struct drm_bar_state bar_state; struct foo_private priv; struct foo_private2 *priv2; }; memcpy priv and priv2 to the new instance of foo_bar_state. The intention is to use this macro in ->atomic_duplicate_state in conjunction with __drm_atomic_helper_*_duplicate_state, which already copies the relevant drm_*_state struct. There's an equality check for new_state and old_state to ensure that they are distinct instances of the same type, and a BUILD_BUG if the base struct (bar_state in the above example) is not first in the derived struct, to avoid missing any data before it and corrupting the base's data. Signed-off-by: Mihail Atanassov --- include/drm/drm_atomic_helper.h | 33 + 1 file changed, 33 insertions(+) diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h index d066e94..ecc6a82 100644 --- a/include/drm/drm_atomic_helper.h +++ b/include/drm/drm_atomic_helper.h @@ -171,6 +171,39 @@ int drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc, uint32_t size); /** + * drm_atomic_duplicate_custom_state - helper macro for duplicating + * driver-private additions to drm_*_state. + * @new_state: pointer to destination state struct + * @old_state: pointer to source state struct + * @basename: name of the drm_*_state member of the new_state/old_state struct + * + * Copies the data after the base struct until the end of the custom struct, + * e.g. given a structure + * + * struct foo_bar_state { + * struct drm_bar_state base; + * struct foo_private priv; + * struct foo_private2 *priv2; + * }; + * + * this copies priv and priv2. NB: the base struct *must* be the first element + * of the derived struct, and new_state and old_state have to be two distinct + * instances. + */ +#define drm_atomic_helper_duplicate_custom_state(new_state, old_state, basename) \ + do { \ + size_t base_size = sizeof(new_state->basename); \ + size_t base_offset = offsetof(typeof(*new_state), basename); \ + \ + BUILD_BUG_ON(base_offset != 0); \ + if (new_state == old_state) /* Type-check */ \ + break; \ + memcpy((char *)new_state + base_size, \ + (char *)old_state + base_size, \ + sizeof(*new_state) - base_size); \ + } while(0) + +/** * drm_atomic_crtc_for_each_plane - iterate over planes currently attached to CRTC * @plane: the loop cursor * @crtc: the crtc whose planes are iterated -- 1.9.1
[PATCH v3 1/2] drm: mali-dp: add malidp_crtc_state struct
Add a custom CRTC state struct to enable storing driver-private per-CRTC state. This patch only adds the base drm_crtc_state struct. Signed-off-by: Mihail Atanassov Reviewed-by: Brian Starkey Acked-by: Liviu Dudau --- Link to v2: https://lkml.org/lkml/2017/2/1/378 Link to v1: https://lkml.org/lkml/2017/2/1/203 Changes since v2: - rebased and fixed conflicts - s/MALIDP_DISP_FUNC_GAM/MALIDP_DISP_FUNC_GAMMA/g - added MALIDP_GAMMA_LUT_SIZE #define + s/4096/MALIDP_GAMMA_LUT_SIZE/g in malidp_crtc.c - improved readability in a few places Changes since v1: - Moved unused variable to patch 2/2, where it is used. drivers/gpu/drm/arm/malidp_crtc.c | 37 +++-- drivers/gpu/drm/arm/malidp_drv.h | 6 ++ 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/arm/malidp_crtc.c b/drivers/gpu/drm/arm/malidp_crtc.c index 08e6a71..ebf57e6 100644 --- a/drivers/gpu/drm/arm/malidp_crtc.c +++ b/drivers/gpu/drm/arm/malidp_crtc.c @@ -160,6 +160,39 @@ static int malidp_crtc_atomic_check(struct drm_crtc *crtc, return 0; } +static struct drm_crtc_state *malidp_crtc_duplicate_state(struct drm_crtc *crtc) +{ + struct malidp_crtc_state *state; + + if (WARN_ON(!crtc->state)) + return NULL; + + state = kmalloc(sizeof(*state), GFP_KERNEL); + if (!state) + return NULL; + + __drm_atomic_helper_crtc_duplicate_state(crtc, &state->base); + + return &state->base; +} + +static void malidp_crtc_reset(struct drm_crtc *crtc) +{ + struct malidp_crtc_state *cs = (crtc->state) ? + to_malidp_crtc_state(crtc->state) : NULL; + + if (crtc->state) + __drm_atomic_helper_crtc_destroy_state(crtc->state); + + kfree(cs); + cs = kzalloc(sizeof(*cs), GFP_KERNEL); + if (!cs) + return; + + crtc->state = &cs->base; + crtc->state->crtc = crtc; +} + static const struct drm_crtc_helper_funcs malidp_crtc_helper_funcs = { .mode_fixup = malidp_crtc_mode_fixup, .enable = malidp_crtc_enable, @@ -171,8 +204,8 @@ static int malidp_crtc_atomic_check(struct drm_crtc *crtc, .destroy = drm_crtc_cleanup, .set_config = drm_atomic_helper_set_config, .page_flip = drm_atomic_helper_page_flip, - .reset = drm_atomic_helper_crtc_reset, - .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, + .reset = malidp_crtc_reset, + .atomic_duplicate_state = malidp_crtc_duplicate_state, .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, }; diff --git a/drivers/gpu/drm/arm/malidp_drv.h b/drivers/gpu/drm/arm/malidp_drv.h index dbc617c..558f4bf 100644 --- a/drivers/gpu/drm/arm/malidp_drv.h +++ b/drivers/gpu/drm/arm/malidp_drv.h @@ -47,6 +47,12 @@ struct malidp_plane_state { #define to_malidp_plane(x) container_of(x, struct malidp_plane, base) #define to_malidp_plane_state(x) container_of(x, struct malidp_plane_state, base) +struct malidp_crtc_state { + struct drm_crtc_state base; +}; + +#define to_malidp_crtc_state(x) container_of(x, struct malidp_crtc_state, base) + int malidp_de_planes_init(struct drm_device *drm); void malidp_de_planes_destroy(struct drm_device *drm); int malidp_crtc_init(struct drm_device *drm); -- 1.9.1
[PATCH v3 2/2] drm: mali-dp: enable gamma support
Add gamma via the DRM GAMMA_LUT/GAMMA_LUT_SIZE CRTC properties. The expected LUT size is 4096 in order to produce as accurate a set of segments as possible. This version uses only the green channel's gamma curve to set the hardware curve on DP550/650. For the sake of simplicity, it uses the same table of coefficients for all 3 curves on DP500. Signed-off-by: Mihail Atanassov Reviewed-by: Brian Starkey Acked-by: Liviu Dudau --- drivers/gpu/drm/arm/malidp_crtc.c | 130 -- drivers/gpu/drm/arm/malidp_drv.c | 52 +++ drivers/gpu/drm/arm/malidp_drv.h | 1 + drivers/gpu/drm/arm/malidp_hw.c | 3 + drivers/gpu/drm/arm/malidp_hw.h | 2 + drivers/gpu/drm/arm/malidp_regs.h | 19 -- 6 files changed, 196 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/arm/malidp_crtc.c b/drivers/gpu/drm/arm/malidp_crtc.c index ebf57e6..6a46520 100644 --- a/drivers/gpu/drm/arm/malidp_crtc.c +++ b/drivers/gpu/drm/arm/malidp_crtc.c @@ -21,6 +21,8 @@ #include "malidp_drv.h" #include "malidp_hw.h" +#define MALIDP_GAMMA_LUT_SIZE 4096 + static bool malidp_crtc_mode_fixup(struct drm_crtc *crtc, const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) @@ -82,6 +84,114 @@ static void malidp_crtc_disable(struct drm_crtc *crtc) clk_disable_unprepare(hwdev->pxlclk); } +static const struct gamma_curve_segment { + u16 start; + u16 end; +} segments[MALIDP_COEFFTAB_NUM_COEFFS] = { + /* sector 0 */ + {0,0 }, {1,1 }, {2,2 }, {3,3 }, + {4,4 }, {5,5 }, {6,6 }, {7,7 }, + {8,8 }, {9,9 }, { 10, 10 }, { 11, 11 }, + { 12, 12 }, { 13, 13 }, { 14, 14 }, { 15, 15 }, + /* sector 1 */ + { 16, 19 }, { 20, 23 }, { 24, 27 }, { 28, 31 }, + /* sector 2 */ + { 32, 39 }, { 40, 47 }, { 48, 55 }, { 56, 63 }, + /* sector 3 */ + { 64, 79 }, { 80, 95 }, { 96, 111 }, { 112, 127 }, + /* sector 4 */ + { 128, 159 }, { 160, 191 }, { 192, 223 }, { 224, 255 }, + /* sector 5 */ + { 256, 319 }, { 320, 383 }, { 384, 447 }, { 448, 511 }, + /* sector 6 */ + { 512, 639 }, { 640, 767 }, { 768, 895 }, { 896, 1023 }, + { 1024, 1151 }, { 1152, 1279 }, { 1280, 1407 }, { 1408, 1535 }, + { 1536, 1663 }, { 1664, 1791 }, { 1792, 1919 }, { 1920, 2047 }, + { 2048, 2175 }, { 2176, 2303 }, { 2304, 2431 }, { 2432, 2559 }, + { 2560, 2687 }, { 2688, 2815 }, { 2816, 2943 }, { 2944, 3071 }, + { 3072, 3199 }, { 3200, 3327 }, { 3328, 3455 }, { 3456, 3583 }, + { 3584, 3711 }, { 3712, 3839 }, { 3840, 3967 }, { 3968, 4095 }, +}; + +#define DE_COEFTAB_DATA(a, b) a) & 0xfff) << 16) | (((b) & 0xfff))) + +static void malidp_generate_gamma_table(struct drm_property_blob *lut_blob, + u32 coeffs[MALIDP_COEFFTAB_NUM_COEFFS]) +{ + struct drm_color_lut *lut = (struct drm_color_lut *)lut_blob->data; + int i; + + for (i = 0; i < MALIDP_COEFFTAB_NUM_COEFFS; ++i) { + u32 a, b; + u32 delta_in; + u32 out_start, out_end; + + delta_in = segments[i].end - segments[i].start; + /* DP has 12-bit internal precision for its LUTs. */ + out_start = drm_color_lut_extract(lut[segments[i].start].green, + 12); + out_end = drm_color_lut_extract(lut[segments[i].end].green, 12); + a = (delta_in == 0) ? + 0 : ((out_end - out_start) * 256) / delta_in; + b = out_start; + coeffs[i] = DE_COEFTAB_DATA(a, b); + } +} + +/* + * Check if there is a new gamma LUT and if it is of an acceptable size. Also, + * reject any LUTs that use distinct red, green, and blue curves. + */ +static int malidp_crtc_atomic_check_gamma(struct drm_crtc *crtc, + struct drm_crtc_state *state) +{ + struct malidp_crtc_state *mc = to_malidp_crtc_state(state); + struct drm_color_lut *lut; + size_t lut_size; + int i; + + if (!state->color_mgmt_changed) + return 0; + + if (!state->gamma_lut) + return 0; + + if (crtc->state->gamma_lut && (crtc->state->gamma_lut->base.id == + state->gamma_lut->base.id)) + return 0; + + if (state->gamma_lut->length % sizeof(struct drm_color_lut)) + return -EINVAL; + + lut_size = state->gamma_lut->length / sizeof(struct drm_color_lut); + if (lut_size != MALIDP_GAMMA_LUT_SIZE) + return
[PATCH v2 1/2] drm: mali-dp: add malidp_crtc_state struct
Add a custom CRTC state struct to enable storing driver-private per-CRTC state. This patch only adds the base drm_crtc_state struct. Signed-off-by: Mihail Atanassov Reviewed-by: Brian Starkey --- Link to v1: https://lkml.org/lkml/2017/2/1/203 Changes since v1: - Moved unused variable to patch 2/2, where it is used. drivers/gpu/drm/arm/malidp_crtc.c | 37 +++-- drivers/gpu/drm/arm/malidp_drv.h | 6 ++ 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/arm/malidp_crtc.c b/drivers/gpu/drm/arm/malidp_crtc.c index 08e6a71..ebf57e6 100644 --- a/drivers/gpu/drm/arm/malidp_crtc.c +++ b/drivers/gpu/drm/arm/malidp_crtc.c @@ -160,6 +160,39 @@ static int malidp_crtc_atomic_check(struct drm_crtc *crtc, return 0; } +static struct drm_crtc_state *malidp_crtc_duplicate_state(struct drm_crtc *crtc) +{ + struct malidp_crtc_state *state; + + if (WARN_ON(!crtc->state)) + return NULL; + + state = kmalloc(sizeof(*state), GFP_KERNEL); + if (!state) + return NULL; + + __drm_atomic_helper_crtc_duplicate_state(crtc, &state->base); + + return &state->base; +} + +static void malidp_crtc_reset(struct drm_crtc *crtc) +{ + struct malidp_crtc_state *cs = (crtc->state) ? + to_malidp_crtc_state(crtc->state) : NULL; + + if (crtc->state) + __drm_atomic_helper_crtc_destroy_state(crtc->state); + + kfree(cs); + cs = kzalloc(sizeof(*cs), GFP_KERNEL); + if (!cs) + return; + + crtc->state = &cs->base; + crtc->state->crtc = crtc; +} + static const struct drm_crtc_helper_funcs malidp_crtc_helper_funcs = { .mode_fixup = malidp_crtc_mode_fixup, .enable = malidp_crtc_enable, @@ -171,8 +204,8 @@ static int malidp_crtc_atomic_check(struct drm_crtc *crtc, .destroy = drm_crtc_cleanup, .set_config = drm_atomic_helper_set_config, .page_flip = drm_atomic_helper_page_flip, - .reset = drm_atomic_helper_crtc_reset, - .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, + .reset = malidp_crtc_reset, + .atomic_duplicate_state = malidp_crtc_duplicate_state, .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, }; diff --git a/drivers/gpu/drm/arm/malidp_drv.h b/drivers/gpu/drm/arm/malidp_drv.h index 9fc8a2e..c7a69ae 100644 --- a/drivers/gpu/drm/arm/malidp_drv.h +++ b/drivers/gpu/drm/arm/malidp_drv.h @@ -47,6 +47,12 @@ struct malidp_plane_state { #define to_malidp_plane(x) container_of(x, struct malidp_plane, base) #define to_malidp_plane_state(x) container_of(x, struct malidp_plane_state, base) +struct malidp_crtc_state { + struct drm_crtc_state base; +}; + +#define to_malidp_crtc_state(x) container_of(x, struct malidp_crtc_state, base) + int malidp_de_planes_init(struct drm_device *drm); void malidp_de_planes_destroy(struct drm_device *drm); int malidp_crtc_init(struct drm_device *drm); -- 1.9.1
[PATCH v2 2/2] drm: mali-dp: enable gamma support
Add gamma via the DRM GAMMA_LUT/GAMMA_LUT_SIZE CRTC properties. The expected LUT size is 4096 in order to produce as accurate a set of segments as possible. This version uses only the green channel's gamma curve to set the hardware curve on DP550/650. For the sake of simplicity, it uses the same table of coefficients for all 3 curves on DP500. Signed-off-by: Mihail Atanassov Reviewed-by: Brian Starkey --- drivers/gpu/drm/arm/malidp_crtc.c | 132 -- drivers/gpu/drm/arm/malidp_drv.c | 52 +++ drivers/gpu/drm/arm/malidp_drv.h | 1 + drivers/gpu/drm/arm/malidp_hw.c | 3 + drivers/gpu/drm/arm/malidp_hw.h | 2 + drivers/gpu/drm/arm/malidp_regs.h | 19 -- 6 files changed, 199 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/arm/malidp_crtc.c b/drivers/gpu/drm/arm/malidp_crtc.c index ebf57e6..10f79b6 100644 --- a/drivers/gpu/drm/arm/malidp_crtc.c +++ b/drivers/gpu/drm/arm/malidp_crtc.c @@ -82,6 +82,114 @@ static void malidp_crtc_disable(struct drm_crtc *crtc) clk_disable_unprepare(hwdev->pxlclk); } +static const struct gamma_curve_segment { + u16 start; + u16 end; +} segments[MALIDP_COEFFTAB_NUM_COEFFS] = { + /* sector 0 */ + {0,0 }, {1,1 }, {2,2 }, {3,3 }, + {4,4 }, {5,5 }, {6,6 }, {7,7 }, + {8,8 }, {9,9 }, { 10, 10 }, { 11, 11 }, + { 12, 12 }, { 13, 13 }, { 14, 14 }, { 15, 15 }, + /* sector 1 */ + { 16, 19 }, { 20, 23 }, { 24, 27 }, { 28, 31 }, + /* sector 2 */ + { 32, 39 }, { 40, 47 }, { 48, 55 }, { 56, 63 }, + /* sector 3 */ + { 64, 79 }, { 80, 95 }, { 96, 111 }, { 112, 127 }, + /* sector 4 */ + { 128, 159 }, { 160, 191 }, { 192, 223 }, { 224, 255 }, + /* sector 5 */ + { 256, 319 }, { 320, 383 }, { 384, 447 }, { 448, 511 }, + /* sector 6 */ + { 512, 639 }, { 640, 767 }, { 768, 895 }, { 896, 1023 }, + { 1024, 1151 }, { 1152, 1279 }, { 1280, 1407 }, { 1408, 1535 }, + { 1536, 1663 }, { 1664, 1791 }, { 1792, 1919 }, { 1920, 2047 }, + { 2048, 2175 }, { 2176, 2303 }, { 2304, 2431 }, { 2432, 2559 }, + { 2560, 2687 }, { 2688, 2815 }, { 2816, 2943 }, { 2944, 3071 }, + { 3072, 3199 }, { 3200, 3327 }, { 3328, 3455 }, { 3456, 3583 }, + { 3584, 3711 }, { 3712, 3839 }, { 3840, 3967 }, { 3968, 4095 }, +}; + +#define DE_COEFTAB_DATA(a, b) a) & 0xfff) << 16) | (((b) & 0xfff))) + +static void malidp_generate_gamma_table(struct drm_property_blob *lut_blob, + u32 coeffs[MALIDP_COEFFTAB_NUM_COEFFS]) +{ + struct drm_color_lut *lut = (struct drm_color_lut *)lut_blob->data; + int i; + + for (i = 0; i < MALIDP_COEFFTAB_NUM_COEFFS; ++i) { + u32 a, b; + u32 delta_in; + u32 out_start, out_end; + + delta_in = segments[i].end - segments[i].start; + /* DP has 12-bit internal precision for its LUTs. */ + out_start = drm_color_lut_extract(lut[segments[i].start].green, + 12); + out_end = drm_color_lut_extract(lut[segments[i].end].green, 12); + a = (delta_in == 0) ? + 0 : ((out_end - out_start) * 256) / delta_in; + b = out_start; + coeffs[i] = DE_COEFTAB_DATA(a, b); + } +} + +/* + * Check if there is a new gamma LUT and if it is of an acceptable size. Also, + * reject any LUTs that use distinct red, green, and blue curves. + */ +static int malidp_crtc_atomic_check_gamma(struct drm_crtc *crtc, + struct drm_crtc_state *state) +{ + struct malidp_crtc_state *mc = to_malidp_crtc_state(state); + struct drm_color_lut *lut; + size_t lut_size; + int i; + + if (!state->color_mgmt_changed) + return 0; + + if (!state->gamma_lut) + return 0; + + if (crtc->state->gamma_lut && (crtc->state->gamma_lut->base.id == + state->gamma_lut->base.id)) + return 0; + + if (state->gamma_lut->length % sizeof(struct drm_color_lut)) + return -EINVAL; + + lut_size = state->gamma_lut->length / sizeof(struct drm_color_lut); + if (lut_size != 4096) + return -EINVAL; + + lut = (struct drm_color_lut *)state->gamma_lut->data; + for (i = 0; i < lut_size; ++i) + if (!((lut[i].red == lut[i].green) && + (lut[i].red == lut[i].blue))) + return -EINVAL; + + if (!state->mode_changed) { + int ret; + + state->mode_c
[PATCH] drm: mali-dp: Add CTM support
All DPs have a COLORADJ matrix which is applied prior to output gamma. Attach that to the CTM property. Also, ensure the input CTM's coefficients can fit in the DP registers' Q3.12 format. Signed-off-by: Mihail Atanassov --- This patch depends on "[PATCH 2/2] drm: mali-dp: enable gamma support", sent out earlier (https://lkml.org/lkml/2017/2/1/201). drivers/gpu/drm/arm/malidp_crtc.c | 59 +-- drivers/gpu/drm/arm/malidp_drv.c | 35 +++ drivers/gpu/drm/arm/malidp_drv.h | 1 + drivers/gpu/drm/arm/malidp_regs.h | 2 ++ 4 files changed, 95 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/arm/malidp_crtc.c b/drivers/gpu/drm/arm/malidp_crtc.c index 10f79b6..2f366e4 100644 --- a/drivers/gpu/drm/arm/malidp_crtc.c +++ b/drivers/gpu/drm/arm/malidp_crtc.c @@ -190,6 +190,55 @@ static int malidp_crtc_atomic_check_gamma(struct drm_crtc *crtc, return 0; } +/* + * Check if there is a new CTM and if it contains valid input. Valid here means + * that the number is inside the representable range for a Q3.12 number, + * excluding truncating the fractional part of the input data. + * + * The COLORADJ registers can be changed atomically. + */ +static int malidp_crtc_atomic_check_ctm(struct drm_crtc *crtc, + struct drm_crtc_state *state) +{ + struct malidp_crtc_state *mc = to_malidp_crtc_state(state); + struct drm_color_ctm *ctm; + int i; + + if (!state->color_mgmt_changed) + return 0; + + if (!state->ctm) + return 0; + + if (crtc->state->ctm && (crtc->state->ctm->base.id == +state->ctm->base.id)) + return 0; + + /* +* The size of the ctm is checked in +* drm_atomic_replace_property_blob_from_id. +*/ + ctm = (struct drm_color_ctm *)state->ctm->data; + for (i = 0; i < ARRAY_SIZE(ctm->matrix); ++i) { + /* Convert from S31.32 to Q3.12. */ + s64 val = ctm->matrix[i]; + u64 mag = u64)val) & ~BIT_ULL(63)) >> 20) & + GENMASK_ULL(14, 0); + + /* Check the destination's top bit for overflow. */ + if (val & BIT_ULL(63)) { + mag = ~mag + 1; + if (!(mag & BIT_ULL(14))) + return -EINVAL; + } else if (mag & BIT_ULL(14)) { + return -EINVAL; + } + mc->coloradj_coeffs[i] = mag; + } + + return 0; +} + static int malidp_crtc_atomic_check(struct drm_crtc *crtc, struct drm_crtc_state *state) { @@ -270,6 +319,10 @@ static int malidp_crtc_atomic_check(struct drm_crtc *crtc, if (ret) return ret; + ret = malidp_crtc_atomic_check_ctm(crtc, state); + if (ret) + return ret; + return 0; } @@ -289,6 +342,8 @@ static struct drm_crtc_state *malidp_crtc_duplicate_state(struct drm_crtc *crtc) __drm_atomic_helper_crtc_duplicate_state(crtc, &state->base); memcpy(state->gamma_coeffs, cs->gamma_coeffs, sizeof(state->gamma_coeffs)); + memcpy(state->coloradj_coeffs, cs->coloradj_coeffs, + sizeof(state->coloradj_coeffs)); return &state->base; } @@ -359,10 +414,10 @@ int malidp_crtc_init(struct drm_device *drm) drm_crtc_helper_add(&malidp->crtc, &malidp_crtc_helper_funcs); drm_mode_crtc_set_gamma_size(&malidp->crtc, 4096); - /* No inverse-gamma and color adjustments yet. */ + /* No inverse-gamma: it is per-plane. */ drm_crtc_enable_color_mgmt(&malidp->crtc, 0, - false, + true, 4096); return 0; diff --git a/drivers/gpu/drm/arm/malidp_drv.c b/drivers/gpu/drm/arm/malidp_drv.c index a9f787d..682901a 100644 --- a/drivers/gpu/drm/arm/malidp_drv.c +++ b/drivers/gpu/drm/arm/malidp_drv.c @@ -78,6 +78,37 @@ static void malidp_atomic_commit_update_gamma(struct drm_crtc *crtc, } } +static +void malidp_atomic_commit_update_coloradj(struct drm_crtc *crtc, + struct drm_crtc_state *old_state) +{ + struct malidp_drm *malidp = crtc_to_malidp_device(crtc); + struct malidp_hw_device *hwdev = malidp->dev; + int i; + + if (!crtc->state->color_mgmt_changed) + return; + + if (!crtc->state->ctm) { + malidp_hw_clearbits(hwdev, MALIDP_DISP_FUNC_CADJ, + MALIDP_DE_DISPLAY_FUNC); + } else
[PATCH 1/2] drm: mali-dp: add malidp_crtc_state struct
Add a custom CRTC state struct to enable storing driver-private per-CRTC state. This patch only adds the base drm_crtc_state struct. Signed-off-by: Mihail Atanassov --- drivers/gpu/drm/arm/malidp_crtc.c | 39 +-- drivers/gpu/drm/arm/malidp_drv.h | 6 ++ 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/arm/malidp_crtc.c b/drivers/gpu/drm/arm/malidp_crtc.c index 08e6a71..d1cd0e7 100644 --- a/drivers/gpu/drm/arm/malidp_crtc.c +++ b/drivers/gpu/drm/arm/malidp_crtc.c @@ -160,6 +160,41 @@ static int malidp_crtc_atomic_check(struct drm_crtc *crtc, return 0; } +static struct drm_crtc_state *malidp_crtc_duplicate_state(struct drm_crtc *crtc) +{ + struct malidp_crtc_state *cs; + struct malidp_crtc_state *state; + + if (WARN_ON(!crtc->state)) + return NULL; + + cs = to_malidp_crtc_state(crtc->state); + state = kmalloc(sizeof(*state), GFP_KERNEL); + if (!state) + return NULL; + + __drm_atomic_helper_crtc_duplicate_state(crtc, &state->base); + + return &state->base; +} + +static void malidp_crtc_reset(struct drm_crtc *crtc) +{ + struct malidp_crtc_state *cs = (crtc->state) ? + to_malidp_crtc_state(crtc->state) : NULL; + + if (crtc->state) + __drm_atomic_helper_crtc_destroy_state(crtc->state); + + kfree(cs); + cs = kzalloc(sizeof(*cs), GFP_KERNEL); + if (!cs) + return; + + crtc->state = &cs->base; + crtc->state->crtc = crtc; +} + static const struct drm_crtc_helper_funcs malidp_crtc_helper_funcs = { .mode_fixup = malidp_crtc_mode_fixup, .enable = malidp_crtc_enable, @@ -171,8 +206,8 @@ static int malidp_crtc_atomic_check(struct drm_crtc *crtc, .destroy = drm_crtc_cleanup, .set_config = drm_atomic_helper_set_config, .page_flip = drm_atomic_helper_page_flip, - .reset = drm_atomic_helper_crtc_reset, - .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, + .reset = malidp_crtc_reset, + .atomic_duplicate_state = malidp_crtc_duplicate_state, .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, }; diff --git a/drivers/gpu/drm/arm/malidp_drv.h b/drivers/gpu/drm/arm/malidp_drv.h index 9fc8a2e..c7a69ae 100644 --- a/drivers/gpu/drm/arm/malidp_drv.h +++ b/drivers/gpu/drm/arm/malidp_drv.h @@ -47,6 +47,12 @@ struct malidp_plane_state { #define to_malidp_plane(x) container_of(x, struct malidp_plane, base) #define to_malidp_plane_state(x) container_of(x, struct malidp_plane_state, base) +struct malidp_crtc_state { + struct drm_crtc_state base; +}; + +#define to_malidp_crtc_state(x) container_of(x, struct malidp_crtc_state, base) + int malidp_de_planes_init(struct drm_device *drm); void malidp_de_planes_destroy(struct drm_device *drm); int malidp_crtc_init(struct drm_device *drm); -- 1.9.1
[PATCH 2/2] drm: mali-dp: enable gamma support
Add gamma via the DRM GAMMA_LUT/GAMMA_LUT_SIZE CRTC properties. The expected LUT size is 4096 in order to produce as accurate a set of segments as possible. This version uses only the green channel's gamma curve to set the hardware curve on DP550/650. For the sake of simplicity, it uses the same table of coefficients for all 3 curves on DP500. Signed-off-by: Mihail Atanassov --- drivers/gpu/drm/arm/malidp_crtc.c | 130 -- drivers/gpu/drm/arm/malidp_drv.c | 52 +++ drivers/gpu/drm/arm/malidp_drv.h | 1 + drivers/gpu/drm/arm/malidp_hw.c | 3 + drivers/gpu/drm/arm/malidp_hw.h | 2 + drivers/gpu/drm/arm/malidp_regs.h | 19 -- 6 files changed, 197 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/arm/malidp_crtc.c b/drivers/gpu/drm/arm/malidp_crtc.c index d1cd0e7..10f79b6 100644 --- a/drivers/gpu/drm/arm/malidp_crtc.c +++ b/drivers/gpu/drm/arm/malidp_crtc.c @@ -82,6 +82,114 @@ static void malidp_crtc_disable(struct drm_crtc *crtc) clk_disable_unprepare(hwdev->pxlclk); } +static const struct gamma_curve_segment { + u16 start; + u16 end; +} segments[MALIDP_COEFFTAB_NUM_COEFFS] = { + /* sector 0 */ + {0,0 }, {1,1 }, {2,2 }, {3,3 }, + {4,4 }, {5,5 }, {6,6 }, {7,7 }, + {8,8 }, {9,9 }, { 10, 10 }, { 11, 11 }, + { 12, 12 }, { 13, 13 }, { 14, 14 }, { 15, 15 }, + /* sector 1 */ + { 16, 19 }, { 20, 23 }, { 24, 27 }, { 28, 31 }, + /* sector 2 */ + { 32, 39 }, { 40, 47 }, { 48, 55 }, { 56, 63 }, + /* sector 3 */ + { 64, 79 }, { 80, 95 }, { 96, 111 }, { 112, 127 }, + /* sector 4 */ + { 128, 159 }, { 160, 191 }, { 192, 223 }, { 224, 255 }, + /* sector 5 */ + { 256, 319 }, { 320, 383 }, { 384, 447 }, { 448, 511 }, + /* sector 6 */ + { 512, 639 }, { 640, 767 }, { 768, 895 }, { 896, 1023 }, + { 1024, 1151 }, { 1152, 1279 }, { 1280, 1407 }, { 1408, 1535 }, + { 1536, 1663 }, { 1664, 1791 }, { 1792, 1919 }, { 1920, 2047 }, + { 2048, 2175 }, { 2176, 2303 }, { 2304, 2431 }, { 2432, 2559 }, + { 2560, 2687 }, { 2688, 2815 }, { 2816, 2943 }, { 2944, 3071 }, + { 3072, 3199 }, { 3200, 3327 }, { 3328, 3455 }, { 3456, 3583 }, + { 3584, 3711 }, { 3712, 3839 }, { 3840, 3967 }, { 3968, 4095 }, +}; + +#define DE_COEFTAB_DATA(a, b) a) & 0xfff) << 16) | (((b) & 0xfff))) + +static void malidp_generate_gamma_table(struct drm_property_blob *lut_blob, + u32 coeffs[MALIDP_COEFFTAB_NUM_COEFFS]) +{ + struct drm_color_lut *lut = (struct drm_color_lut *)lut_blob->data; + int i; + + for (i = 0; i < MALIDP_COEFFTAB_NUM_COEFFS; ++i) { + u32 a, b; + u32 delta_in; + u32 out_start, out_end; + + delta_in = segments[i].end - segments[i].start; + /* DP has 12-bit internal precision for its LUTs. */ + out_start = drm_color_lut_extract(lut[segments[i].start].green, + 12); + out_end = drm_color_lut_extract(lut[segments[i].end].green, 12); + a = (delta_in == 0) ? + 0 : ((out_end - out_start) * 256) / delta_in; + b = out_start; + coeffs[i] = DE_COEFTAB_DATA(a, b); + } +} + +/* + * Check if there is a new gamma LUT and if it is of an acceptable size. Also, + * reject any LUTs that use distinct red, green, and blue curves. + */ +static int malidp_crtc_atomic_check_gamma(struct drm_crtc *crtc, + struct drm_crtc_state *state) +{ + struct malidp_crtc_state *mc = to_malidp_crtc_state(state); + struct drm_color_lut *lut; + size_t lut_size; + int i; + + if (!state->color_mgmt_changed) + return 0; + + if (!state->gamma_lut) + return 0; + + if (crtc->state->gamma_lut && (crtc->state->gamma_lut->base.id == + state->gamma_lut->base.id)) + return 0; + + if (state->gamma_lut->length % sizeof(struct drm_color_lut)) + return -EINVAL; + + lut_size = state->gamma_lut->length / sizeof(struct drm_color_lut); + if (lut_size != 4096) + return -EINVAL; + + lut = (struct drm_color_lut *)state->gamma_lut->data; + for (i = 0; i < lut_size; ++i) + if (!((lut[i].red == lut[i].green) && + (lut[i].red == lut[i].blue))) + return -EINVAL; + + if (!state->mode_changed) { + int ret; + + state->mode_changed = true;
[PATCH] drm: mali-dp: add custom plane ->reset hook
The reset hook needs to allocate space for a malidp_plane_state, which is larger than drm_plane_state. Otherwise, the hook is identical to the default one. Signed-off-by: Mihail Atanassov --- drivers/gpu/drm/arm/malidp_planes.c | 23 ++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/arm/malidp_planes.c b/drivers/gpu/drm/arm/malidp_planes.c index eff2fe4..686ff86 100644 --- a/drivers/gpu/drm/arm/malidp_planes.c +++ b/drivers/gpu/drm/arm/malidp_planes.c @@ -58,6 +58,27 @@ static void malidp_de_plane_destroy(struct drm_plane *plane) devm_kfree(plane->dev->dev, mp); } +/* + * Replicate what the default ->reset hook does: free the state pointer and + * allocate a new empty object. We just need enough space to store + * a malidp_plane_state instead of a drm_plane_state. + */ +static void malidp_plane_reset(struct drm_plane *plane) +{ + struct malidp_plane_state *state = to_malidp_plane_state(plane->state); + + if (state) + __drm_atomic_helper_plane_destroy_state(&state->base); + kfree(state); + plane->state = NULL; + state = kzalloc(sizeof(*state), GFP_KERNEL); + if (state) { + state->base.plane = plane; + state->base.rotation = DRM_ROTATE_0; + plane->state = &state->base; + } +} + static struct drm_plane_state *malidp_duplicate_plane_state(struct drm_plane *plane) { @@ -92,7 +113,7 @@ static void malidp_destroy_plane_state(struct drm_plane *plane, .disable_plane = drm_atomic_helper_disable_plane, .set_property = drm_atomic_helper_plane_set_property, .destroy = malidp_de_plane_destroy, - .reset = drm_atomic_helper_plane_reset, + .reset = malidp_plane_reset, .atomic_duplicate_state = malidp_duplicate_plane_state, .atomic_destroy_state = malidp_destroy_plane_state, }; -- 1.9.1
[PATCH 1/2] drm: mali-dp: Check hw version matches device-tree
Refuse to bind if the device-tree compatible string lists a different hardware version. Reviewed-by: Brian Starkey Signed-off-by: Mihail Atanassov --- A couple of small improvements to driver-to-hardware binding. drivers/gpu/drm/arm/malidp_drv.c | 52 +++ drivers/gpu/drm/arm/malidp_regs.h | 2 ++ 2 files changed, 54 insertions(+) diff --git a/drivers/gpu/drm/arm/malidp_drv.c b/drivers/gpu/drm/arm/malidp_drv.c index 32f746e..43238f4 100644 --- a/drivers/gpu/drm/arm/malidp_drv.c +++ b/drivers/gpu/drm/arm/malidp_drv.c @@ -256,6 +256,46 @@ static void malidp_lastclose(struct drm_device *drm) }; MODULE_DEVICE_TABLE(of, malidp_drm_of_match); +static bool malidp_is_compatible_hw_id(struct malidp_hw_device *hwdev, + const struct of_device_id *dev_id) +{ + u32 core_id; + const char *compatstr_dp500 = "arm,mali-dp500"; + bool is_dp500; + bool dt_is_dp500; + + /* +* The DP500 CORE_ID register is in a different location, so check it +* first. If the product id field matches, then this is DP500, otherwise +* check the DP550/650 CORE_ID register. +*/ + core_id = malidp_hw_read(hwdev, MALIDP500_DC_BASE + MALIDP_DE_CORE_ID); + /* Offset 0x18 will never read 0x500 on products other than DP500. */ + is_dp500 = (MALIDP_PRODUCT_ID(core_id) == 0x500); + dt_is_dp500 = strnstr(dev_id->compatible, compatstr_dp500, + sizeof(dev_id->compatible)) != NULL; + if (is_dp500 != dt_is_dp500) { + DRM_ERROR("Device-tree expects %s, but hardware %s DP500.\n", + dev_id->compatible, is_dp500 ? "is" : "is not"); + return false; + } else if (!dt_is_dp500) { + u16 product_id; + char buf[32]; + + core_id = malidp_hw_read(hwdev, +MALIDP550_DC_BASE + MALIDP_DE_CORE_ID); + product_id = MALIDP_PRODUCT_ID(core_id); + snprintf(buf, sizeof(buf), "arm,mali-dp%X", product_id); + if (!strnstr(dev_id->compatible, buf, +sizeof(dev_id->compatible))) { + DRM_ERROR("Device-tree expects %s, but hardware is DP%03X.\n", + dev_id->compatible, product_id); + return false; + } + } + return true; +} + #define MAX_OUTPUT_CHANNELS3 static int malidp_bind(struct device *dev) @@ -266,6 +306,7 @@ static int malidp_bind(struct device *dev) struct malidp_drm *malidp; struct malidp_hw_device *hwdev; struct platform_device *pdev = to_platform_device(dev); + struct of_device_id const *dev_id; /* number of lines for the R, G and B output */ u8 output_width[MAX_OUTPUT_CHANNELS]; int ret = 0, i; @@ -329,6 +370,17 @@ static int malidp_bind(struct device *dev) clk_prepare_enable(hwdev->aclk); clk_prepare_enable(hwdev->mclk); + dev_id = of_match_device(malidp_drm_of_match, dev); + if (!dev_id) { + ret = -EINVAL; + goto query_hw_fail; + } + + if (!malidp_is_compatible_hw_id(hwdev, dev_id)) { + ret = -EINVAL; + goto query_hw_fail; + } + ret = hwdev->query_hw(hwdev); if (ret) { DRM_ERROR("Invalid HW configuration\n"); diff --git a/drivers/gpu/drm/arm/malidp_regs.h b/drivers/gpu/drm/arm/malidp_regs.h index 73fecb3..7a89997 100644 --- a/drivers/gpu/drm/arm/malidp_regs.h +++ b/drivers/gpu/drm/arm/malidp_regs.h @@ -92,6 +92,8 @@ #define MALIDP_DE_H_ACTIVE(x) (((x) & 0x1fff) << 0) #define MALIDP_DE_V_ACTIVE(x) (((x) & 0x1fff) << 16) +#define MALIDP_PRODUCT_ID(__core_id) ((u32)(__core_id) >> 16) + /* register offsets and bits specific to DP500 */ #define MALIDP500_DC_BASE 0x0 #define MALIDP500_DC_CONTROL 0xc -- 1.8.3
[PATCH 2/2] drm: mali-dp: Check for sufficient address space
If the device-tree 'reg' node doesn't reserve enough space for the DP, fail to bind. Reviewed-by: Brian Starkey Signed-off-by: Mihail Atanassov --- drivers/gpu/drm/arm/malidp_drv.c | 20 drivers/gpu/drm/arm/malidp_regs.h | 2 ++ 2 files changed, 22 insertions(+) diff --git a/drivers/gpu/drm/arm/malidp_drv.c b/drivers/gpu/drm/arm/malidp_drv.c index 43238f4..66622a5 100644 --- a/drivers/gpu/drm/arm/malidp_drv.c +++ b/drivers/gpu/drm/arm/malidp_drv.c @@ -296,6 +296,20 @@ static bool malidp_is_compatible_hw_id(struct malidp_hw_device *hwdev, return true; } +static bool malidp_is_sufficient_address_space(const struct resource *res, + const struct of_device_id *dev_id) +{ + resource_size_t res_size = resource_size(res); + const char *compatstr_dp500 = "arm,mali-dp500"; + + if (!strnstr(dev_id->compatible, compatstr_dp500, +sizeof(dev_id->compatible))) + return res_size >= MALIDP550_ADDR_SPACE_SIZE; + else if (res_size < MALIDP500_ADDR_SPACE_SIZE) + return false; + return true; +} + #define MAX_OUTPUT_CHANNELS3 static int malidp_bind(struct device *dev) @@ -376,6 +390,12 @@ static int malidp_bind(struct device *dev) goto query_hw_fail; } + if (!malidp_is_sufficient_address_space(res, dev_id)) { + DRM_ERROR("Insufficient address space in device-tree.\n"); + ret = -EINVAL; + goto query_hw_fail; + } + if (!malidp_is_compatible_hw_id(hwdev, dev_id)) { ret = -EINVAL; goto query_hw_fail; diff --git a/drivers/gpu/drm/arm/malidp_regs.h b/drivers/gpu/drm/arm/malidp_regs.h index 7a89997..e0651d2 100644 --- a/drivers/gpu/drm/arm/malidp_regs.h +++ b/drivers/gpu/drm/arm/malidp_regs.h @@ -95,6 +95,7 @@ #define MALIDP_PRODUCT_ID(__core_id) ((u32)(__core_id) >> 16) /* register offsets and bits specific to DP500 */ +#define MALIDP500_ADDR_SPACE_SIZE 0x01000 #define MALIDP500_DC_BASE 0x0 #define MALIDP500_DC_CONTROL 0xc #define MALIDP500_DC_CONFIG_REQ (1 << 17) @@ -127,6 +128,7 @@ #define MALIDP500_CONFIG_ID0x00fd4 /* register offsets and bits specific to DP550/DP650 */ +#define MALIDP550_ADDR_SPACE_SIZE 0x1 #define MALIDP550_DE_CONTROL 0x00010 #define MALIDP550_DE_LINE_COUNTER 0x00014 #define MALIDP550_DE_AXI_CONTROL 0x00018 -- 1.8.3