* [PATCH v2 07/19] arm64: insn: Add encoder for bitwise operations using litterals
From: James Morse @ 2017-12-13 15:45 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <07971a66-1b36-d2cd-e590-2b7b65d14b97@arm.com>
Hi Marc,
On 13/12/17 14:32, Marc Zyngier wrote:
> On 12/12/17 18:32, James Morse wrote:
>> On 11/12/17 14:49, Marc Zyngier wrote:
>>> We lack a way to encode operations such as AND, ORR, EOR that take
>>> an immediate value. Doing so is quite involved, and is all about
>>> reverse engineering the decoding algorithm described in the
>>> pseudocode function DecodeBitMasks().
>>> diff --git a/arch/arm64/kernel/insn.c b/arch/arm64/kernel/insn.c
>>> index 7e432662d454..326b17016485 100644
>>> --- a/arch/arm64/kernel/insn.c
>>> +++ b/arch/arm64/kernel/insn.c
>>
>>> +static u32 aarch64_encode_immediate(u64 imm,
>>> + enum aarch64_insn_variant variant,
>>> + u32 insn)
>>> +{
>>> + unsigned int immr, imms, n, ones, ror, esz, tmp;
>>> + u64 mask;
>>
>> [...]
>>
>>> + /* Compute the rotation */
>>> + if (range_of_ones(imm)) {
>>> + /*
>>> + * Pattern: 0..01..10..0
>>> + *
>>> + * Compute how many rotate we need to align it right
>>> + */
>>> + ror = ffs(imm) - 1;
>>
>> (how come range_of_ones() uses __ffs64() on the same value?)
>
> News flash: range_of_ones is completely buggy. It will fail on the
> trivial value 1 (__ffs64(1) = 0; 0 - 1 = -1; val >> -1 is... ermmmm).
> I definitely got mixed up between the two.
They do different things!? Aaaaaahhhh....
[ ...]
>> Unless I've gone wrong, I think the 'Trim imm to the element size' code needs to
>> move up into the esz-reducing loop so it doesn't happen for a 64bit immediate.
> Yup. I've stashed the following patch:
>
> diff --git a/arch/arm64/kernel/insn.c b/arch/arm64/kernel/insn.c
> index b8fb2d89b3a6..e58be1c57f18 100644
> --- a/arch/arm64/kernel/insn.c
> +++ b/arch/arm64/kernel/insn.c
> @@ -1503,8 +1503,7 @@ pstate_check_t * const aarch32_opcode_cond_checks[16] = {
> static bool range_of_ones(u64 val)
> {
> /* Doesn't handle full ones or full zeroes */
> - int x = __ffs64(val) - 1;
> - u64 sval = val >> x;
> + u64 sval = val >> __ffs64(val);
>
> /* One of Sean Eron Anderson's bithack tricks */
> return ((sval + 1) & (sval)) == 0;
> @@ -1515,7 +1514,7 @@ static u32 aarch64_encode_immediate(u64 imm,
> u32 insn)
> {
> unsigned int immr, imms, n, ones, ror, esz, tmp;
> - u64 mask;
> + u64 mask = ~0UL;
>
> /* Can't encode full zeroes or full ones */
> if (!imm || !~imm)
> @@ -1543,8 +1542,12 @@ static u32 aarch64_encode_immediate(u64 imm,
> for (tmp = esz; tmp > 2; tmp /= 2) {
> u64 emask = BIT(tmp / 2) - 1;
>
> - if ((imm & emask) != ((imm >> (tmp / 2)) & emask))
> + if ((imm & emask) != ((imm >> (tmp / 2)) & emask)) {
> + /* Trim imm to the element size */
> + mask = BIT(esz - 1) - 1;
> + imm &= mask;
Won't this still lose the top bit? It generates 0x7fffffff for esz=32, and for
esz=32 we run through here when the two 16bit values are different.
This still runs for a 64bit immediate. The 0xf80000000fffffff example compares
0xf8000000 with 0fffffff then breaks here on the first iteration of this loop.
With this change it still attempts to generate a 64bit mask.
I was thinking of something like [0]. That only runs when we know the two
tmp:halves match, it just keeps the bottom tmp:half for the next run and never
runs for a 64bit immediate.
> break;
> + }
>
> esz = tmp;
> }
> @@ -1552,10 +1555,6 @@ static u32 aarch64_encode_immediate(u64 imm,
> /* N is only set if we're encoding a 64bit value */
> n = esz == 64;
>
> - /* Trim imm to the element size */
> - mask = BIT(esz - 1) - 1;
> - imm &= mask;
> -
> /* That's how many ones we need to encode */
> ones = hweight64(imm);
>
> I really need to run this against gas in order to make sure
> I get the same parameters for all the possible values.
Sounds good,
Thanks,
James
[0] Not even built:
diff --git a/arch/arm64/kernel/insn.c b/arch/arm64/kernel/insn.c
index 12d3ec2154c2..d9fbdea7b18d 100644
--- a/arch/arm64/kernel/insn.c
+++ b/arch/arm64/kernel/insn.c
@@ -1529,15 +1529,15 @@ static u32 aarch64_encode_immediate(u64 imm,
break;
esz = tmp;
+
+ /* Trim imm to the element size */
+ mask = BIT(esz) - 1;
+ imm &= mask;
}
/* N is only set if we're encoding a 64bit value */
n = esz == 64;
- /* Trim imm to the element size */
- mask = BIT(esz - 1) - 1;
- imm &= mask;
-
/* That's how many ones we need to encode */
ones = hweight64(imm);
^ permalink raw reply related
* [PATCH 4/4] [v4] pinctrl: qcom: qdf2xxx: add support for new ACPI HID QCOM8002
From: Andy Shevchenko @ 2017-12-13 15:40 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <c41db747-757a-131f-14b6-e181403db007@codeaurora.org>
On Wed, 2017-12-13 at 09:18 -0600, Timur Tabi wrote:
> On 12/13/2017 08:46 AM, Timur Tabi wrote:
> I think I found it. Are you talking about doing this instead:
>
> id = acpi_match_device(pdev->dev.driver->acpi_match_table, &pdev-
> >dev);
Precisely!
--
Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Intel Finland Oy
^ permalink raw reply
* [PATCH 1/1] arm: sunxi: Add alternative pins for spi0
From: Maxime Ripard @ 2017-12-13 15:40 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1513151074-6888-1-git-send-email-stefan@olimex.com>
Hi,
On Wed, Dec 13, 2017 at 09:44:34AM +0200, Stefan Mavrodiev wrote:
> Allwinner A10/A13/A20 SoCs have pinmux for spi0
> on port C. The patch adds these pins in the respective
> dts includes.
>
> Signed-off-by: Stefan Mavrodiev <stefan@olimex.com>
Do you have any boards that are using these?
We won't merge that patch if there's no users for it.
Maxime
--
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20171213/6c0122b7/attachment.sig>
^ permalink raw reply
* [PATCH v3 03/12] media: rkisp1: Add user space ABI definitions
From: Hans Verkuil @ 2017-12-13 15:34 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20171206111939.1153-4-jacob-chen@iotwrt.com>
On 06/12/17 12:19, Jacob Chen wrote:
> From: Jeffy Chen <jeffy.chen@rock-chips.com>
>
> Add the header for userspace
>
> Signed-off-by: Jeffy Chen <jeffy.chen@rock-chips.com>
> Signed-off-by: Jacob Chen <jacob2.chen@rock-chips.com>
> ---
> include/uapi/linux/rkisp1-config.h | 785 +++++++++++++++++++++++++++++++++++++
> 1 file changed, 785 insertions(+)
> create mode 100644 include/uapi/linux/rkisp1-config.h
>
> diff --git a/include/uapi/linux/rkisp1-config.h b/include/uapi/linux/rkisp1-config.h
> new file mode 100644
> index 000000000000..82fecbee23a9
> --- /dev/null
> +++ b/include/uapi/linux/rkisp1-config.h
> @@ -0,0 +1,785 @@
> +/*
> + * Rockchip isp1 driver
> + *
> + * Copyright (C) 2017 Rockchip Electronics Co., Ltd.
> + *
> + * This software is available to you under a choice of one of two
> + * licenses. You may choose to be licensed under the terms of the GNU
> + * General Public License (GPL) Version 2, available from the file
> + * COPYING in the main directory of this source tree, or the
> + * OpenIB.org BSD license below:
> + *
> + * Redistribution and use in source and binary forms, with or
> + * without modification, are permitted provided that the following
> + * conditions are met:
> + *
> + * - Redistributions of source code must retain the above
> + * copyright notice, this list of conditions and the following
> + * disclaimer.
> + *
> + * - Redistributions in binary form must reproduce the above
> + * copyright notice, this list of conditions and the following
> + * disclaimer in the documentation and/or other materials
> + * provided with the distribution.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
> + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
> + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
> + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
> + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
> + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
> + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
> + * SOFTWARE.
Please use the new SPDX license identifier.
> + */
> +
> +#ifndef _UAPI_RKISP1_CONFIG_H
> +#define _UAPI_RKISP1_CONFIG_H
> +
> +#include <linux/types.h>
> +#include <linux/v4l2-controls.h>
> +
> +#define CIFISP_MODULE_DPCC (1 << 0)
> +#define CIFISP_MODULE_BLS (1 << 1)
> +#define CIFISP_MODULE_SDG (1 << 2)
> +#define CIFISP_MODULE_HST (1 << 3)
> +#define CIFISP_MODULE_LSC (1 << 4)
> +#define CIFISP_MODULE_AWB_GAIN (1 << 5)
> +#define CIFISP_MODULE_FLT (1 << 6)
> +#define CIFISP_MODULE_BDM (1 << 7)
> +#define CIFISP_MODULE_CTK (1 << 8)
> +#define CIFISP_MODULE_GOC (1 << 9)
> +#define CIFISP_MODULE_CPROC (1 << 10)
> +#define CIFISP_MODULE_AFC (1 << 11)
> +#define CIFISP_MODULE_AWB (1 << 12)
> +#define CIFISP_MODULE_IE (1 << 13)
> +#define CIFISP_MODULE_AEC (1 << 14)
> +#define CIFISP_MODULE_WDR (1 << 15)
> +#define CIFISP_MODULE_DPF (1 << 16)
> +#define CIFISP_MODULE_DPF_STRENGTH (1 << 17)
> +
> +#define CIFISP_CTK_COEFF_MAX 0x100
> +#define CIFISP_CTK_OFFSET_MAX 0x800
> +
> +#define CIFISP_AE_MEAN_MAX 25
> +#define CIFISP_HIST_BIN_N_MAX 16
> +#define CIFISP_AFM_MAX_WINDOWS 3
> +#define CIFISP_DEGAMMA_CURVE_SIZE 17
> +
> +#define CIFISP_BDM_MAX_TH 0xFF
> +
> +/*
> + * Black level compensation
> + */
> +/* maximum value for horizontal start address */
> +#define CIFISP_BLS_START_H_MAX 0x00000FFF
> +/* maximum value for horizontal stop address */
> +#define CIFISP_BLS_STOP_H_MAX 0x00000FFF
> +/* maximum value for vertical start address */
> +#define CIFISP_BLS_START_V_MAX 0x00000FFF
> +/* maximum value for vertical stop address */
> +#define CIFISP_BLS_STOP_V_MAX 0x00000FFF
> +/* maximum is 2^18 = 262144*/
> +#define CIFISP_BLS_SAMPLES_MAX 0x00000012
> +/* maximum value for fixed black level */
> +#define CIFISP_BLS_FIX_SUB_MAX 0x00000FFF
> +/* minimum value for fixed black level */
> +#define CIFISP_BLS_FIX_SUB_MIN 0xFFFFF000
> +/* 13 bit range (signed)*/
> +#define CIFISP_BLS_FIX_MASK 0x00001FFF
> +
> +/*
> + * Automatic white balance measurments
> + */
> +#define CIFISP_AWB_MAX_GRID 1
> +#define CIFISP_AWB_MAX_FRAMES 7
> +
> +/*
> + * Gamma out
> + */
> +/* Maximum number of color samples supported */
> +#define CIFISP_GAMMA_OUT_MAX_SAMPLES 17
> +
> +/*
> + * Lens shade correction
> + */
> +#define CIFISP_LSC_GRAD_TBL_SIZE 8
> +#define CIFISP_LSC_SIZE_TBL_SIZE 8
> +/*
> + * The following matches the tuning process,
> + * not the max capabilities of the chip.
> + * Last value unused.
> + */
> +#define CIFISP_LSC_DATA_TBL_SIZE 290
> +
> +/*
> + * Histogram calculation
> + */
> +/* Last 3 values unused. */
> +#define CIFISP_HISTOGRAM_WEIGHT_GRIDS_SIZE 28
> +
> +/*
> + * Defect Pixel Cluster Correction
> + */
> +#define CIFISP_DPCC_METHODS_MAX 3
> +
> +/*
> + * Denoising pre filter
> + */
> +#define CIFISP_DPF_MAX_NLF_COEFFS 17
> +#define CIFISP_DPF_MAX_SPATIAL_COEFFS 6
> +
> +/*
> + * Measurement types
> + */
> +#define CIFISP_STAT_AWB (1 << 0)
> +#define CIFISP_STAT_AUTOEXP (1 << 1)
> +#define CIFISP_STAT_AFM_FIN (1 << 2)
> +#define CIFISP_STAT_HIST (1 << 3)
> +
> +enum cifisp_histogram_mode {
> + CIFISP_HISTOGRAM_MODE_DISABLE,
> + CIFISP_HISTOGRAM_MODE_RGB_COMBINED,
> + CIFISP_HISTOGRAM_MODE_R_HISTOGRAM,
> + CIFISP_HISTOGRAM_MODE_G_HISTOGRAM,
> + CIFISP_HISTOGRAM_MODE_B_HISTOGRAM,
> + CIFISP_HISTOGRAM_MODE_Y_HISTOGRAM
> +};
> +
> +enum cifisp_awb_mode_type {
> + CIFISP_AWB_MODE_MANUAL,
> + CIFISP_AWB_MODE_RGB,
> + CIFISP_AWB_MODE_YCBCR
> +};
> +
> +enum cifisp_flt_mode {
> + CIFISP_FLT_STATIC_MODE,
> + CIFISP_FLT_DYNAMIC_MODE
> +};
> +
> +/**
> + * enum cifisp_exp_ctrl_auotostop - stop modes
> + * @CIFISP_EXP_CTRL_AUTOSTOP_0: continuous measurement
> + * @CIFISP_EXP_CTRL_AUTOSTOP_1: stop measuring after a complete frame
> + */
> +enum cifisp_exp_ctrl_auotostop {
> + CIFISP_EXP_CTRL_AUTOSTOP_0 = 0,
> + CIFISP_EXP_CTRL_AUTOSTOP_1 = 1,
> +};
> +
> +/**
> + * enum cifisp_exp_meas_mode - Exposure measure mode
> + * @CIFISP_EXP_MEASURING_MODE_0: Y = 16 + 0.25R + 0.5G + 0.1094B
> + * @CIFISP_EXP_MEASURING_MODE_1: Y = (R + G + B) x (85/256)
> + */
> +enum cifisp_exp_meas_mode {
> + CIFISP_EXP_MEASURING_MODE_0,
> + CIFISP_EXP_MEASURING_MODE_1,
> +};
> +
> +/*---------- PART1: Input Parameters ------------*/
> +
> +struct cifisp_window {
> + unsigned short h_offs;
> + unsigned short v_offs;
> + unsigned short h_size;
> + unsigned short v_size;
Use __u16 et al instead of unsigned short etc. It's the safest way to do this.
> +} __attribute__ ((packed));
> +
> +/**
> + * struct cifisp_bls_fixed_val - BLS fixed subtraction values
> + *
> + * The values will be subtracted from the sensor
> + * values. Therefore a negative value means addition instead of subtraction!
> + *
> + * @r: Fixed (signed!) subtraction value for Bayer pattern R
> + * @gr: Fixed (signed!) subtraction value for Bayer pattern Gr
> + * @gb: Fixed (signed!) subtraction value for Bayer pattern Gb
> + * @b: Fixed (signed!) subtraction value for Bayer pattern B
> + */
> +struct cifisp_bls_fixed_val {
> + signed short r;
> + signed short gr;
> + signed short gb;
> + signed short b;
> +} __attribute__ ((packed));
> +
> +/**
> + * struct cifisp_bls_config - Configuration used by black level subtraction
> + *
> + * @enable_auto: Automatic mode activated means that the measured values
> + * are subtracted.Otherwise the fixed subtraction
Space after '.'
> + * values will be subtracted.
> + * @en_windows: enabled window
> + * @bls_window1: Measurement window 1 size
> + * @bls_window2: Measurement window 2 size
> + * @bls_samples: Set amount of measured pixels for each Bayer position
> + * (A, B,C and D) to 2^bls_samples.
> + * @cifisp_bls_fixed_val: Fixed subtraction values
> + */
> +struct cifisp_bls_config {
> + bool enable_auto;
Don't use bool, use __u8.
> + unsigned char en_windows;
> + struct cifisp_window bls_window1;
> + struct cifisp_window bls_window2;
> + unsigned char bls_samples;
> + struct cifisp_bls_fixed_val fixed_val;
> +} __attribute__ ((packed));
> +
> +/**
> + * struct cifisp_dpcc_methods_config - Methods Configuration used by Defect Pixel Cluster Correction
> + *
> + * @method:
> + * @line_thresh:
> + * @line_mad_fac:
> + * @pg_fac:
> + * @rnd_thresh:
> + * @rg_fac:
> + */
> +struct cifisp_dpcc_methods_config {
> + unsigned int method;
> + unsigned int line_thresh;
> + unsigned int line_mad_fac;
> + unsigned int pg_fac;
> + unsigned int rnd_thresh;
> + unsigned int rg_fac;
> +} __attribute__ ((packed));
> +
> +/**
> + * struct cifisp_dpcc_methods_config - Configuration used by Defect Pixel Cluster Correction
> + *
> + * @mode: dpcc output mode
> + * @output_mode: whether use hard coded methods
> + * @set_use: stage1 methods set
> + * @methods: methods config
> + * @ro_limits: rank order limits
> + * @rnd_offs: differential rank offsets for rank neighbor difference
> + */
> +struct cifisp_dpcc_config {
> + unsigned int mode;
> + unsigned int output_mode;
> + unsigned int set_use;
> + struct cifisp_dpcc_methods_config methods[CIFISP_DPCC_METHODS_MAX];
> + unsigned int ro_limits;
> + unsigned int rnd_offs;
> +} __attribute__ ((packed));
> +
> +struct cifisp_gamma_corr_curve {
> + unsigned short gamma_y[CIFISP_DEGAMMA_CURVE_SIZE];
> +} __attribute__ ((packed));
> +
> +struct cifisp_gamma_curve_x_axis_pnts {
> + unsigned int gamma_dx0;
> + unsigned int gamma_dx1;
> +} __attribute__ ((packed));
Can add a short description of the two structs above?
> +
> +/**
> + * struct cifisp_gamma_corr_curve - Configuration used by sensor degamma
> + *
> + * @curve_x: gamma curve point defintion axis for x
defintion -> definition
> + * @xa_pnts: x increments
> + */
> +struct cifisp_sdg_config {
> + struct cifisp_gamma_corr_curve curve_r;
> + struct cifisp_gamma_corr_curve curve_g;
> + struct cifisp_gamma_corr_curve curve_b;
> + struct cifisp_gamma_curve_x_axis_pnts xa_pnts;
> +} __attribute__ ((packed));
> +
> +/**
> + * struct cifisp_lsc_config - Configuration used by Lens shading correction
> + *
> + * refer to datasheet for details
> + */
> +struct cifisp_lsc_config {
> + unsigned int r_data_tbl[CIFISP_LSC_DATA_TBL_SIZE];
> + unsigned int gr_data_tbl[CIFISP_LSC_DATA_TBL_SIZE];
> + unsigned int gb_data_tbl[CIFISP_LSC_DATA_TBL_SIZE];
> + unsigned int b_data_tbl[CIFISP_LSC_DATA_TBL_SIZE];
> +
> + unsigned int x_grad_tbl[CIFISP_LSC_GRAD_TBL_SIZE];
> + unsigned int y_grad_tbl[CIFISP_LSC_GRAD_TBL_SIZE];
> +
> + unsigned int x_size_tbl[CIFISP_LSC_SIZE_TBL_SIZE];
> + unsigned int y_size_tbl[CIFISP_LSC_SIZE_TBL_SIZE];
> + unsigned short config_width;
> + unsigned short config_height;
> +} __attribute__ ((packed));
> +
> +/**
> + * struct cifisp_ie_config - Configuration used by image effects
> + *
> + * @eff_mat_1: 3x3 Matrix Coefficients for Emboss Effect 1
> + * @eff_mat_2: 3x3 Matrix Coefficients for Emboss Effect 2
> + * @eff_mat_3: 3x3 Matrix Coefficients for Emboss 3/Sketch 1
> + * @eff_mat_4: 3x3 Matrix Coefficients for Sketch Effect 2
> + * @eff_mat_5: 3x3 Matrix Coefficients for Sketch Effect 3
> + * @eff_tint: Chrominance increment values of tint (used for sepia effect)
> + */
> +struct cifisp_ie_config {
> + enum v4l2_colorfx effect;
Avoid enums, use __u16 here.
> + unsigned short color_sel;
> + unsigned short eff_mat_1;
> + unsigned short eff_mat_2;
> + unsigned short eff_mat_3;
> + unsigned short eff_mat_4;
> + unsigned short eff_mat_5;
> + unsigned short eff_tint;
> +} __attribute__ ((packed));
> +
> +/**
> + * struct cifisp_cproc_config - Configuration used by Color Processing
> + *
> + * @c_out_range: Chrominance pixel clippping range at output. (0 for limit, 1 for full)
> + * @y_in_range: Luminance pixel clippping range at output.
> + * @y_out_range: Luminance pixel clippping range at output.
clippping -> clipping (three times)
> + * @contrast: 00~ff, 0.0~1.992
> + * @brightness: 80~7F, -128~+127
> + * @sat: saturation, 00~FF, 0.0~1.992
> + * @hue: 80~7F, -90~+87.188
> + */
> +struct cifisp_cproc_config {
> + unsigned char c_out_range;
> + unsigned char y_in_range;
> + unsigned char y_out_range;
> + unsigned char contrast;
> + unsigned char brightness;
> + unsigned char sat;
> + unsigned char hue;
> +} __attribute__ ((packed));
> +
> +/**
> + * struct cifisp_awb_meas_config - Configuration used by auto white balance
> + *
> + * @awb_wnd: white balance measurement window (in pixels)
> + * @max_y: only pixels values < max_y contribute to awb measurement, set to 0 to disable this feature
> + * @min_y: only pixels values > min_y contribute to awb measurement
> + * @max_csum: Chrominance sum maximum value, only consider pixels with Cb+Cr, smaller than threshold for awb measurements
> + * @min_c: Chrominance minimum value, only consider pixels with Cb/Cr each greater than threshold value for awb measurements
> + * @frames: number of frames - 1 used for mean value calculation(ucFrames=0 means 1 Frame)
> + * @awb_ref_cr: reference Cr value for AWB regulation, target for AWB
> + * @awb_ref_cb: reference Cb value for AWB regulation, target for AWB
> + */
> +struct cifisp_awb_meas_config {
> + /*
> + * Note: currently the h and v offsets are mapped to grid offsets
> + */
> + struct cifisp_window awb_wnd;
> + enum cifisp_awb_mode_type awb_mode;
> + unsigned char max_y;
> + unsigned char min_y;
> + unsigned char max_csum;
> + unsigned char min_c;
> + unsigned char frames;
> + unsigned char awb_ref_cr;
> + unsigned char awb_ref_cb;
> + bool enable_ymax_cmp;
> +} __attribute__ ((packed));
> +
> +/**
> + * struct cifisp_awb_gain_config - Configuration used by auto white balance gain
> + *
> + * out_data_x = ( AWB_GEAIN_X * in_data + 128) >> 8
> + */
> +struct cifisp_awb_gain_config {
> + unsigned short gain_red;
> + unsigned short gain_green_r;
> + unsigned short gain_blue;
> + unsigned short gain_green_b;
> +} __attribute__ ((packed));
> +
> +/**
> + * struct cifisp_flt_config - Configuration used by ISP filtering
> + *
> + * @mode: ISP_FILT_MODE register fields
> + * @grn_stage1: ISP_FILT_MODE register fields
> + * @chr_h_mode: ISP_FILT_MODE register fields
> + * @chr_v_mode: ISP_FILT_MODE register fields
> + *
> + * refer to datasheet for details.
> + */
> +struct cifisp_flt_config {
> + enum cifisp_flt_mode mode;
> + unsigned char grn_stage1;
> + unsigned char chr_h_mode;
> + unsigned char chr_v_mode;
> + unsigned int thresh_bl0;
> + unsigned int thresh_bl1;
> + unsigned int thresh_sh0;
> + unsigned int thresh_sh1;
> + unsigned int lum_weight;
> + unsigned int fac_sh1;
> + unsigned int fac_sh0;
> + unsigned int fac_mid;
> + unsigned int fac_bl0;
> + unsigned int fac_bl1;
> +} __attribute__ ((packed));
> +
> +/**
> + * struct cifisp_bdm_config - Configuration used by Bayer DeMosaic
> + *
> + * @demosaic_th: threshod for bayer demosaicing texture detection
> + */
> +struct cifisp_bdm_config {
> + unsigned char demosaic_th;
> +} __attribute__ ((packed));
> +
> +/**
> + * struct cifisp_ctk_config - Configuration used by Cross Talk correction
> + *
> + * @coeff: color correction matrix
> + * @ct_offset_b: offset for the crosstalk correction matrix
> + */
> +struct cifisp_ctk_config {
> + unsigned short coeff0;
> + unsigned short coeff1;
> + unsigned short coeff2;
> + unsigned short coeff3;
> + unsigned short coeff4;
> + unsigned short coeff5;
> + unsigned short coeff6;
> + unsigned short coeff7;
> + unsigned short coeff8;
> + unsigned short ct_offset_r;
> + unsigned short ct_offset_g;
> + unsigned short ct_offset_b;
> +} __attribute__ ((packed));
> +
> +enum cifisp_goc_mode {
> + CIFISP_GOC_MODE_LOGARITHMIC,
> + CIFISP_GOC_MODE_EQUIDISTANT
> +} __attribute__ ((packed));
> +
> +/**
> + * struct cifisp_goc_config - Configuration used by Gamma Out correction
> + *
> + * @mode: goc mode
> + * @gamma_y: gamma out curve y-axis for all color components
> + */
> +struct cifisp_goc_config {
> + enum cifisp_goc_mode mode;
> + unsigned short gamma_y[CIFISP_GAMMA_OUT_MAX_SAMPLES];
> +} __attribute__ ((packed));
> +
> +/**
> + * struct cifisp_hst_config - Configuration used by Histogram
> + *
> + * @mode: histogram mode
> + * @histogram_predivider: process every stepsize pixel, all other pixels are skipped
> + * @meas_window: coordinates of the meas window
> + * @hist_weight: weighting factor for sub-windows
> + */
> +struct cifisp_hst_config {
> + enum cifisp_histogram_mode mode;
> + unsigned char histogram_predivider;
> + struct cifisp_window meas_window;
> + unsigned char hist_weight[CIFISP_HISTOGRAM_WEIGHT_GRIDS_SIZE];
> +} __attribute__ ((packed));
> +
> +/**
> + * struct cifisp_aec_config - Configuration used by Auto Exposure Control
> + *
> + * @mode: Exposure measure mode
> + * @autostop: stop mode (from enum cifisp_exp_ctrl_auotostop)
> + * @meas_window: coordinates of the meas window
> + */
> +struct cifisp_aec_config {
> + enum cifisp_exp_meas_mode mode;
> + __u32 autostop;
> + struct cifisp_window meas_window;
> +} __attribute__ ((packed));
> +
> +/**
> + * struct cifisp_afc_config - Configuration used by Auto Focus Control
> + *
> + * @num_afm_win: max CIFISP_AFM_MAX_WINDOWS
> + * @afm_win: coordinates of the meas window
> + * @thres: threshold used for minimizing the influence of noise
> + * @var_shift: the number of bits for the shift operation at the end of the calculaton chain.
calculaton -> calculation
> + */
> +struct cifisp_afc_config {
> + unsigned char num_afm_win;
> + struct cifisp_window afm_win[CIFISP_AFM_MAX_WINDOWS];
> + unsigned int thres;
> + unsigned int var_shift;
> +} __attribute__ ((packed));
> +
> +/**
> + * enum cifisp_dpf_gain_usage - dpf gain usage
> + * @CIFISP_DPF_GAIN_USAGE_DISABLED: don't use any gains in preprocessing stage
> + * @CIFISP_DPF_GAIN_USAGE_NF_GAINS: use only the noise function gains from registers DPF_NF_GAIN_R, ...
> + * @CIFISP_DPF_GAIN_USAGE_LSC_GAINS: use only the gains from LSC module
> + * @CIFISP_DPF_GAIN_USAGE_NF_LSC_GAINS: use the moise function gains and the gains from LSC module
moise -> noise
> + * @CIFISP_DPF_GAIN_USAGE_AWB_GAINS: use only the gains from AWB module
> + * @CIFISP_DPF_GAIN_USAGE_AWB_LSC_GAINS: use the gains from AWB and LSC module
> + * @CIFISP_DPF_GAIN_USAGE_MAX: upper border (only for an internal evaluation)
> + */
> +enum cifisp_dpf_gain_usage {
> + CIFISP_DPF_GAIN_USAGE_DISABLED,
> + CIFISP_DPF_GAIN_USAGE_NF_GAINS,
> + CIFISP_DPF_GAIN_USAGE_LSC_GAINS,
> + CIFISP_DPF_GAIN_USAGE_NF_LSC_GAINS,
> + CIFISP_DPF_GAIN_USAGE_AWB_GAINS,
> + CIFISP_DPF_GAIN_USAGE_AWB_LSC_GAINS,
> + CIFISP_DPF_GAIN_USAGE_MAX
> +};
> +
> +/**
> + * enum cifisp_dpf_gain_usage - dpf gain usage
> + * @CIFISP_DPF_RB_FILTERSIZE_13x9: red and blue filter kernel size 13x9 (means 7x5 active pixel)
> + * @CIFISP_DPF_RB_FILTERSIZE_9x9: red and blue filter kernel size 9x9 (means 5x5 active pixel)
> + */
> +enum cifisp_dpf_rb_filtersize {
> + CIFISP_DPF_RB_FILTERSIZE_13x9,
> + CIFISP_DPF_RB_FILTERSIZE_9x9,
> +};
> +
> +/**
> + * enum cifisp_dpf_nll_scale_mode - dpf noise level scale mode
> + * @CIFISP_NLL_SCALE_LINEAR: use a linear scaling
> + * @CIFISP_NLL_SCALE_LOGARITHMIC: use a logarithmic scaling
> + */
> +enum cifisp_dpf_nll_scale_mode {
> + CIFISP_NLL_SCALE_LINEAR,
> + CIFISP_NLL_SCALE_LOGARITHMIC,
> +};
> +
> +struct cifisp_dpf_nll {
> + unsigned short coeff[CIFISP_DPF_MAX_NLF_COEFFS];
> + enum cifisp_dpf_nll_scale_mode scale_mode;
> +} __attribute__ ((packed));
> +
> +struct cifisp_dpf_rb_flt {
> + enum cifisp_dpf_rb_filtersize fltsize;
> + unsigned char spatial_coeff[CIFISP_DPF_MAX_SPATIAL_COEFFS];
> + bool r_enable;
> + bool b_enable;
> +} __attribute__ ((packed));
> +
> +struct cifisp_dpf_g_flt {
> + unsigned char spatial_coeff[CIFISP_DPF_MAX_SPATIAL_COEFFS];
> + bool gr_enable;
> + bool gb_enable;
> +} __attribute__ ((packed));
> +
> +struct cifisp_dpf_gain {
> + enum cifisp_dpf_gain_usage mode;
> + unsigned short nf_r_gain;
> + unsigned short nf_b_gain;
> + unsigned short nf_gr_gain;
> + unsigned short nf_gb_gain;
> +} __attribute__ ((packed));
> +
> +/**
> + * struct cifisp_dpf_config - Configuration used by De-noising pre-filiter
> + *
> + * @gain: noise function gain
> + * @g_flt: green filiter config
> + * @rb_flt: red blue filiter config
filiter -> filter (2x)
> + * @nll: noise level lookup
> + */
> +struct cifisp_dpf_config {
> + struct cifisp_dpf_gain gain;
> + struct cifisp_dpf_g_flt g_flt;
> + struct cifisp_dpf_rb_flt rb_flt;
> + struct cifisp_dpf_nll nll;
> +} __attribute__ ((packed));
> +
> +/**
> + * struct cifisp_dpf_strength_config - strength of the filiter
Ditto.
> + *
> + * @r: filter strength of the RED filter
> + * @g: filter strength of the GREEN filter
> + * @b: filter strength of the BLUE filter
> + */
> +struct cifisp_dpf_strength_config {
> + unsigned char r;
> + unsigned char g;
> + unsigned char b;
> +} __attribute__ ((packed));
> +
> +/**
> + * struct cifisp_isp_other_cfg - Parameters for some blocks in rockchip isp1
> + *
> + * @dpcc_config: Defect Pixel Cluster Correction config
> + * @bls_config: Black Level Subtraction config
> + * @sdg_config: sensor degamma config
> + * @lsc_config: Lens Shade config
> + * @awb_gain_config: Auto White balance gain config
> + * @flt_config: filter config
> + * @bdm_config: demosaic config
> + * @ctk_config: cross talk config
> + * @goc_config: gamma out config
> + * @bls_config: black level suntraction config
> + * @dpf_config: De-noising pre-filiter config
> + * @dpf_strength_config: dpf strength config
> + * @cproc_config: color process config
> + * @ie_config: image effects config
> + */
> +struct cifisp_isp_other_cfg {
> + struct cifisp_dpcc_config dpcc_config;
> + struct cifisp_bls_config bls_config;
> + struct cifisp_sdg_config sdg_config;
> + struct cifisp_lsc_config lsc_config;
> + struct cifisp_awb_gain_config awb_gain_config;
> + struct cifisp_flt_config flt_config;
> + struct cifisp_bdm_config bdm_config;
> + struct cifisp_ctk_config ctk_config;
> + struct cifisp_goc_config goc_config;
> + struct cifisp_dpf_config dpf_config;
> + struct cifisp_dpf_strength_config dpf_strength_config;
> + struct cifisp_cproc_config cproc_config;
> + struct cifisp_ie_config ie_config;
> +} __attribute__ ((packed));
> +
> +/**
> + * struct cifisp_isp_meas_cfg - Rockchip ISP1 Measure Parameters
> + *
> + * @awb_meas_config: auto white balance config
> + * @hst_config: histogram config
> + * @aec_config: auto exposure config
> + * @afc_config: auto focus config
> + */
> +struct cifisp_isp_meas_cfg {
> + struct cifisp_awb_meas_config awb_meas_config;
> + struct cifisp_hst_config hst_config;
> + struct cifisp_aec_config aec_config;
> + struct cifisp_afc_config afc_config;
> +} __attribute__ ((packed));
> +
> +/**
> + * struct rkisp1_isp_params_cfg - Rockchip ISP1 Input Parameters Meta Data
> + *
> + * @module_en_update: mask the enable bits of which module should be updated
> + * @module_ens: mask the enable value of each module, only update the module
> + * which correspond bit was set in module_en_update
> + * @module_cfg_update: mask the config bits of which module should be updated
> + * @meas: measurement config
> + * @others: other config
> + */
> +struct rkisp1_isp_params_cfg {
> + unsigned int module_en_update;
> + unsigned int module_ens;
> + unsigned int module_cfg_update;
> +
> + struct cifisp_isp_meas_cfg meas;
> + struct cifisp_isp_other_cfg others;
> +} __attribute__ ((packed));
> +
> +/*---------- PART2: Measurement Statistics ------------*/
> +
> +/**
> + * struct cifisp_bls_meas_val - AWB measured values
> + *
> + * @cnt: White pixel count, number of "white pixels" found during laster measurement
> + * @mean_y_or_g: Mean value of Y within window and frames, Green if RGB is selected.
> + * @mean_cb_or_b: Mean value of Cb within window and frames, Blue if RGB is selected.
> + * @mean_cr_or_r: Mean value of Cr within window and frames, Red if RGB is selected.
> + */
> +struct cifisp_awb_meas {
> + unsigned int cnt;
> + unsigned char mean_y_or_g;
> + unsigned char mean_cb_or_b;
> + unsigned char mean_cr_or_r;
> +} __attribute__ ((packed));
> +
> +/**
> + * struct cifisp_awb_stat - statistics automatic white balance data
> + *
> + * @awb_mean: Mean measured data
> + */
> +struct cifisp_awb_stat {
> + struct cifisp_awb_meas awb_mean[CIFISP_AWB_MAX_GRID];
> +} __attribute__ ((packed));
> +
> +/**
> + * struct cifisp_bls_meas_val - BLS measured values
> + *
> + * @meas_r: Mean measured value for Bayer pattern R
> + * @meas_gr: Mean measured value for Bayer pattern Gr
> + * @meas_gb: Mean measured value for Bayer pattern Gb
> + * @meas_b: Mean measured value for Bayer pattern B
> + */
> +struct cifisp_bls_meas_val {
> + unsigned short meas_r;
> + unsigned short meas_gr;
> + unsigned short meas_gb;
> + unsigned short meas_b;
> +} __attribute__ ((packed));
> +
> +/**
> + * struct cifisp_ae_stat - statistics auto exposure data
> + *
> + * @exp_mean: Mean luminance value of block xx
> + * @bls_val: available wit exposure results
> + *
> + * Image is divided into 5x5 blocks.
> + */
> +struct cifisp_ae_stat {
> + unsigned char exp_mean[CIFISP_AE_MEAN_MAX];
> + struct cifisp_bls_meas_val bls_val;
> +} __attribute__ ((packed));
> +
> +/**
> + * struct cifisp_af_meas_val - AF measured values
> + *
> + * @sum: sharpness, refer to datasheet for definition
> + * @lum: luminance, refer to datasheet for definition
> + */
> +struct cifisp_af_meas_val {
> + unsigned int sum;
> + unsigned int lum;
> +} __attribute__ ((packed));
> +
> +/**
> + * struct cifisp_af_stat - statistics auto focus data
> + *
> + * @window: AF measured value of window x
> + *
> + * The module measures the sharpness in 3 windows of selectable size via
> + * register settings(ISP_AFM_*_A/B/C)
> + */
> +struct cifisp_af_stat {
> + struct cifisp_af_meas_val window[CIFISP_AFM_MAX_WINDOWS];
> +} __attribute__ ((packed));
> +
> +/**
> + * struct cifisp_hist_stat - statistics histogram data
> + *
> + * @hist_bins: measured bin counters
> + *
> + * Measurement window divided into 25 sub-windows, set
> + * with ISP_HIST_XXX
> + */
> +struct cifisp_hist_stat {
> + unsigned short hist_bins[CIFISP_HIST_BIN_N_MAX];
> +} __attribute__ ((packed));
> +
> +/**
> + * struct rkisp1_stat_buffer - Rockchip ISP1 Statistics Data
> + *
> + * @cifisp_awb_stat: statistics data for automatic white balance
> + * @cifisp_ae_stat: statistics data for auto exposure
> + * @cifisp_af_stat: statistics data for auto focus
> + * @cifisp_hist_stat: statistics histogram data
> + */
> +struct cifisp_stat {
> + struct cifisp_awb_stat awb;
> + struct cifisp_ae_stat ae;
> + struct cifisp_af_stat af;
> + struct cifisp_hist_stat hist;
> +} __attribute__ ((packed));
> +
> +/**
> + * struct rkisp1_stat_buffer - Rockchip ISP1 Statistics Meta Data
> + *
> + * @meas_type: measurement types (CIFISP_STAT_ definitions)
> + * @frame_id: frame ID for sync
> + * @params: statistics data
> + */
> +struct rkisp1_stat_buffer {
> + unsigned int meas_type;
> + unsigned int frame_id;
> + struct cifisp_stat params;
> +} __attribute__ ((packed));
> +
> +#endif /* _UAPI_RKISP1_CONFIG_H */
>
So it is very hard to tell whether there are 32 vs 64 bit issues from reading
this header.
For the daily build of V4L2 I've made a little script to test if the ABI changed.
The scripts I use are part of this archive:
https://hverkuil.home.xs4all.nl/logs/scripts.tar.bz2
Specifically stabs-parser.pl and build.sh. The build.sh script is the main shell
script that builds media for all the various architectures. At line 499 it creates
a little test.c source that is basically a union with all the various top-level data
structs used by v4l2.
It then compiles it using the -gstabs compiler option and feeds the test.s to the
stabs-parser. The output looks like this:
v4l2_bt_timings: struct(124) { width at 0(4) height at 4(4) interlaced at 8(4) polarities at 12(4) pixelclock at 16(8) hfrontporch at 24(4) hsync at 28(4) hbackporch at 32(4) vfrontporch at 36(4) vsync at 40(4) vbackporch at 44(4)
il_vfrontporch at 48(4) il_vsync at 52(4) il_vbackporch at 56(4) standards at 60(4) flags at 64(4) picture_aspect at 68(8) cea861_vic at 76(1) hdmi_vic at 77(1) reserved[]@78(46) }
v4l2_bt_timings_cap: struct(104) { min_width at 0(4) max_width at 4(4) min_height at 8(4) max_height at 12(4) min_pixelclock at 16(8) max_pixelclock at 24(8) standards at 32(4) capabilities at 36(4) reserved[]@40(64) }
v4l2_buf_type:T0=eV4L2_BUF_TYPE_VIDEO_CAPTURE:1,V4L2_BUF_TYPE_VIDEO_OUTPUT:2,V4L2_BUF_TYPE_VIDEO_OVERLAY:3,V4L2_BUF_TYPE_VBI_CAPTURE:4,V4L2_BUF_TYPE_VBI_OUTPUT:5,V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:6,V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:7,V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:8,V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:9,V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:10,V4L2_BUF_TYPE_SDR_CAPTURE:11,V4L2_BUF_TYPE_SDR_OUTPUT:12,V4L2_BUF_TYPE_META_CAPTURE:13,V4L2_BUF_TYPE_PRIVATE:128,}
v4l2_buffer: struct(68) { index at 0(4) type at 4(4) bytesused at 8(4) flags at 12(4) field at 16(4) timestamp at 20(8) timecode at 28(16) sequence at 44(4) memory at 48(4) m union(4) { offset at 0(4) userptr at 0(4) planes*@0(4)
fd at 0(4) }@52(4) } length at 56(4) reserved2 at 60(4) reserved at 64(4) }
v4l2_capability: struct(104) { driver[]@0(16) card[]@16(32) bus_info at 48(32) version at 80(4) capabilities at 84(4) device_caps at 88(4) reserved[]@92(12) }
It shows the sizes and offsets of all the fields. In your case compiling this program
for 32 bit and 64 bit and parsing the stabs info should result in the same layout.
It's not elegant perhaps, but it works well.
Regards,
Hans
^ permalink raw reply
* [PATCH 8/8] ARM: dts: sun8i: a33 Enable our display frontend
From: Maxime Ripard @ 2017-12-13 15:33 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <cover.63722fe4aeb908cf3c6f73874bdf69b193fe43c9.1513178989.git-series.maxime.ripard@free-electrons.com>
The display frontend can be used to do hardware scaling, colorspaces
conversion or to implement the buffer format output by the Cedar VPU.
Since we're starting to have some support for it in the DRM driver, let's
enable its DT node.
Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
arch/arm/boot/dts/sun8i-a33.dtsi | 1 -
1 file changed, 1 deletion(-)
diff --git a/arch/arm/boot/dts/sun8i-a33.dtsi b/arch/arm/boot/dts/sun8i-a33.dtsi
index 50eb84fa246a..a21f2ed07a52 100644
--- a/arch/arm/boot/dts/sun8i-a33.dtsi
+++ b/arch/arm/boot/dts/sun8i-a33.dtsi
@@ -289,7 +289,6 @@
clock-names = "ahb", "mod",
"ram";
resets = <&ccu RST_BUS_DE_FE>;
- status = "disabled";
ports {
#address-cells = <1>;
--
git-series 0.9.1
^ permalink raw reply related
* [PATCH 7/8] drm/sun4i: sun4i_layer: Add a custom atomic_check for the frontend
From: Maxime Ripard @ 2017-12-13 15:33 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <cover.63722fe4aeb908cf3c6f73874bdf69b193fe43c9.1513178989.git-series.maxime.ripard@free-electrons.com>
Now that we have everything in place, we can start enabling the frontend.
This is more difficult than one would assume since there can only be one
plane using the frontend per-backend.
We therefore need to make sure that the userspace will not try to setup
multiple planes using it, since that would be impossible. In order to
prevent that, we can create an atomic_check callback that will check that
only one plane will effectively make use of the frontend in a given
configuration, and will toggle the switch in that plane state so that the
proper setup function can do their role.
Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
drivers/gpu/drm/sun4i/sun4i_backend.c | 65 ++++++++++++++++++++++++++++-
drivers/gpu/drm/sun4i/sun4i_backend.h | 2 +-
2 files changed, 67 insertions(+)
diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c
index f1d19767c55d..a7b87a12990e 100644
--- a/drivers/gpu/drm/sun4i/sun4i_backend.c
+++ b/drivers/gpu/drm/sun4i/sun4i_backend.c
@@ -11,6 +11,7 @@
*/
#include <drm/drmP.h>
+#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h>
#include <drm/drm_crtc_helper.h>
@@ -271,6 +272,69 @@ int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend,
return 0;
}
+static bool sun4i_backend_plane_uses_scaler(struct drm_plane_state *state)
+{
+ u16 src_h = state->src_h >> 16;
+ u16 src_w = state->src_w >> 16;
+
+ DRM_DEBUG_DRIVER("Input size %dx%d, output size %dx%d\n",
+ src_w, src_h, state->crtc_w, state->crtc_h);
+
+ if ((state->crtc_h != src_h) || (state->crtc_w != src_w))
+ return true;
+
+ return false;
+}
+
+static bool sun4i_backend_plane_uses_frontend(struct drm_plane_state *state)
+{
+ struct sun4i_layer *layer = plane_to_sun4i_layer(state->plane);
+ struct sun4i_backend *backend = layer->backend;
+
+ if (IS_ERR(backend->frontend))
+ return false;
+
+ return sun4i_backend_plane_uses_scaler(state);
+}
+
+static int sun4i_backend_atomic_check(struct sunxi_engine *engine,
+ struct drm_crtc_state *crtc_state)
+{
+ struct drm_atomic_state *state = crtc_state->state;
+ struct drm_device *drm = state->dev;
+ struct drm_plane *plane;
+ unsigned int num_frontend_planes = 0;
+
+ DRM_DEBUG_DRIVER("Starting checking our planes\n");
+
+ if (!crtc_state->planes_changed)
+ return 0;
+
+ drm_for_each_plane_mask(plane, drm, crtc_state->plane_mask) {
+ struct drm_plane_state *plane_state =
+ drm_atomic_get_plane_state(state, plane);
+ struct sun4i_layer_state *layer_state =
+ state_to_sun4i_layer_state(plane_state);
+
+ if (sun4i_backend_plane_uses_frontend(plane_state)) {
+ DRM_DEBUG_DRIVER("Using the frontend for plane %d\n",
+ plane->index);
+
+ layer_state->uses_frontend = true;
+ num_frontend_planes++;
+ } else {
+ layer_state->uses_frontend = false;
+ }
+ }
+
+ if (num_frontend_planes > SUN4I_BACKEND_NUM_FRONTEND_LAYERS) {
+ DRM_DEBUG_DRIVER("Too many planes going through the frontend, rejecting\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static int sun4i_backend_init_sat(struct device *dev) {
struct sun4i_backend *backend = dev_get_drvdata(dev);
int ret;
@@ -384,6 +448,7 @@ static struct sun4i_frontend *sun4i_backend_find_frontend(struct sun4i_drv *drv,
}
static const struct sunxi_engine_ops sun4i_backend_engine_ops = {
+ .atomic_check = sun4i_backend_atomic_check,
.commit = sun4i_backend_commit,
.layers_init = sun4i_layers_init,
.apply_color_correction = sun4i_backend_apply_color_correction,
diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.h b/drivers/gpu/drm/sun4i/sun4i_backend.h
index 636a51521e77..3b5531440fa3 100644
--- a/drivers/gpu/drm/sun4i/sun4i_backend.h
+++ b/drivers/gpu/drm/sun4i/sun4i_backend.h
@@ -144,6 +144,8 @@
#define SUN4I_BACKEND_HWCCOLORTAB_OFF 0x4c00
#define SUN4I_BACKEND_PIPE_OFF(p) (0x5000 + (0x400 * (p)))
+#define SUN4I_BACKEND_NUM_FRONTEND_LAYERS 1
+
struct sun4i_backend {
struct sunxi_engine engine;
struct sun4i_frontend *frontend;
--
git-series 0.9.1
^ permalink raw reply related
* [PATCH 6/8] drm/sun4i: sun4i_layer: Wire in the frontend
From: Maxime Ripard @ 2017-12-13 15:33 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <cover.63722fe4aeb908cf3c6f73874bdf69b193fe43c9.1513178989.git-series.maxime.ripard@free-electrons.com>
Now that we have a driver, we can make use of it. This is done by
adding a flag to our custom plane state that will trigger whether we should
use the frontend on that particular plane or not.
The rest is just plumbing to set up the backend to not perform the DMA but
receive its data from the frontend.
Note that we're still not making any use of the frontend itself, as no one
is setting the flag yet.
Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
drivers/gpu/drm/sun4i/sun4i_backend.c | 53 ++++++++++++++++++++++++++++-
drivers/gpu/drm/sun4i/sun4i_backend.h | 3 ++-
drivers/gpu/drm/sun4i/sun4i_layer.c | 27 ++++++++++++--
drivers/gpu/drm/sun4i/sun4i_layer.h | 1 +-
4 files changed, 81 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c
index e83e1fe43823..f1d19767c55d 100644
--- a/drivers/gpu/drm/sun4i/sun4i_backend.c
+++ b/drivers/gpu/drm/sun4i/sun4i_backend.c
@@ -26,6 +26,7 @@
#include "sun4i_backend.h"
#include "sun4i_drv.h"
+#include "sun4i_frontend.h"
#include "sun4i_layer.h"
#include "sunxi_engine.h"
@@ -203,6 +204,30 @@ int sun4i_backend_update_layer_formats(struct sun4i_backend *backend,
return 0;
}
+int sun4i_backend_update_layer_frontend(struct sun4i_backend *backend,
+ int layer, uint32_t fmt)
+{
+ u32 val;
+ int ret;
+
+ ret = sun4i_backend_drm_format_to_layer(NULL, fmt, &val);
+ if (ret) {
+ DRM_DEBUG_DRIVER("Invalid format\n");
+ return ret;
+ }
+
+ regmap_update_bits(backend->engine.regs,
+ SUN4I_BACKEND_ATTCTL_REG0(layer),
+ SUN4I_BACKEND_ATTCTL_REG0_LAY_VDOEN,
+ SUN4I_BACKEND_ATTCTL_REG0_LAY_VDOEN);
+
+ regmap_update_bits(backend->engine.regs,
+ SUN4I_BACKEND_ATTCTL_REG1(layer),
+ SUN4I_BACKEND_ATTCTL_REG1_LAY_FBFMT, val);
+
+ return 0;
+}
+
int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend,
int layer, struct drm_plane *plane)
{
@@ -330,6 +355,34 @@ static int sun4i_backend_of_get_id(struct device_node *node)
return ret;
}
+static struct sun4i_frontend *sun4i_backend_find_frontend(struct sun4i_drv *drv,
+ struct device_node *node)
+{
+ struct device_node *port, *ep, *remote;
+ struct sun4i_frontend *frontend;
+
+ port = of_graph_get_port_by_id(node, 0);
+ if (!port)
+ return ERR_PTR(-EINVAL);
+
+ for_each_available_child_of_node(port, ep) {
+ remote = of_graph_get_remote_port_parent(ep);
+ if (!remote)
+ continue;
+
+ /* does this node match any registered engines? */
+ list_for_each_entry(frontend, &drv->frontend_list, list) {
+ if (remote == frontend->node) {
+ of_node_put(remote);
+ of_node_put(port);
+ return frontend;
+ }
+ }
+ }
+
+ return ERR_PTR(-EINVAL);
+}
+
static const struct sunxi_engine_ops sun4i_backend_engine_ops = {
.commit = sun4i_backend_commit,
.layers_init = sun4i_layers_init,
diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.h b/drivers/gpu/drm/sun4i/sun4i_backend.h
index ba1410fd5410..636a51521e77 100644
--- a/drivers/gpu/drm/sun4i/sun4i_backend.h
+++ b/drivers/gpu/drm/sun4i/sun4i_backend.h
@@ -72,6 +72,7 @@
#define SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL(x) ((x) << 15)
#define SUN4I_BACKEND_ATTCTL_REG0_LAY_PRISEL_MASK GENMASK(11, 10)
#define SUN4I_BACKEND_ATTCTL_REG0_LAY_PRISEL(x) ((x) << 10)
+#define SUN4I_BACKEND_ATTCTL_REG0_LAY_VDOEN BIT(1)
#define SUN4I_BACKEND_ATTCTL_REG1(l) (0x8a0 + (0x4 * (l)))
#define SUN4I_BACKEND_ATTCTL_REG1_LAY_HSCAFCT GENMASK(15, 14)
@@ -171,5 +172,7 @@ int sun4i_backend_update_layer_formats(struct sun4i_backend *backend,
int layer, struct drm_plane *plane);
int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend,
int layer, struct drm_plane *plane);
+int sun4i_backend_update_layer_frontend(struct sun4i_backend *backend,
+ int layer, uint32_t in_fmt);
#endif /* _SUN4I_BACKEND_H_ */
diff --git a/drivers/gpu/drm/sun4i/sun4i_layer.c b/drivers/gpu/drm/sun4i/sun4i_layer.c
index c3afcf888906..3b58667a06dc 100644
--- a/drivers/gpu/drm/sun4i/sun4i_layer.c
+++ b/drivers/gpu/drm/sun4i/sun4i_layer.c
@@ -15,6 +15,7 @@
#include <drm/drmP.h>
#include "sun4i_backend.h"
+#include "sun4i_frontend.h"
#include "sun4i_layer.h"
#include "sunxi_engine.h"
@@ -70,21 +71,41 @@ static void sun4i_backend_layer_destroy_state(struct drm_plane *plane,
static void sun4i_backend_layer_atomic_disable(struct drm_plane *plane,
struct drm_plane_state *old_state)
{
+ struct sun4i_layer_state *layer_state = state_to_sun4i_layer_state(old_state);
struct sun4i_layer *layer = plane_to_sun4i_layer(plane);
struct sun4i_backend *backend = layer->backend;
+ struct sun4i_frontend *frontend = backend->frontend;
sun4i_backend_layer_enable(backend, layer->id, false);
+
+ if (layer_state->uses_frontend)
+ sun4i_frontend_exit(frontend);
}
static void sun4i_backend_layer_atomic_update(struct drm_plane *plane,
struct drm_plane_state *old_state)
{
+ struct sun4i_layer_state *layer_state = state_to_sun4i_layer_state(plane->state);
struct sun4i_layer *layer = plane_to_sun4i_layer(plane);
struct sun4i_backend *backend = layer->backend;
+ struct sun4i_frontend *frontend = backend->frontend;
+
+ if (layer_state->uses_frontend) {
+ sun4i_frontend_init(frontend);
+ sun4i_frontend_update_coord(frontend, plane);
+ sun4i_frontend_update_buffer(frontend, plane);
+ sun4i_frontend_update_formats(frontend, plane,
+ DRM_FORMAT_ARGB8888);
+ sun4i_backend_update_layer_frontend(backend, layer->id,
+ DRM_FORMAT_ARGB8888);
+ sun4i_backend_update_layer_coord(backend, layer->id, plane);
+ sun4i_frontend_enable(frontend);
+ } else {
+ sun4i_backend_update_layer_coord(backend, layer->id, plane);
+ sun4i_backend_update_layer_formats(backend, layer->id, plane);
+ sun4i_backend_update_layer_buffer(backend, layer->id, plane);
+ }
- sun4i_backend_update_layer_coord(backend, layer->id, plane);
- sun4i_backend_update_layer_formats(backend, layer->id, plane);
- sun4i_backend_update_layer_buffer(backend, layer->id, plane);
sun4i_backend_layer_enable(backend, layer->id, true);
}
diff --git a/drivers/gpu/drm/sun4i/sun4i_layer.h b/drivers/gpu/drm/sun4i/sun4i_layer.h
index d2c19348d1b0..75b4868ba87c 100644
--- a/drivers/gpu/drm/sun4i/sun4i_layer.h
+++ b/drivers/gpu/drm/sun4i/sun4i_layer.h
@@ -24,6 +24,7 @@ struct sun4i_layer {
struct sun4i_layer_state {
struct drm_plane_state state;
+ bool uses_frontend;
};
static inline struct sun4i_layer *
--
git-series 0.9.1
^ permalink raw reply related
* [PATCH 5/8] drm/sun4i: Add a driver for the display frontend
From: Maxime Ripard @ 2017-12-13 15:33 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <cover.63722fe4aeb908cf3c6f73874bdf69b193fe43c9.1513178989.git-series.maxime.ripard@free-electrons.com>
The display frontend is an hardware block that can be used to implement
some more advanced features like hardware scaling or colorspace
conversions. It can also be used to implement the output format of the VPU.
Let's create a minimal driver for it that will only enable the hardware
scaling features.
Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
drivers/gpu/drm/sun4i/Makefile | 3 +-
drivers/gpu/drm/sun4i/sun4i_backend.c | 5 +-
drivers/gpu/drm/sun4i/sun4i_backend.h | 1 +-
drivers/gpu/drm/sun4i/sun4i_drv.c | 16 +-
drivers/gpu/drm/sun4i/sun4i_drv.h | 1 +-
drivers/gpu/drm/sun4i/sun4i_frontend.c | 377 ++++++++++++++++++++++++++-
drivers/gpu/drm/sun4i/sun4i_frontend.h | 102 +++++++-
7 files changed, 500 insertions(+), 5 deletions(-)
create mode 100644 drivers/gpu/drm/sun4i/sun4i_frontend.c
create mode 100644 drivers/gpu/drm/sun4i/sun4i_frontend.h
diff --git a/drivers/gpu/drm/sun4i/Makefile b/drivers/gpu/drm/sun4i/Makefile
index 0c2f8c7facae..b660d82011f4 100644
--- a/drivers/gpu/drm/sun4i/Makefile
+++ b/drivers/gpu/drm/sun4i/Makefile
@@ -1,5 +1,6 @@
# SPDX-License-Identifier: GPL-2.0
sun4i-backend-y += sun4i_backend.o sun4i_layer.o
+sun4i-frontend-y += sun4i_frontend.o
sun4i-drm-y += sun4i_drv.o
sun4i-drm-y += sun4i_framebuffer.o
@@ -21,6 +22,6 @@ obj-$(CONFIG_DRM_SUN4I) += sun4i-tcon.o
obj-$(CONFIG_DRM_SUN4I) += sun4i_tv.o
obj-$(CONFIG_DRM_SUN4I) += sun6i_drc.o
-obj-$(CONFIG_DRM_SUN4I_BACKEND) += sun4i-backend.o
+obj-$(CONFIG_DRM_SUN4I_BACKEND) += sun4i-backend.o sun4i-frontend.o
obj-$(CONFIG_DRM_SUN4I_HDMI) += sun4i-drm-hdmi.o
obj-$(CONFIG_DRM_SUN8I_MIXER) += sun8i-mixer.o
diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c
index f971d3fb5ee4..e83e1fe43823 100644
--- a/drivers/gpu/drm/sun4i/sun4i_backend.c
+++ b/drivers/gpu/drm/sun4i/sun4i_backend.c
@@ -367,6 +367,11 @@ static int sun4i_backend_bind(struct device *dev, struct device *master,
if (backend->engine.id < 0)
return backend->engine.id;
+ backend->frontend = sun4i_backend_find_frontend(drv, dev->of_node);
+ if (IS_ERR(backend->frontend)) {
+ dev_err(dev, "Couldn't find matching frontend, frontend features disabled\n");
+ }
+
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
regs = devm_ioremap_resource(dev, res);
if (IS_ERR(regs))
diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.h b/drivers/gpu/drm/sun4i/sun4i_backend.h
index ac3cc029f5cd..ba1410fd5410 100644
--- a/drivers/gpu/drm/sun4i/sun4i_backend.h
+++ b/drivers/gpu/drm/sun4i/sun4i_backend.h
@@ -145,6 +145,7 @@
struct sun4i_backend {
struct sunxi_engine engine;
+ struct sun4i_frontend *frontend;
struct reset_control *reset;
diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.c b/drivers/gpu/drm/sun4i/sun4i_drv.c
index 75c76cdd82bc..17bf9bfd98ba 100644
--- a/drivers/gpu/drm/sun4i/sun4i_drv.c
+++ b/drivers/gpu/drm/sun4i/sun4i_drv.c
@@ -98,6 +98,7 @@ static int sun4i_drv_bind(struct device *dev)
goto free_drm;
}
drm->dev_private = drv;
+ INIT_LIST_HEAD(&drv->frontend_list);
INIT_LIST_HEAD(&drv->engine_list);
INIT_LIST_HEAD(&drv->tcon_list);
@@ -239,9 +240,11 @@ static int sun4i_drv_add_endpoints(struct device *dev,
int count = 0;
/*
- * We don't support the frontend for now, so we will never
- * have a device bound. Just skip over it, but we still want
- * the rest our pipeline to be added.
+ * The frontend has been disabled in all of our old device
+ * trees. If we find a node that is the frontend and is
+ * disabled, we should just follow through and parse its
+ * child, but without adding it to the component list.
+ * Otherwise, we obviously want to add it to the list.
*/
if (!sun4i_drv_node_is_frontend(node) &&
!of_device_is_available(node))
@@ -254,7 +257,12 @@ static int sun4i_drv_add_endpoints(struct device *dev,
if (sun4i_drv_node_is_connector(node))
return 0;
- if (!sun4i_drv_node_is_frontend(node)) {
+ /*
+ * If the device is either just a regular device, or an
+ * enabled frontend, we add it to our component list.
+ */
+ if (!sun4i_drv_node_is_frontend(node) ||
+ (sun4i_drv_node_is_frontend(node) && of_device_is_available(node))) {
/* Add current component */
DRM_DEBUG_DRIVER("Adding component %pOF\n", node);
drm_of_component_match_add(dev, match, compare_of, node);
diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.h b/drivers/gpu/drm/sun4i/sun4i_drv.h
index a960c89270cc..9c26a345f85c 100644
--- a/drivers/gpu/drm/sun4i/sun4i_drv.h
+++ b/drivers/gpu/drm/sun4i/sun4i_drv.h
@@ -19,6 +19,7 @@
struct sun4i_drv {
struct list_head engine_list;
+ struct list_head frontend_list;
struct list_head tcon_list;
struct drm_fbdev_cma *fbdev;
diff --git a/drivers/gpu/drm/sun4i/sun4i_frontend.c b/drivers/gpu/drm/sun4i/sun4i_frontend.c
new file mode 100644
index 000000000000..1be0e86d1457
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/sun4i_frontend.c
@@ -0,0 +1,377 @@
+/*
+ * Copyright (C) 2017 Free Electrons
+ *
+ * Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ */
+#include <drm/drmP.h>
+#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_fb_cma_helper.h>
+
+#include <linux/clk.h>
+#include <linux/component.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
+
+#include "sun4i_drv.h"
+#include "sun4i_frontend.h"
+
+static const u32 sun4i_frontend_vert_coef[32] = {
+ 0x00004000, 0x000140ff, 0x00033ffe, 0x00043ffd,
+ 0x00063efc, 0xff083dfc, 0x000a3bfb, 0xff0d39fb,
+ 0xff0f37fb, 0xff1136fa, 0xfe1433fb, 0xfe1631fb,
+ 0xfd192ffb, 0xfd1c2cfb, 0xfd1f29fb, 0xfc2127fc,
+ 0xfc2424fc, 0xfc2721fc, 0xfb291ffd, 0xfb2c1cfd,
+ 0xfb2f19fd, 0xfb3116fe, 0xfb3314fe, 0xfa3611ff,
+ 0xfb370fff, 0xfb390dff, 0xfb3b0a00, 0xfc3d08ff,
+ 0xfc3e0600, 0xfd3f0400, 0xfe3f0300, 0xff400100,
+};
+
+static const u32 sun4i_frontend_horz_coef[64] = {
+ 0x40000000, 0x00000000, 0x40fe0000, 0x0000ff03,
+ 0x3ffd0000, 0x0000ff05, 0x3ffc0000, 0x0000ff06,
+ 0x3efb0000, 0x0000ff08, 0x3dfb0000, 0x0000ff09,
+ 0x3bfa0000, 0x0000fe0d, 0x39fa0000, 0x0000fe0f,
+ 0x38fa0000, 0x0000fe10, 0x36fa0000, 0x0000fe12,
+ 0x33fa0000, 0x0000fd16, 0x31fa0000, 0x0000fd18,
+ 0x2ffa0000, 0x0000fd1a, 0x2cfa0000, 0x0000fc1e,
+ 0x29fa0000, 0x0000fc21, 0x27fb0000, 0x0000fb23,
+ 0x24fb0000, 0x0000fb26, 0x21fb0000, 0x0000fb29,
+ 0x1ffc0000, 0x0000fa2b, 0x1cfc0000, 0x0000fa2e,
+ 0x19fd0000, 0x0000fa30, 0x16fd0000, 0x0000fa33,
+ 0x14fd0000, 0x0000fa35, 0x11fe0000, 0x0000fa37,
+ 0x0ffe0000, 0x0000fa39, 0x0dfe0000, 0x0000fa3b,
+ 0x0afe0000, 0x0000fa3e, 0x08ff0000, 0x0000fb3e,
+ 0x06ff0000, 0x0000fb40, 0x05ff0000, 0x0000fc40,
+ 0x03ff0000, 0x0000fd41, 0x01ff0000, 0x0000fe42,
+};
+
+static void sun4i_frontend_scaler_init(struct sun4i_frontend *frontend)
+{
+ int i;
+
+ for (i = 0; i < 32; i++) {
+ regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_HORZCOEF0_REG(i),
+ sun4i_frontend_horz_coef[2 * i]);
+ regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_HORZCOEF0_REG(i),
+ sun4i_frontend_horz_coef[2 * i]);
+ regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_HORZCOEF1_REG(i),
+ sun4i_frontend_horz_coef[2 * i + 1]);
+ regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_HORZCOEF1_REG(i),
+ sun4i_frontend_horz_coef[2 * i + 1]);
+ regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_VERTCOEF_REG(i),
+ sun4i_frontend_vert_coef[i]);
+ regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_VERTCOEF_REG(i),
+ sun4i_frontend_vert_coef[i]);
+ }
+
+ regmap_update_bits(frontend->regs, SUN4I_FRONTEND_FRM_CTRL_REG, BIT(23), BIT(23));
+}
+
+int sun4i_frontend_init(struct sun4i_frontend *frontend)
+{
+ int ret;
+
+ if (atomic_read(&frontend->users))
+ return -EBUSY;
+
+ ret = reset_control_deassert(frontend->reset);
+ if (ret) {
+ DRM_DEBUG_DRIVER("Couldn't deassert our reset line\n");
+ return ret;
+ }
+
+ clk_set_rate(frontend->mod_clk, 300000000);
+
+ clk_prepare_enable(frontend->bus_clk);
+ clk_prepare_enable(frontend->mod_clk);
+ clk_prepare_enable(frontend->ram_clk);
+
+ regmap_update_bits(frontend->regs, SUN4I_FRONTEND_EN_REG,
+ SUN4I_FRONTEND_EN_EN,
+ SUN4I_FRONTEND_EN_EN);
+
+ regmap_update_bits(frontend->regs, SUN4I_FRONTEND_BYPASS_REG,
+ SUN4I_FRONTEND_BYPASS_CSC_EN,
+ SUN4I_FRONTEND_BYPASS_CSC_EN);
+
+ sun4i_frontend_scaler_init(frontend);
+
+ atomic_inc(&frontend->users);
+
+ return 0;
+}
+EXPORT_SYMBOL(sun4i_frontend_init);
+
+void sun4i_frontend_exit(struct sun4i_frontend *frontend)
+{
+ atomic_dec(&frontend->users);
+
+ clk_disable_unprepare(frontend->ram_clk);
+ clk_disable_unprepare(frontend->mod_clk);
+ clk_disable_unprepare(frontend->bus_clk);
+ reset_control_assert(frontend->reset);
+}
+EXPORT_SYMBOL(sun4i_frontend_exit);
+
+void sun4i_frontend_update_buffer(struct sun4i_frontend *frontend,
+ struct drm_plane *plane)
+{
+ struct drm_plane_state *state = plane->state;
+ struct drm_framebuffer *fb = state->fb;
+ struct drm_gem_cma_object *gem;
+ dma_addr_t paddr;
+ int bpp;
+
+ /* Get the physical address of the buffer in memory */
+ gem = drm_fb_cma_get_gem_obj(fb, 0);
+
+ DRM_DEBUG_DRIVER("Using GEM @ %pad\n", &gem->paddr);
+
+ /* Set the line width */
+ DRM_DEBUG_DRIVER("Frontend stride: %d bytes\n", fb->pitches[0]);
+ regmap_write(frontend->regs, SUN4I_FRONTEND_LINESTRD0_REG,
+ fb->pitches[0]);
+
+ /* Compute the start of the displayed memory */
+ bpp = fb->format->cpp[0];
+ paddr = gem->paddr + fb->offsets[0];
+ paddr += (state->src_x >> 16) * bpp;
+ paddr += (state->src_y >> 16) * fb->pitches[0];
+
+ DRM_DEBUG_DRIVER("Setting buffer address to %pad\n", &paddr);
+ regmap_write(frontend->regs, SUN4I_FRONTEND_BUF_ADDR0_REG, paddr);
+}
+
+static int sun4i_frontend_drm_format_to_input_fmt(uint32_t fmt, u32 *val)
+{
+ switch (fmt) {
+ case DRM_FORMAT_ARGB8888:
+ case DRM_FORMAT_XRGB8888:
+ *val = 3;
+ return 0;
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static int sun4i_frontend_drm_format_to_output_fmt(uint32_t fmt, u32 *val)
+{
+ switch (fmt) {
+ case DRM_FORMAT_ARGB8888:
+ *val = 2;
+ return 0;
+
+ default:
+ return -EINVAL;
+ }
+}
+
+int sun4i_frontend_update_formats(struct sun4i_frontend *frontend,
+ struct drm_plane *plane, uint32_t out_fmt)
+{
+ struct drm_plane_state *state = plane->state;
+ struct drm_framebuffer *fb = state->fb;
+ u32 out_fmt_val;
+ u32 in_fmt_val;
+ int ret;
+
+ ret = sun4i_frontend_drm_format_to_input_fmt(fb->format->format,
+ &in_fmt_val);
+ if (ret) {
+ DRM_DEBUG_DRIVER("Invalid input format\n");
+ return ret;
+ }
+
+ ret = sun4i_frontend_drm_format_to_output_fmt(out_fmt, &out_fmt_val);
+ if (ret) {
+ DRM_DEBUG_DRIVER("Invalid output format\n");
+ return ret;
+ }
+
+ regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_HORZPHASE_REG, 0x400);
+ regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_HORZPHASE_REG, 0x400);
+
+ regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_VERTPHASE0_REG, 0x400);
+ regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_VERTPHASE0_REG, 0x400);
+
+ regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_VERTPHASE1_REG, 0x400);
+ regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_VERTPHASE1_REG, 0x400);
+
+ regmap_write(frontend->regs, SUN4I_FRONTEND_INPUT_FMT_REG, 0x151);
+ /* SUN4I_FRONTEND_INPUT_FMT_DATA_MOD(1) | */
+ /* SUN4I_FRONTEND_INPUT_FMT_DATA_FMT(5) | */
+ /* SUN4I_FRONTEND_INPUT_FMT_PS(1)); */
+ regmap_write(frontend->regs, SUN4I_FRONTEND_OUTPUT_FMT_REG, 0x82);
+ /* SUN4I_FRONTEND_OUTPUT_FMT_DATA_FMT(1)); */
+
+ return 0;
+}
+
+void sun4i_frontend_update_coord(struct sun4i_frontend *frontend,
+ struct drm_plane *plane)
+{
+ struct drm_plane_state *state = plane->state;
+
+ /* Set height and width */
+ DRM_DEBUG_DRIVER("Frontend size W: %u H: %u\n",
+ state->crtc_w, state->crtc_h);
+ regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_INSIZE_REG,
+ SUN4I_FRONTEND_INSIZE(state->src_h >> 16,
+ state->src_w >> 16));
+ regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_INSIZE_REG,
+ SUN4I_FRONTEND_INSIZE(state->src_h >> 16,
+ state->src_w >> 16));
+
+ regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_OUTSIZE_REG,
+ SUN4I_FRONTEND_OUTSIZE(state->crtc_h, state->crtc_w));
+ regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_OUTSIZE_REG,
+ SUN4I_FRONTEND_OUTSIZE(state->crtc_h, state->crtc_w));
+
+ DRM_DEBUG_DRIVER("Frontend horizontal scaling factor %d.%d\n", 1, 0);
+ regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_HORZFACT_REG,
+ state->src_w / state->crtc_w);
+ regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_HORZFACT_REG,
+ state->src_w / state->crtc_w);
+
+ DRM_DEBUG_DRIVER("Frontend vertical scaling factor %d.%d\n", 1, 0);
+ regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_VERTFACT_REG,
+ state->src_h / state->crtc_h);
+ regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_VERTFACT_REG,
+ state->src_h / state->crtc_h);
+
+ regmap_write_bits(frontend->regs, SUN4I_FRONTEND_FRM_CTRL_REG,
+ SUN4I_FRONTEND_FRM_CTRL_REG_RDY,
+ SUN4I_FRONTEND_FRM_CTRL_REG_RDY);
+}
+EXPORT_SYMBOL(sun4i_frontend_update_coord);
+
+int sun4i_frontend_enable(struct sun4i_frontend *frontend)
+{
+ regmap_write_bits(frontend->regs, SUN4I_FRONTEND_FRM_CTRL_REG,
+ SUN4I_FRONTEND_FRM_CTRL_FRM_START,
+ SUN4I_FRONTEND_FRM_CTRL_FRM_START);
+
+ return 0;
+}
+EXPORT_SYMBOL(sun4i_frontend_enable);
+
+static struct regmap_config sun4i_frontend_regmap_config = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+ .max_register = 0x0a14,
+};
+
+static int sun4i_frontend_bind(struct device *dev, struct device *master,
+ void *data)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct sun4i_frontend *frontend;
+ struct drm_device *drm = data;
+ struct sun4i_drv *drv = drm->dev_private;
+ struct resource *res;
+ void __iomem *regs;
+
+ frontend = devm_kzalloc(dev, sizeof(*frontend), GFP_KERNEL);
+ if (!frontend)
+ return -ENOMEM;
+ dev_set_drvdata(dev, frontend);
+ frontend->node = dev->of_node;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ regs = devm_ioremap_resource(dev, res);
+ if (IS_ERR(regs))
+ return PTR_ERR(regs);
+
+ frontend->regs = devm_regmap_init_mmio(dev, regs,
+ &sun4i_frontend_regmap_config);
+ if (IS_ERR(frontend->regs)) {
+ dev_err(dev, "Couldn't create the frontend regmap\n");
+ return PTR_ERR(frontend->regs);
+ }
+
+ frontend->reset = devm_reset_control_get(dev, NULL);
+ if (IS_ERR(frontend->reset)) {
+ dev_err(dev, "Couldn't get our reset line\n");
+ return PTR_ERR(frontend->reset);
+ }
+
+ frontend->bus_clk = devm_clk_get(dev, "ahb");
+ if (IS_ERR(frontend->bus_clk)) {
+ dev_err(dev, "Couldn't get our bus clock\n");
+ return PTR_ERR(frontend->bus_clk);
+ }
+
+ frontend->mod_clk = devm_clk_get(dev, "mod");
+ if (IS_ERR(frontend->mod_clk)) {
+ dev_err(dev, "Couldn't get our mod clock\n");
+ return PTR_ERR(frontend->mod_clk);
+ }
+
+ frontend->ram_clk = devm_clk_get(dev, "ram");
+ if (IS_ERR(frontend->ram_clk)) {
+ dev_err(dev, "Couldn't get our ram clock\n");
+ return PTR_ERR(frontend->ram_clk);
+ }
+
+ list_add_tail(&frontend->list, &drv->frontend_list);
+
+ return 0;
+}
+
+static void sun4i_frontend_unbind(struct device *dev, struct device *master,
+ void *data)
+{
+ struct sun4i_frontend *frontend = dev_get_drvdata(dev);
+
+ clk_disable_unprepare(frontend->mod_clk);
+ clk_disable_unprepare(frontend->bus_clk);
+ reset_control_assert(frontend->reset);
+}
+
+static const struct component_ops sun4i_frontend_ops = {
+ .bind = sun4i_frontend_bind,
+ .unbind = sun4i_frontend_unbind,
+};
+
+static int sun4i_frontend_probe(struct platform_device *pdev)
+{
+ return component_add(&pdev->dev, &sun4i_frontend_ops);
+}
+
+static int sun4i_frontend_remove(struct platform_device *pdev)
+{
+ component_del(&pdev->dev, &sun4i_frontend_ops);
+
+ return 0;
+}
+
+static const struct of_device_id sun4i_frontend_of_table[] = {
+ { .compatible = "allwinner,sun5i-a13-display-frontend" },
+ { .compatible = "allwinner,sun6i-a31-display-frontend" },
+ { .compatible = "allwinner,sun8i-a33-display-frontend" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, sun4i_frontend_of_table);
+
+static struct platform_driver sun4i_frontend_driver = {
+ .probe = sun4i_frontend_probe,
+ .remove = sun4i_frontend_remove,
+ .driver = {
+ .name = "sun4i-frontend",
+ .of_match_table = sun4i_frontend_of_table,
+ },
+};
+module_platform_driver(sun4i_frontend_driver);
+
+MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
+MODULE_DESCRIPTION("Allwinner A10 Display Engine Frontend Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/sun4i/sun4i_frontend.h b/drivers/gpu/drm/sun4i/sun4i_frontend.h
new file mode 100644
index 000000000000..2df9f6de0f3f
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/sun4i_frontend.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2017 Free Electrons
+ *
+ * Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ */
+
+#ifndef _SUN4I_FRONTEND_H_
+#define _SUN4I_FRONTEND_H_
+
+#include <linux/atomic.h>
+#include <linux/list.h>
+
+#define SUN4I_FRONTEND_EN_REG 0x000
+#define SUN4I_FRONTEND_EN_EN BIT(0)
+
+#define SUN4I_FRONTEND_FRM_CTRL_REG 0x004
+#define SUN4I_FRONTEND_FRM_CTRL_FRM_START BIT(16)
+#define SUN4I_FRONTEND_FRM_CTRL_COEF_RDY BIT(1)
+#define SUN4I_FRONTEND_FRM_CTRL_REG_RDY BIT(0)
+
+#define SUN4I_FRONTEND_BYPASS_REG 0x008
+#define SUN4I_FRONTEND_BYPASS_CSC_EN BIT(1)
+
+#define SUN4I_FRONTEND_BUF_ADDR0_REG 0x020
+
+#define SUN4I_FRONTEND_LINESTRD0_REG 0x040
+
+#define SUN4I_FRONTEND_INPUT_FMT_REG 0x04c
+#define SUN4I_FRONTEND_INPUT_FMT_DATA_MOD(mod) ((mod) << 8)
+#define SUN4I_FRONTEND_INPUT_FMT_DATA_FMT(fmt) ((fmt) << 4)
+#define SUN4I_FRONTEND_INPUT_FMT_PS(ps) (ps)
+
+#define SUN4I_FRONTEND_OUTPUT_FMT_REG 0x05c
+#define SUN4I_FRONTEND_OUTPUT_FMT_DATA_FMT(fmt) (fmt)
+
+#define SUN4I_FRONTEND_CH0_INSIZE_REG 0x100
+#define SUN4I_FRONTEND_INSIZE(h, w) ((((h) - 1) << 16) | (((w) - 1)))
+
+#define SUN4I_FRONTEND_CH0_OUTSIZE_REG 0x104
+#define SUN4I_FRONTEND_OUTSIZE(h, w) ((((h) - 1) << 16) | (((w) - 1)))
+
+#define SUN4I_FRONTEND_CH0_HORZFACT_REG 0x108
+#define SUN4I_FRONTEND_HORZFACT(i, f) (((i) << 16) | (f))
+
+#define SUN4I_FRONTEND_CH0_VERTFACT_REG 0x10c
+#define SUN4I_FRONTEND_VERTFACT(i, f) (((i) << 16) | (f))
+
+#define SUN4I_FRONTEND_CH0_HORZPHASE_REG 0x110
+#define SUN4I_FRONTEND_CH0_VERTPHASE0_REG 0x114
+#define SUN4I_FRONTEND_CH0_VERTPHASE1_REG 0x118
+
+#define SUN4I_FRONTEND_CH1_INSIZE_REG 0x200
+#define SUN4I_FRONTEND_CH1_OUTSIZE_REG 0x204
+#define SUN4I_FRONTEND_CH1_HORZFACT_REG 0x208
+#define SUN4I_FRONTEND_CH1_VERTFACT_REG 0x20c
+
+#define SUN4I_FRONTEND_CH1_HORZPHASE_REG 0x210
+#define SUN4I_FRONTEND_CH1_VERTPHASE0_REG 0x214
+#define SUN4I_FRONTEND_CH1_VERTPHASE1_REG 0x218
+
+#define SUN4I_FRONTEND_CH0_HORZCOEF0_REG(i) (0x400 + i * 4)
+#define SUN4I_FRONTEND_CH0_HORZCOEF1_REG(i) (0x480 + i * 4)
+#define SUN4I_FRONTEND_CH0_VERTCOEF_REG(i) (0x500 + i * 4)
+#define SUN4I_FRONTEND_CH1_HORZCOEF0_REG(i) (0x600 + i * 4)
+#define SUN4I_FRONTEND_CH1_HORZCOEF1_REG(i) (0x680 + i * 4)
+#define SUN4I_FRONTEND_CH1_VERTCOEF_REG(i) (0x700 + i * 4)
+
+struct clk;
+struct device_node;
+struct drm_plane;
+struct regmap;
+struct reset_control;
+
+struct sun4i_frontend {
+ struct list_head list;
+ atomic_t users;
+ struct device_node *node;
+
+ struct clk *bus_clk;
+ struct clk *mod_clk;
+ struct clk *ram_clk;
+ struct regmap *regs;
+ struct reset_control *reset;
+};
+
+int sun4i_frontend_init(struct sun4i_frontend *frontend);
+void sun4i_frontend_exit(struct sun4i_frontend *frontend);
+int sun4i_frontend_enable(struct sun4i_frontend *frontend);
+
+void sun4i_frontend_update_buffer(struct sun4i_frontend *frontend,
+ struct drm_plane *plane);
+void sun4i_frontend_update_coord(struct sun4i_frontend *frontend,
+ struct drm_plane *plane);
+int sun4i_frontend_update_formats(struct sun4i_frontend *frontend,
+ struct drm_plane *plane, uint32_t out_fmt);
+
+#endif /* _SUN4I_FRONTEND_H_ */
--
git-series 0.9.1
^ permalink raw reply related
* [PATCH 4/8] drm/sun4i: crtc: Add a custom crtc atomic_check
From: Maxime Ripard @ 2017-12-13 15:33 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <cover.63722fe4aeb908cf3c6f73874bdf69b193fe43c9.1513178989.git-series.maxime.ripard@free-electrons.com>
We have some restrictions on what the planes and CRTC can provide that are
tied to only one generation of display engines.
For example, on the first generation, we can only have one YUV plane or one
plane that uses the frontend output.
Let's allow our engines to provide an atomic_check callback to validate the
current configuration.
Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
drivers/gpu/drm/sun4i/sun4i_crtc.c | 14 ++++++++++++++
drivers/gpu/drm/sun4i/sunxi_engine.h | 2 ++
2 files changed, 16 insertions(+)
diff --git a/drivers/gpu/drm/sun4i/sun4i_crtc.c b/drivers/gpu/drm/sun4i/sun4i_crtc.c
index 5decae0069d0..2a565325714f 100644
--- a/drivers/gpu/drm/sun4i/sun4i_crtc.c
+++ b/drivers/gpu/drm/sun4i/sun4i_crtc.c
@@ -46,6 +46,19 @@ static struct drm_encoder *sun4i_crtc_get_encoder(struct drm_crtc *crtc)
return NULL;
}
+static int sun4i_crtc_atomic_check(struct drm_crtc *crtc,
+ struct drm_crtc_state *state)
+{
+ struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc);
+ struct sunxi_engine *engine = scrtc->engine;
+ int ret = 0;
+
+ if (engine && engine->ops && engine->ops->atomic_check)
+ ret = engine->ops->atomic_check(engine, state);
+
+ return ret;
+}
+
static void sun4i_crtc_atomic_begin(struct drm_crtc *crtc,
struct drm_crtc_state *old_state)
{
@@ -125,6 +138,7 @@ static void sun4i_crtc_mode_set_nofb(struct drm_crtc *crtc)
}
static const struct drm_crtc_helper_funcs sun4i_crtc_helper_funcs = {
+ .atomic_check = sun4i_crtc_atomic_check,
.atomic_begin = sun4i_crtc_atomic_begin,
.atomic_flush = sun4i_crtc_atomic_flush,
.atomic_enable = sun4i_crtc_atomic_enable,
diff --git a/drivers/gpu/drm/sun4i/sunxi_engine.h b/drivers/gpu/drm/sun4i/sunxi_engine.h
index 4cb70ae65c79..42655230aeba 100644
--- a/drivers/gpu/drm/sun4i/sunxi_engine.h
+++ b/drivers/gpu/drm/sun4i/sunxi_engine.h
@@ -16,6 +16,8 @@ struct drm_device;
struct sunxi_engine;
struct sunxi_engine_ops {
+ int (*atomic_check)(struct sunxi_engine *engine,
+ struct drm_crtc_state *state);
void (*commit)(struct sunxi_engine *engine);
struct drm_plane **(*layers_init)(struct drm_device *drm,
struct sunxi_engine *engine);
--
git-series 0.9.1
^ permalink raw reply related
* [PATCH 3/8] drm/sun4i: sun4i_layer: Add a custom plane state
From: Maxime Ripard @ 2017-12-13 15:33 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <cover.63722fe4aeb908cf3c6f73874bdf69b193fe43c9.1513178989.git-series.maxime.ripard@free-electrons.com>
We will need to store some additional data in the future to the state.
Create a custom plane state that will embed those data, in order to store
the pipe or whether or not that plane should use the frontend.
Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
drivers/gpu/drm/sun4i/sun4i_layer.c | 48 ++++++++++++++++++++++++++++--
drivers/gpu/drm/sun4i/sun4i_layer.h | 10 ++++++-
2 files changed, 55 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/sun4i/sun4i_layer.c b/drivers/gpu/drm/sun4i/sun4i_layer.c
index 7bddf12548d3..c3afcf888906 100644
--- a/drivers/gpu/drm/sun4i/sun4i_layer.c
+++ b/drivers/gpu/drm/sun4i/sun4i_layer.c
@@ -25,6 +25,48 @@ struct sun4i_plane_desc {
uint32_t nformats;
};
+static void sun4i_backend_layer_reset(struct drm_plane *plane)
+{
+ struct sun4i_layer_state *state;
+
+ if (plane->state) {
+ state = state_to_sun4i_layer_state(plane->state);
+
+ __drm_atomic_helper_plane_destroy_state(&state->state);
+ kfree(state);
+ plane->state = NULL;
+ }
+
+ state = kzalloc(sizeof(*state), GFP_KERNEL);
+ if (state) {
+ plane->state = &state->state;
+ plane->state->plane = plane;
+ }
+}
+
+static struct drm_plane_state *
+sun4i_backend_layer_duplicate_state(struct drm_plane *plane)
+{
+ struct sun4i_layer_state *copy;
+
+ copy = kzalloc(sizeof(*copy), GFP_KERNEL);
+ if (!copy)
+ return NULL;
+
+ __drm_atomic_helper_plane_duplicate_state(plane, ©->state);
+
+ return ©->state;
+}
+
+static void sun4i_backend_layer_destroy_state(struct drm_plane *plane,
+ struct drm_plane_state *state)
+{
+ struct sun4i_layer_state *s_state = state_to_sun4i_layer_state(state);
+
+ __drm_atomic_helper_plane_destroy_state(state);
+ kfree(s_state);
+}
+
static void sun4i_backend_layer_atomic_disable(struct drm_plane *plane,
struct drm_plane_state *old_state)
{
@@ -52,11 +94,11 @@ static const struct drm_plane_helper_funcs sun4i_backend_layer_helper_funcs = {
};
static const struct drm_plane_funcs sun4i_backend_layer_funcs = {
- .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
- .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
+ .atomic_destroy_state = sun4i_backend_layer_destroy_state,
+ .atomic_duplicate_state = sun4i_backend_layer_duplicate_state,
.destroy = drm_plane_cleanup,
.disable_plane = drm_atomic_helper_disable_plane,
- .reset = drm_atomic_helper_plane_reset,
+ .reset = sun4i_backend_layer_reset,
.update_plane = drm_atomic_helper_update_plane,
};
diff --git a/drivers/gpu/drm/sun4i/sun4i_layer.h b/drivers/gpu/drm/sun4i/sun4i_layer.h
index 4e84f438b346..d2c19348d1b0 100644
--- a/drivers/gpu/drm/sun4i/sun4i_layer.h
+++ b/drivers/gpu/drm/sun4i/sun4i_layer.h
@@ -22,12 +22,22 @@ struct sun4i_layer {
int id;
};
+struct sun4i_layer_state {
+ struct drm_plane_state state;
+};
+
static inline struct sun4i_layer *
plane_to_sun4i_layer(struct drm_plane *plane)
{
return container_of(plane, struct sun4i_layer, plane);
}
+static inline struct sun4i_layer_state *
+state_to_sun4i_layer_state(struct drm_plane_state *state)
+{
+ return container_of(state, struct sun4i_layer_state, state);
+}
+
struct drm_plane **sun4i_layers_init(struct drm_device *drm,
struct sunxi_engine *engine);
--
git-series 0.9.1
^ permalink raw reply related
* [PATCH 2/8] drm/sun4i: backend: Allow a NULL plane pointer to retrieve the format
From: Maxime Ripard @ 2017-12-13 15:33 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <cover.63722fe4aeb908cf3c6f73874bdf69b193fe43c9.1513178989.git-series.maxime.ripard@free-electrons.com>
The function converting the DRM format to its equivalent in the backend
registers was assuming that we were having a plane.
However, we might want to use that function when setting up a plane using
the frontend, in which case we will not have a plane associated to the
backend's layer. Yet, we still need to setup the format to the one output
by the frontend.
Test for NULL plane pointers before referencing them, so that we can work
around it.
Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
drivers/gpu/drm/sun4i/sun4i_backend.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c
index c99d1a7e815a..f971d3fb5ee4 100644
--- a/drivers/gpu/drm/sun4i/sun4i_backend.c
+++ b/drivers/gpu/drm/sun4i/sun4i_backend.c
@@ -93,7 +93,7 @@ void sun4i_backend_layer_enable(struct sun4i_backend *backend,
static int sun4i_backend_drm_format_to_layer(struct drm_plane *plane,
u32 format, u32 *mode)
{
- if ((plane->type == DRM_PLANE_TYPE_PRIMARY) &&
+ if (plane && (plane->type == DRM_PLANE_TYPE_PRIMARY) &&
(format == DRM_FORMAT_ARGB8888))
format = DRM_FORMAT_XRGB8888;
--
git-series 0.9.1
^ permalink raw reply related
* [PATCH 1/8] drm/sun4i: backend: Move line stride setup to buffer setup function
From: Maxime Ripard @ 2017-12-13 15:33 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <cover.63722fe4aeb908cf3c6f73874bdf69b193fe43c9.1513178989.git-series.maxime.ripard@free-electrons.com>
Setup the line stride in the buffer setup function, since it's tied to the
buffer itself, and is not needed when we do not set the buffer in the
backend.
This is for example the case when using the frontend and then routing its
output to the backend.
Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
drivers/gpu/drm/sun4i/sun4i_backend.c | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c
index 847eecbe4d14..c99d1a7e815a 100644
--- a/drivers/gpu/drm/sun4i/sun4i_backend.c
+++ b/drivers/gpu/drm/sun4i/sun4i_backend.c
@@ -141,7 +141,6 @@ int sun4i_backend_update_layer_coord(struct sun4i_backend *backend,
int layer, struct drm_plane *plane)
{
struct drm_plane_state *state = plane->state;
- struct drm_framebuffer *fb = state->fb;
DRM_DEBUG_DRIVER("Updating layer %d\n", layer);
@@ -153,12 +152,6 @@ int sun4i_backend_update_layer_coord(struct sun4i_backend *backend,
state->crtc_h));
}
- /* Set the line width */
- DRM_DEBUG_DRIVER("Layer line width: %d bits\n", fb->pitches[0] * 8);
- regmap_write(backend->engine.regs,
- SUN4I_BACKEND_LAYLINEWIDTH_REG(layer),
- fb->pitches[0] * 8);
-
/* Set height and width */
DRM_DEBUG_DRIVER("Layer size W: %u H: %u\n",
state->crtc_w, state->crtc_h);
@@ -218,6 +211,13 @@ int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend,
u32 lo_paddr, hi_paddr;
dma_addr_t paddr;
+ /* Set the line width */
+ DRM_DEBUG_DRIVER("Layer line width: %d bits\n", fb->pitches[0] * 8);
+ regmap_write(backend->engine.regs,
+ SUN4I_BACKEND_LAYLINEWIDTH_REG(layer),
+ fb->pitches[0] * 8);
+
+
/* Get the start of the displayed memory */
paddr = drm_fb_cma_get_gem_addr(fb, state, 0);
DRM_DEBUG_DRIVER("Setting buffer address to %pad\n", &paddr);
--
git-series 0.9.1
^ permalink raw reply related
* [PATCH 0/8] drm/sun4i: Support the Display Engine frontend
From: Maxime Ripard @ 2017-12-13 15:33 UTC (permalink / raw)
To: linux-arm-kernel
Hi,
This is a first serie to enable the display engine frontend.
This hardware block is found in the first generation Display Engine from
Allwinner. Its role is to implement more advanced features that the
associated backend, even though the backend alone can be used (and was used
so far) for basic composition.
Among those features, we will find hardware scaling, that is supported in
this serie, colorspace conversions, or more exotic formats support such as
the one output by the VPU.
Let me know what you think,
Maxime
Maxime Ripard (8):
drm/sun4i: backend: Move line stride setup to buffer setup function
drm/sun4i: backend: Allow a NULL plane pointer to retrieve the format
drm/sun4i: sun4i_layer: Add a custom plane state
drm/sun4i: crtc: Add a custom crtc atomic_check
drm/sun4i: Add a driver for the display frontend
drm/sun4i: sun4i_layer: Wire in the frontend
drm/sun4i: sun4i_layer: Add a custom atomic_check for the frontend
ARM: dts: sun8i: a33 Enable our display frontend
arch/arm/boot/dts/sun8i-a33.dtsi | 1 +-
drivers/gpu/drm/sun4i/Makefile | 3 +-
drivers/gpu/drm/sun4i/sun4i_backend.c | 139 +++++++++-
drivers/gpu/drm/sun4i/sun4i_backend.h | 6 +-
drivers/gpu/drm/sun4i/sun4i_crtc.c | 14 +-
drivers/gpu/drm/sun4i/sun4i_drv.c | 16 +-
drivers/gpu/drm/sun4i/sun4i_drv.h | 1 +-
drivers/gpu/drm/sun4i/sun4i_frontend.c | 377 ++++++++++++++++++++++++++-
drivers/gpu/drm/sun4i/sun4i_frontend.h | 102 +++++++-
drivers/gpu/drm/sun4i/sun4i_layer.c | 75 ++++-
drivers/gpu/drm/sun4i/sun4i_layer.h | 11 +-
drivers/gpu/drm/sun4i/sunxi_engine.h | 2 +-
12 files changed, 727 insertions(+), 20 deletions(-)
create mode 100644 drivers/gpu/drm/sun4i/sun4i_frontend.c
create mode 100644 drivers/gpu/drm/sun4i/sun4i_frontend.h
base-commit: 4fbd8d194f06c8a3fd2af1ce560ddb31f7ec8323
--
git-series 0.9.1
^ permalink raw reply
* [xlnx:2017.3_video_ea 6599/6607] drivers/staging/xilinx/hdmi/phy-xilinx-vphy/xhdcp1x_rx.c:896:22: warning: ') - ' directive output may be truncated writing 4 bytes into a region of size between 3 and 7
From: kbuild test robot @ 2017-12-13 15:22 UTC (permalink / raw)
To: linux-arm-kernel
tree: https://github.com/Xilinx/linux-xlnx 2017.3_video_ea
head: af045f9682c65a0c26afb2f638603d3c01079222
commit: 15c99dce11944aa6657cade4fb30d978d002e783 [6599/6607] staging: xilinx: hdmirx: Fix hdcp authentication problem on key load
config: blackfin-allmodconfig (attached as .config)
compiler: bfin-uclinux-gcc (GCC) 7.2.0
reproduce:
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
git checkout 15c99dce11944aa6657cade4fb30d978d002e783
# save the attached .config to linux build tree
make.cross ARCH=blackfin
All warnings (new ones prefixed by >>):
drivers/staging/xilinx/hdmi/phy-xilinx-vphy/xhdcp1x_rx.c: In function 'XHdcp1x_RxDebugLog.isra.6':
>> drivers/staging/xilinx/hdmi/phy-xilinx-vphy/xhdcp1x_rx.c:896:22: warning: ') - ' directive output may be truncated writing 4 bytes into a region of size between 3 and 7 [-Wformat-truncation=]
snprintf(Label, 16, "hdcp-rx(%d) - ", InstancePtr->Config.DeviceId);
^~~~~~~~~~~~~~~~
drivers/staging/xilinx/hdmi/phy-xilinx-vphy/xhdcp1x_rx.c:896:2: note: 'snprintf' output between 14 and 18 bytes into a destination of size 16
snprintf(Label, 16, "hdcp-rx(%d) - ", InstancePtr->Config.DeviceId);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
vim +896 drivers/staging/xilinx/hdmi/phy-xilinx-vphy/xhdcp1x_rx.c
73634d89 Rohit Consul 2017-10-31 878
73634d89 Rohit Consul 2017-10-31 879 /*****************************************************************************/
73634d89 Rohit Consul 2017-10-31 880 /**
73634d89 Rohit Consul 2017-10-31 881 * This function logs a debug message on behalf of a handler state machine.
73634d89 Rohit Consul 2017-10-31 882 *
73634d89 Rohit Consul 2017-10-31 883 * @param InstancePtr is the receiver instance.
73634d89 Rohit Consul 2017-10-31 884 * @param LogMsg is the message to log.
73634d89 Rohit Consul 2017-10-31 885 *
73634d89 Rohit Consul 2017-10-31 886 * @return None.
73634d89 Rohit Consul 2017-10-31 887 *
73634d89 Rohit Consul 2017-10-31 888 * @note None.
73634d89 Rohit Consul 2017-10-31 889 *
73634d89 Rohit Consul 2017-10-31 890 ******************************************************************************/
73634d89 Rohit Consul 2017-10-31 891 static void XHdcp1x_RxDebugLog(const XHdcp1x *InstancePtr, const char *LogMsg)
73634d89 Rohit Consul 2017-10-31 892 {
73634d89 Rohit Consul 2017-10-31 893 char Label[16];
73634d89 Rohit Consul 2017-10-31 894
73634d89 Rohit Consul 2017-10-31 895 /* Format Label */
73634d89 Rohit Consul 2017-10-31 @896 snprintf(Label, 16, "hdcp-rx(%d) - ", InstancePtr->Config.DeviceId);
73634d89 Rohit Consul 2017-10-31 897
73634d89 Rohit Consul 2017-10-31 898 /* Log it */
73634d89 Rohit Consul 2017-10-31 899 XHDCP1X_DEBUG_LOGMSG(Label);
73634d89 Rohit Consul 2017-10-31 900 XHDCP1X_DEBUG_LOGMSG(LogMsg);
15c99dce Rohit Consul 2017-11-14 901 XHDCP1X_DEBUG_LOGMSG("\n");
73634d89 Rohit Consul 2017-10-31 902 }
73634d89 Rohit Consul 2017-10-31 903
:::::: The code at line 896 was first introduced by commit
:::::: 73634d891211ef92c9d8c789a1ccc002118164ba phy: xilinx-vphy: Initial release of xilinx video phy soft IP driver
:::::: TO: Rohit Consul <rohit.consul@xilinx.com>
:::::: CC: Jeffrey Mouroux <jmouroux@xilinx.com>
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
-------------- next part --------------
A non-text attachment was scrubbed...
Name: .config.gz
Type: application/gzip
Size: 42262 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20171213/1acd4476/attachment-0001.gz>
^ permalink raw reply
* [PATCH 4/4] [v4] pinctrl: qcom: qdf2xxx: add support for new ACPI HID QCOM8002
From: Timur Tabi @ 2017-12-13 15:18 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <9c28bebb-5f57-83e8-9885-5262bbdc1b94@codeaurora.org>
On 12/13/2017 08:46 AM, Timur Tabi wrote:
>
>> Please, read my comment again. The key part of the phrase:
>> "Use members of struct device_driver"
>>
>> So, do not move the IDs. There are examples in the kernel how to access
>> it.
>
> Sorry, I don't understand what you're talking about.? I don't see how I
> can call
>
> ????const struct acpi_device_id *id =
> ??????? acpi_match_device(qdf2xxx_acpi_ids, &pdev->dev);
>
> without having qdf2xxx_acpi_ids already defined previously.? And without
> the 'id', I can't figure out whether I've probed via QCOM8001 or QCOM8002.
I think I found it. Are you talking about doing this instead:
id = acpi_match_device(pdev->dev.driver->acpi_match_table, &pdev->dev);
--
Qualcomm Datacenter Technologies, Inc. as an affiliate of Qualcomm
Technologies, Inc. Qualcomm Technologies, Inc. is a member of the
Code Aurora Forum, a Linux Foundation Collaborative Project.
^ permalink raw reply
* [PATCH] arm64: dts: hisilicon: Add hi3660 cpu capacity-dmips-mhz information
From: Valentin Schneider @ 2017-12-13 15:16 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20171213145311.GA30463@leoy-ThinkPad-T440>
Hi Leo,
On 12/13/2017 02:53 PM, Leo Yan wrote:
> Hi Valentin,
>
> On Wed, Dec 13, 2017 at 02:21:06PM +0000, Valentin Schneider wrote:
>> The following dt entries are added:
>> cpus [0-3] (Cortex A53):
>> - capacity-dmips-mhz = <592>;
>>
>> cpus [4-7] (Cortex A73):
>> - capacity-dmips-mhz = <1024>;
>>
>> Those values were obtained by running dhrystone 2.1 on a
>> HiKey960 with the following procedure:
>> - Offline all CPUs but CPU0 (A53)
>> - Set CPU0 frequency to maximum
>> - Run Dhrystone 2.1 for 20 seconds
>>
>> - Offline all CPUs but CPU4 (A73)
>> - set CPU4 frequency to maximum
>> - Run Dhrystone 2.1 for 20 seconds
>>
>> The results are as follows:
>> A53: 129633887 loops
>> A73: 287034147 loops
> Seems to me the capacity-dmips-mhz should be:
>
> CA53: 129633887 / 20 / 1844 = 3515
> CA73: 287034147 / 20 / 2362 = 6076
>
> After normalized to range [0..1024], we could get:
>
> CA53: 592
> CA73: 1024
Yes, that's the "direct approach". I wanted to underline the fact that
there are two different max frequencies so what I followed would be:
1) Computing the performance ratio:
(129633887 / 287034147) * 1024 = 462.47
2) Scaling that to the same frequency scale:
462.47 * (2362/1844) = 592.38
Which gives the same end result (it's the same equation but split in two
steps). Also it makes it easy to check that the cpu_capacity sysfs entry
for the A53s gets correctly set (to 462).
>
> Reviewed-by: Leo Yan <leo.yan@linaro.org>
>
>> By scaling those values so that the A73s use 1024, we end up with 462
>> for the A53s. However, they have different maximum frequencies:
>> 1.844GHz for A53s and 2.362GHz for A73s. Thus, we can scale the A53
>> value to truly represent dmips per MHz, and we end up with 592.
>>
>> The impact of this change can be verified on HiKey960:
>>
>> $ cat /sys/devices/system/cpu/cpu*/cpufreq/scaling_cur_freq
>> 1844000
>> 1844000
>> 1844000
>> 1844000
>> 2362000
>> 2362000
>> 2362000
>> 2362000
>>
>> $ cat /sys/devices/system/cpu/cpu*/cpu_capacity
>> 462
>> 462
>> 462
>> 462
>> 1024
>> 1024
>> 1024
>> 1024
>>
>> Signed-off-by: Valentin Schneider <valentin.schneider@arm.com>
>> ---
>> arch/arm64/boot/dts/hisilicon/hi3660.dtsi | 8 ++++++++
>> 1 file changed, 8 insertions(+)
>>
>> diff --git a/arch/arm64/boot/dts/hisilicon/hi3660.dtsi b/arch/arm64/boot/dts/hisilicon/hi3660.dtsi
>> index ab0b95b..04a8d28 100644
>> --- a/arch/arm64/boot/dts/hisilicon/hi3660.dtsi
>> +++ b/arch/arm64/boot/dts/hisilicon/hi3660.dtsi
>> @@ -61,6 +61,7 @@
>> enable-method = "psci";
>> next-level-cache = <&A53_L2>;
>> cpu-idle-states = <&CPU_SLEEP &CLUSTER_SLEEP_0>;
>> + capacity-dmips-mhz = <592>;
>> };
>>
>> cpu1: cpu at 1 {
>> @@ -70,6 +71,7 @@
>> enable-method = "psci";
>> next-level-cache = <&A53_L2>;
>> cpu-idle-states = <&CPU_SLEEP &CLUSTER_SLEEP_0>;
>> + capacity-dmips-mhz = <592>;
>> };
>>
>> cpu2: cpu at 2 {
>> @@ -79,6 +81,7 @@
>> enable-method = "psci";
>> next-level-cache = <&A53_L2>;
>> cpu-idle-states = <&CPU_SLEEP &CLUSTER_SLEEP_0>;
>> + capacity-dmips-mhz = <592>;
>> };
>>
>> cpu3: cpu at 3 {
>> @@ -88,6 +91,7 @@
>> enable-method = "psci";
>> next-level-cache = <&A53_L2>;
>> cpu-idle-states = <&CPU_SLEEP &CLUSTER_SLEEP_0>;
>> + capacity-dmips-mhz = <592>;
>> };
>>
>> cpu4: cpu at 100 {
>> @@ -101,6 +105,7 @@
>> &CPU_SLEEP
>> &CLUSTER_SLEEP_1
>> >;
>> + capacity-dmips-mhz = <1024>;
>> };
>>
>> cpu5: cpu at 101 {
>> @@ -114,6 +119,7 @@
>> &CPU_SLEEP
>> &CLUSTER_SLEEP_1
>> >;
>> + capacity-dmips-mhz = <1024>;
>> };
>>
>> cpu6: cpu at 102 {
>> @@ -127,6 +133,7 @@
>> &CPU_SLEEP
>> &CLUSTER_SLEEP_1
>> >;
>> + capacity-dmips-mhz = <1024>;
>> };
>>
>> cpu7: cpu at 103 {
>> @@ -140,6 +147,7 @@
>> &CPU_SLEEP
>> &CLUSTER_SLEEP_1
>> >;
>> + capacity-dmips-mhz = <1024>;
>> };
>>
>> idle-states {
>> --
>> 2.7.4
>>
^ permalink raw reply
* [PATCH] arm64: dts: hisilicon: Add hi3660 cpu capacity-dmips-mhz information
From: Leo Yan @ 2017-12-13 14:53 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1513174866-6678-1-git-send-email-valentin.schneider@arm.com>
Hi Valentin,
On Wed, Dec 13, 2017 at 02:21:06PM +0000, Valentin Schneider wrote:
> The following dt entries are added:
> cpus [0-3] (Cortex A53):
> - capacity-dmips-mhz = <592>;
>
> cpus [4-7] (Cortex A73):
> - capacity-dmips-mhz = <1024>;
>
> Those values were obtained by running dhrystone 2.1 on a
> HiKey960 with the following procedure:
> - Offline all CPUs but CPU0 (A53)
> - Set CPU0 frequency to maximum
> - Run Dhrystone 2.1 for 20 seconds
>
> - Offline all CPUs but CPU4 (A73)
> - set CPU4 frequency to maximum
> - Run Dhrystone 2.1 for 20 seconds
>
> The results are as follows:
> A53: 129633887 loops
> A73: 287034147 loops
Seems to me the capacity-dmips-mhz should be:
CA53: 129633887 / 20 / 1844 = 3515
CA73: 287034147 / 20 / 2362 = 6076
After normalized to range [0..1024], we could get:
CA53: 592
CA73: 1024
Reviewed-by: Leo Yan <leo.yan@linaro.org>
> By scaling those values so that the A73s use 1024, we end up with 462
> for the A53s. However, they have different maximum frequencies:
> 1.844GHz for A53s and 2.362GHz for A73s. Thus, we can scale the A53
> value to truly represent dmips per MHz, and we end up with 592.
>
> The impact of this change can be verified on HiKey960:
>
> $ cat /sys/devices/system/cpu/cpu*/cpufreq/scaling_cur_freq
> 1844000
> 1844000
> 1844000
> 1844000
> 2362000
> 2362000
> 2362000
> 2362000
>
> $ cat /sys/devices/system/cpu/cpu*/cpu_capacity
> 462
> 462
> 462
> 462
> 1024
> 1024
> 1024
> 1024
>
> Signed-off-by: Valentin Schneider <valentin.schneider@arm.com>
> ---
> arch/arm64/boot/dts/hisilicon/hi3660.dtsi | 8 ++++++++
> 1 file changed, 8 insertions(+)
>
> diff --git a/arch/arm64/boot/dts/hisilicon/hi3660.dtsi b/arch/arm64/boot/dts/hisilicon/hi3660.dtsi
> index ab0b95b..04a8d28 100644
> --- a/arch/arm64/boot/dts/hisilicon/hi3660.dtsi
> +++ b/arch/arm64/boot/dts/hisilicon/hi3660.dtsi
> @@ -61,6 +61,7 @@
> enable-method = "psci";
> next-level-cache = <&A53_L2>;
> cpu-idle-states = <&CPU_SLEEP &CLUSTER_SLEEP_0>;
> + capacity-dmips-mhz = <592>;
> };
>
> cpu1: cpu at 1 {
> @@ -70,6 +71,7 @@
> enable-method = "psci";
> next-level-cache = <&A53_L2>;
> cpu-idle-states = <&CPU_SLEEP &CLUSTER_SLEEP_0>;
> + capacity-dmips-mhz = <592>;
> };
>
> cpu2: cpu at 2 {
> @@ -79,6 +81,7 @@
> enable-method = "psci";
> next-level-cache = <&A53_L2>;
> cpu-idle-states = <&CPU_SLEEP &CLUSTER_SLEEP_0>;
> + capacity-dmips-mhz = <592>;
> };
>
> cpu3: cpu at 3 {
> @@ -88,6 +91,7 @@
> enable-method = "psci";
> next-level-cache = <&A53_L2>;
> cpu-idle-states = <&CPU_SLEEP &CLUSTER_SLEEP_0>;
> + capacity-dmips-mhz = <592>;
> };
>
> cpu4: cpu at 100 {
> @@ -101,6 +105,7 @@
> &CPU_SLEEP
> &CLUSTER_SLEEP_1
> >;
> + capacity-dmips-mhz = <1024>;
> };
>
> cpu5: cpu at 101 {
> @@ -114,6 +119,7 @@
> &CPU_SLEEP
> &CLUSTER_SLEEP_1
> >;
> + capacity-dmips-mhz = <1024>;
> };
>
> cpu6: cpu at 102 {
> @@ -127,6 +133,7 @@
> &CPU_SLEEP
> &CLUSTER_SLEEP_1
> >;
> + capacity-dmips-mhz = <1024>;
> };
>
> cpu7: cpu at 103 {
> @@ -140,6 +147,7 @@
> &CPU_SLEEP
> &CLUSTER_SLEEP_1
> >;
> + capacity-dmips-mhz = <1024>;
> };
>
> idle-states {
> --
> 2.7.4
>
^ permalink raw reply
* [PATCH 4/4] [v4] pinctrl: qcom: qdf2xxx: add support for new ACPI HID QCOM8002
From: Timur Tabi @ 2017-12-13 14:47 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1513175798.7000.15.camel@linux.intel.com>
On 12/13/2017 08:36 AM, Andy Shevchenko wrote:
> Wait, runtime muxing is a matter of requesting another function (usually
> GPIO) and putting it back afterwards. Do you really need anything like
> this at*runtime*?
No, there is no runtime muxing on ACPI platforms.
--
Qualcomm Datacenter Technologies, Inc. as an affiliate of Qualcomm
Technologies, Inc. Qualcomm Technologies, Inc. is a member of the
Code Aurora Forum, a Linux Foundation Collaborative Project.
^ permalink raw reply
* [PATCH v4 4/4] ARM: pinctrl: sunxi-pinctrl: fix pin funtion can not be match correctly.
From: hao_zhang @ 2017-12-13 14:47 UTC (permalink / raw)
To: linux-arm-kernel
Pin function can not be match correctly when SUNXI_PIN describe with
mutiple variant and same function.
such as:
on pinctrl-sun4i-a10.c
SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 2),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION_VARIANT(0x2, "pwm", /* PWM0 */
PINCTRL_SUN4I_A10 |
PINCTRL_SUN7I_A20),
SUNXI_FUNCTION_VARIANT(0x3, "pwm", /* PWM0 */
PINCTRL_SUN8I_R40)),
it would always match to the first variant function
(PINCTRL_SUN4I_A10, PINCTRL_SUN7I_A20)
so we should add variant compare on it.
Signed-off-by: hao_zhang <hao5781286@gmail.com>
---
drivers/pinctrl/sunxi/pinctrl-sunxi.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
index 4b6cb25..f23e74e 100644
--- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c
+++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
@@ -83,9 +83,11 @@ sunxi_pinctrl_desc_find_function_by_name(struct sunxi_pinctrl *pctl,
struct sunxi_desc_function *func = pin->functions;
while (func->name) {
- if (!strcmp(func->name, func_name))
+ if (!strcmp(func->name, func_name)) {
+ if (!(func->variant) ||
+ (func->variant & pctl->variant))
return func;
-
+ }
func++;
}
}
--
2.7.4
^ permalink raw reply related
* [PATCH 4/4] [v4] pinctrl: qcom: qdf2xxx: add support for new ACPI HID QCOM8002
From: Timur Tabi @ 2017-12-13 14:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1513175535.7000.10.camel@linux.intel.com>
On 12/13/2017 08:32 AM, Andy Shevchenko wrote:
> Please, read my comment again. The key part of the phrase:
> "Use members of struct device_driver"
>
> So, do not move the IDs. There are examples in the kernel how to access
> it.
Sorry, I don't understand what you're talking about. I don't see how I
can call
const struct acpi_device_id *id =
acpi_match_device(qdf2xxx_acpi_ids, &pdev->dev);
without having qdf2xxx_acpi_ids already defined previously. And without
the 'id', I can't figure out whether I've probed via QCOM8001 or QCOM8002.
--
Qualcomm Datacenter Technologies, Inc. as an affiliate of Qualcomm
Technologies, Inc. Qualcomm Technologies, Inc. is a member of the
Code Aurora Forum, a Linux Foundation Collaborative Project.
^ permalink raw reply
* [PATCH v4 3/4] ARM: dts: add pwm node for r40.
From: hao_zhang @ 2017-12-13 14:46 UTC (permalink / raw)
To: linux-arm-kernel
This patch add pwm node for r40.
Signed-off-by: hao_zhang <hao5781286@gmail.com>
---
arch/arm/boot/dts/sun8i-r40-bananapi-m2-ultra.dts | 6 ++++++
arch/arm/boot/dts/sun8i-r40.dtsi | 13 +++++++++++++
2 files changed, 19 insertions(+)
diff --git a/arch/arm/boot/dts/sun8i-r40-bananapi-m2-ultra.dts b/arch/arm/boot/dts/sun8i-r40-bananapi-m2-ultra.dts
index 8c5efe2..6cf6273 100644
--- a/arch/arm/boot/dts/sun8i-r40-bananapi-m2-ultra.dts
+++ b/arch/arm/boot/dts/sun8i-r40-bananapi-m2-ultra.dts
@@ -196,6 +196,12 @@
status = "okay";
};
+&pwm {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pwm_pins>;
+ status = "okay";
+};
+
&uart0 {
pinctrl-names = "default";
pinctrl-0 = <&uart0_pb_pins>;
diff --git a/arch/arm/boot/dts/sun8i-r40.dtsi b/arch/arm/boot/dts/sun8i-r40.dtsi
index 173dcc1..6628b17 100644
--- a/arch/arm/boot/dts/sun8i-r40.dtsi
+++ b/arch/arm/boot/dts/sun8i-r40.dtsi
@@ -295,6 +295,11 @@
bias-pull-up;
};
+ pwm_pins: pwm0-pin {
+ pins = "PB2", "PB3";
+ function = "pwm";
+ };
+
uart0_pb_pins: uart0-pb-pins {
pins = "PB22", "PB23";
function = "uart0";
@@ -306,6 +311,14 @@
reg = <0x01c20c90 0x10>;
};
+ pwm: pwm at 1c23400 {
+ compatible = "allwinner,sun8i-r40-pwm";
+ reg = <0x01c23400 0x154>;
+ clocks = <&osc24M>;
+ #pwm-cells = <3>;
+ status = "disabled";
+ };
+
uart0: serial at 1c28000 {
compatible = "snps,dw-apb-uart";
reg = <0x01c28000 0x400>;
--
2.7.4
^ permalink raw reply related
* [PATCH v4 2/4] ARM: PWM: add allwinner sun8i R40/V40/T3 pwm support.
From: hao_zhang @ 2017-12-13 14:44 UTC (permalink / raw)
To: linux-arm-kernel
This patch add allwinner sun8i R40/V40/T3 pwm support.
Signed-off-by: hao_zhang <hao5781286@gmail.com>
---
drivers/pwm/Kconfig | 10 +
drivers/pwm/Makefile | 1 +
drivers/pwm/pwm-sun8i-r40.c | 449 ++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 460 insertions(+)
create mode 100644 drivers/pwm/pwm-sun8i-r40.c
diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
index 763ee50..cde5a70 100644
--- a/drivers/pwm/Kconfig
+++ b/drivers/pwm/Kconfig
@@ -444,6 +444,16 @@ config PWM_SUN4I
To compile this driver as a module, choose M here: the module
will be called pwm-sun4i.
+config PWM_SUN8I_R40
+ tristate "Allwinner PWM SUN8I R40 support"
+ depends on ARCH_SUNXI || COMPILE_TEST
+ depends on HAS_IOMEM && COMMON_CLK
+ help
+ Generic PWM framework driver for Allwinner SoCs R40, V40, T3.
+
+ To compile this driver as a module, choose M here: the module
+ will be called pwm-sun8i-r40.
+
config PWM_TEGRA
tristate "NVIDIA Tegra PWM support"
depends on ARCH_TEGRA
diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
index 0258a74..026a55b 100644
--- a/drivers/pwm/Makefile
+++ b/drivers/pwm/Makefile
@@ -44,6 +44,7 @@ obj-$(CONFIG_PWM_STM32) += pwm-stm32.o
obj-$(CONFIG_PWM_STM32_LP) += pwm-stm32-lp.o
obj-$(CONFIG_PWM_STMPE) += pwm-stmpe.o
obj-$(CONFIG_PWM_SUN4I) += pwm-sun4i.o
+obj-$(CONFIG_PWM_SUN8I_R40) += pwm-sun8i-r40.o
obj-$(CONFIG_PWM_TEGRA) += pwm-tegra.o
obj-$(CONFIG_PWM_TIECAP) += pwm-tiecap.o
obj-$(CONFIG_PWM_TIEHRPWM) += pwm-tiehrpwm.o
diff --git a/drivers/pwm/pwm-sun8i-r40.c b/drivers/pwm/pwm-sun8i-r40.c
new file mode 100644
index 0000000..8df538d
--- /dev/null
+++ b/drivers/pwm/pwm-sun8i-r40.c
@@ -0,0 +1,449 @@
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/jiffies.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pwm.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/time.h>
+
+#define PWM_IRQ_ENABLE_REG 0x0000
+#define PCIE(ch) BIT(ch)
+
+#define PWM_IRQ_STATUS_REG 0x0004
+#define PIS(ch) BIT(ch)
+
+#define CAPTURE_IRQ_ENABLE_REG 0x0010
+#define CFIE(ch) BIT(ch << 1 + 1)
+#define CRIE(ch) BIT(ch << 1)
+
+#define CAPTURE_IRQ_STATUS_REG 0x0014
+#define CFIS(ch) BIT(ch << 1 + 1)
+#define CRIS(ch) BIT(ch << 1)
+
+#define CLK_CFG_REG(ch) (0x0020 + (ch >> 1) * 4)
+#define CLK_SRC BIT(7)
+#define CLK_SRC_BYPASS_SEC BIT(6)
+#define CLK_SRC_BYPASS_FIR BIT(5)
+#define CLK_GATING BIT(4)
+#define CLK_DIV_M GENMASK(3, 0)
+
+#define PWM_DZ_CTR_REG(ch) (0x0030 + (ch >> 1) * 4)
+#define PWM_DZ_INTV GENMASK(15, 8)
+#define PWM_DZ_EN BIT(0)
+
+#define PWM_ENABLE_REG 0x0040
+#define PWM_EN(ch) BIT(ch)
+
+#define CAPTURE_ENABLE_REG 0x0044
+#define CAP_EN(ch) BIT(ch)
+
+#define PWM_CTR_REG(ch) (0x0060 + ch * 0x20)
+#define PWM_PERIOD_RDY BIT(11)
+#define PWM_PUL_START BIT(10)
+#define PWM_MODE BIT(9)
+#define PWM_ACT_STA BIT(8)
+#define PWM_PRESCAL_K GENMASK(7, 0)
+
+#define PWM_PERIOD_REG(ch) (0x0064 + ch * 0x20)
+#define PWM_ENTIRE_CYCLE GENMASK(31, 16)
+#define PWM_ACT_CYCLE GENMASK(15, 0)
+
+#define PWM_CNT_REG(ch) (0x0068 + ch * 0x20)
+#define PWM_CNT_VAL GENMASK(15, 0)
+
+#define CAPTURE_CTR_REG(ch) (0x006c + ch * 0x20)
+#define CAPTURE_CRLF BIT(2)
+#define CAPTURE_CFLF BIT(1)
+#define CAPINV BIT(0)
+
+#define CAPTURE_RISE_REG(ch) (0x0070 + ch * 0x20)
+#define CAPTURE_CRLR GENMASK(15, 0)
+
+#define CAPTURE_FALL_REG(ch) (0x0074 + ch * 0x20)
+#define CAPTURE_CFLR GENMASK(15, 0)
+
+struct sunxi_pwm_data {
+ bool has_prescaler_bypass;
+ bool has_rdy;
+ unsigned int npwm;
+};
+
+struct sunxi_pwm_chip {
+ struct pwm_chip chip;
+ struct clk *clk;
+ void __iomem *base;
+ spinlock_t ctrl_lock;
+ const struct sunxi_pwm_data *data;
+};
+
+static const u16 div_m_table[] = {
+ 1,
+ 2,
+ 4,
+ 8,
+ 16,
+ 32,
+ 64,
+ 128,
+ 256
+};
+
+static inline struct sunxi_pwm_chip *to_sunxi_pwm_chip(struct pwm_chip *chip)
+{
+ return container_of(chip, struct sunxi_pwm_chip, chip);
+}
+
+static inline u32 sunxi_pwm_readl(struct sunxi_pwm_chip *chip,
+ unsigned long offset)
+{
+ return readl(chip->base + offset);
+}
+
+static inline void sunxi_pwm_writel(struct sunxi_pwm_chip *chip,
+ u32 val, unsigned long offset)
+{
+ writel(val, chip->base + offset);
+}
+
+static void sunxi_pwm_set_bit(struct sunxi_pwm_chip *sunxi_pwm,
+ unsigned long reg, u32 bit)
+{
+ u32 val;
+
+ val = sunxi_pwm_readl(sunxi_pwm, reg);
+ val |= bit;
+ sunxi_pwm_writel(sunxi_pwm, val, reg);
+}
+
+static void sunxi_pwm_clear_bit(struct sunxi_pwm_chip *sunxi_pwm,
+ unsigned long reg, u32 bit)
+{
+ u32 val;
+
+ val = sunxi_pwm_readl(sunxi_pwm, reg);
+ val &= ~bit;
+ sunxi_pwm_writel(sunxi_pwm, val, reg);
+}
+
+static void sunxi_pwm_set_value(struct sunxi_pwm_chip *sunxi_pwm,
+ unsigned long reg, u32 mask, u32 val)
+{
+ u32 tmp;
+
+ tmp = sunxi_pwm_readl(sunxi_pwm, reg);
+ tmp &= ~mask;
+ tmp |= mask & val;
+ sunxi_pwm_writel(sunxi_pwm, tmp, reg);
+}
+
+static void sunxi_pwm_set_polarity(struct sunxi_pwm_chip *chip, u32 ch,
+ enum pwm_polarity polarity)
+{
+ if (polarity == PWM_POLARITY_NORMAL)
+ sunxi_pwm_set_bit(chip, PWM_CTR_REG(ch), PWM_ACT_STA);
+ else
+ sunxi_pwm_clear_bit(chip, PWM_CTR_REG(ch), PWM_ACT_STA);
+}
+
+static void sunxi_dump_reg(struct sunxi_pwm_chip *sunxi_pwm, u8 ch)
+{
+ dev_dbg(sunxi_pwm->chip.dev, "ch: %d\n"
+ "\tPWM_IRQ_ENABLE_REG(%04x): \t0x%08x\n"
+ "\tPWM_IRQ_STATUS_REG(%04x): \t0x%08x\n"
+ "\tCAPTURE_IRQ_ENABLE_REG(%04x): \t0x%08x\n"
+ "\tCAPTURE_IRQ_STATUS_REG(%04x): \t0x%08x\n"
+ "\tCLK_CFG_REG(%04x)(%d): \t0x%08x\n"
+ "\tPWM_DZ_CTR_REG(%04x)(%d): \t0x%08x\n"
+ "\tPWM_ENABLE_REG(%04x): \t0x%08x\n"
+ "\tCAPTURE_ENABLE_REG(%04x): \t0x%08x\n"
+ "\tPWM_CTR_REG(%04x)(%d): \t0x%08x\n"
+ "\tPWM_PERIOD_REG(%04x)(%d): \t0x%08x\n"
+ "\tPWM_CNT_REG(%04x)(%d): \t0x%08x\n"
+ "\tCAPTURE_CTR_REG(%04x)(%d): \t0x%08x\n"
+ "\tCAPTURE_RISE_REG(%04x)(%d): \t0x%08x\n"
+ "\tCAPTURE_FALL_REG(%04x)(%d): \t0x%08x\n",
+ ch,
+ PWM_IRQ_ENABLE_REG,
+ readl(sunxi_pwm->base + PWM_IRQ_ENABLE_REG),
+ PWM_IRQ_STATUS_REG,
+ readl(sunxi_pwm->base + PWM_IRQ_STATUS_REG),
+ CAPTURE_IRQ_ENABLE_REG,
+ readl(sunxi_pwm->base + CAPTURE_IRQ_ENABLE_REG),
+ CAPTURE_IRQ_STATUS_REG,
+ readl(sunxi_pwm->base + CAPTURE_IRQ_STATUS_REG),
+ CLK_CFG_REG(ch),
+ ch, readl(sunxi_pwm->base + CLK_CFG_REG(ch)),
+ PWM_DZ_CTR_REG(ch),
+ ch, readl(sunxi_pwm->base + PWM_DZ_CTR_REG(ch)),
+ PWM_ENABLE_REG,
+ readl(sunxi_pwm->base + PWM_ENABLE_REG),
+ CAPTURE_ENABLE_REG,
+ readl(sunxi_pwm->base + CAPTURE_ENABLE_REG),
+ PWM_CTR_REG(ch),
+ ch, readl(sunxi_pwm->base + PWM_CTR_REG(ch)),
+ PWM_PERIOD_REG(ch),
+ ch, readl(sunxi_pwm->base + PWM_PERIOD_REG(ch)),
+ PWM_CNT_REG(ch),
+ ch, readl(sunxi_pwm->base + PWM_CNT_REG(ch)),
+ CAPTURE_CTR_REG(ch),
+ ch, readl(sunxi_pwm->base + CAPTURE_CTR_REG(ch)),
+ CAPTURE_RISE_REG(ch),
+ ch, readl(sunxi_pwm->base + CAPTURE_RISE_REG(ch)),
+ CAPTURE_FALL_REG(ch),
+ ch, readl(sunxi_pwm->base + CAPTURE_FALL_REG(ch)));
+}
+
+static int sunxi_pwm_config(struct sunxi_pwm_chip *sunxi_pwm, u8 ch,
+ struct pwm_state *state)
+{
+ u64 clk_rate, clk_div, val;
+ u16 prescaler = 0;
+ u8 id = 0;
+
+ clk_rate = clk_get_rate(sunxi_pwm->clk);
+ dev_dbg(sunxi_pwm->chip.dev, "clock rate:%lld\n", clk_rate);
+
+ if (clk_rate == 24000000)
+ sunxi_pwm_clear_bit(sunxi_pwm, CLK_CFG_REG(ch), CLK_SRC);
+ else
+ sunxi_pwm_set_bit(sunxi_pwm, CLK_CFG_REG(ch), CLK_SRC);
+
+ if (sunxi_pwm->data->has_prescaler_bypass) {
+ /* pwm output bypass */
+ if (ch % 2)
+ sunxi_pwm_set_bit(sunxi_pwm, CLK_CFG_REG(ch),
+ CLK_SRC_BYPASS_FIR);
+ else
+ sunxi_pwm_set_bit(sunxi_pwm, CLK_CFG_REG(ch),
+ CLK_SRC_BYPASS_SEC);
+ return 0;
+ }
+
+ val = state->period * clk_rate;
+ do_div(val, NSEC_PER_SEC);
+ if (val < 1) {
+ dev_err(sunxi_pwm->chip.dev,
+ "period expects a larger value\n");
+ return -EINVAL;
+ }
+
+ /* calculate and set prescalar, div table, pwn entrie cycle */
+ clk_div = val;
+
+ while (clk_div > 65535) {
+ prescaler++;
+ clk_div = val;
+ do_div(clk_div, prescaler + 1);
+ do_div(clk_div, div_m_table[id]);
+
+ if (prescaler == 255) {
+ prescaler = 0;
+ id++;
+ if (id == 9)
+ return -EINVAL;
+ }
+ }
+
+ sunxi_pwm_set_value(sunxi_pwm, PWM_PERIOD_REG(ch),
+ PWM_ENTIRE_CYCLE, clk_div << 16);
+ sunxi_pwm_set_value(sunxi_pwm, PWM_CTR_REG(ch),
+ PWM_PRESCAL_K, prescaler << 0);
+ sunxi_pwm_set_value(sunxi_pwm, CLK_CFG_REG(ch),
+ CLK_DIV_M, id << 0);
+
+ /* set duty cycle */
+ val = (prescaler + 1) * div_m_table[id] * clk_div;
+ val = state->period;
+ do_div(val, clk_div);
+ clk_div = state->duty_cycle;
+ do_div(clk_div, val);
+
+ sunxi_pwm_set_value(sunxi_pwm, PWM_PERIOD_REG(ch),
+ PWM_ACT_CYCLE, clk_div << 0);
+
+ return 0;
+}
+
+static int sunxi_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
+ struct pwm_state *state)
+{
+ int ret;
+ struct sunxi_pwm_chip *sunxi_pwm = to_sunxi_pwm_chip(chip);
+ struct pwm_state cstate;
+
+ sunxi_dump_reg(sunxi_pwm, pwm->hwpwm);
+ pwm_get_state(pwm, &cstate);
+ if (!cstate.enabled) {
+ ret = clk_prepare_enable(sunxi_pwm->clk);
+ if (ret) {
+ dev_err(chip->dev, "failed to enable PWM clock\n");
+ return ret;
+ }
+ }
+
+ spin_lock(&sunxi_pwm->ctrl_lock);
+
+ if (state->polarity != cstate.polarity)
+ sunxi_pwm_set_polarity(sunxi_pwm, pwm->hwpwm, state->polarity);
+
+ if ((cstate.period != state->period) ||
+ (cstate.duty_cycle != state->duty_cycle)) {
+ ret = sunxi_pwm_config(sunxi_pwm, pwm->hwpwm, state);
+ if (ret) {
+ dev_err(chip->dev, "failed to enable PWM clock\n");
+ return ret;
+ }
+ }
+
+ if (state->enabled) {
+ sunxi_pwm_set_bit(sunxi_pwm,
+ CLK_CFG_REG(pwm->hwpwm), CLK_GATING);
+
+ sunxi_pwm_set_bit(sunxi_pwm,
+ PWM_ENABLE_REG, PWM_EN(pwm->hwpwm));
+ } else {
+ sunxi_pwm_clear_bit(sunxi_pwm,
+ CLK_CFG_REG(pwm->hwpwm), CLK_GATING);
+
+ sunxi_pwm_clear_bit(sunxi_pwm,
+ PWM_ENABLE_REG, PWM_EN(pwm->hwpwm));
+ }
+
+ spin_unlock(&sunxi_pwm->ctrl_lock);
+ sunxi_dump_reg(sunxi_pwm, pwm->hwpwm);
+
+ return 0;
+}
+
+static void sunxi_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
+ struct pwm_state *state)
+{
+ struct sunxi_pwm_chip *sunxi_pwm = to_sunxi_pwm_chip(chip);
+ u64 clk_rate, tmp;
+ u32 val;
+ u16 clk_div, act_cycle;
+ u8 prescal, id;
+
+ clk_rate = clk_get_rate(sunxi_pwm->clk);
+
+ val = sunxi_pwm_readl(sunxi_pwm, PWM_CTR_REG(pwm->hwpwm));
+ if (PWM_ACT_STA & val)
+ state->polarity = PWM_POLARITY_NORMAL;
+ else
+ state->polarity = PWM_POLARITY_INVERSED;
+
+ prescal = PWM_PRESCAL_K & val;
+
+ val = sunxi_pwm_readl(sunxi_pwm, PWM_ENABLE_REG);
+ if (PWM_EN(pwm->hwpwm) & val)
+ state->enabled = true;
+ else
+ state->enabled = false;
+
+ val = sunxi_pwm_readl(sunxi_pwm, PWM_PERIOD_REG(pwm->hwpwm));
+ act_cycle = PWM_ACT_CYCLE & val;
+ clk_div = val >> 16;
+
+ val = sunxi_pwm_readl(sunxi_pwm, CLK_CFG_REG(pwm->hwpwm));
+ id = CLK_DIV_M & val;
+
+ tmp = act_cycle * prescal * div_m_table[id] * NSEC_PER_SEC;
+ state->duty_cycle = DIV_ROUND_CLOSEST_ULL(tmp, clk_rate);
+ tmp = clk_div * prescal * div_m_table[id] * NSEC_PER_SEC;
+ state->period = DIV_ROUND_CLOSEST_ULL(tmp, clk_rate);
+}
+
+static const struct pwm_ops sunxi_pwm_ops = {
+ .apply = sunxi_pwm_apply,
+ .get_state = sunxi_pwm_get_state,
+ .owner = THIS_MODULE,
+};
+
+static const struct sunxi_pwm_data sunxi_pwm_data_r40 = {
+ .has_prescaler_bypass = false,
+ .has_rdy = true,
+ .npwm = 8,
+};
+
+static const struct of_device_id sunxi_pwm_dt_ids[] = {
+ {
+ .compatible = "allwinner,sun8i-r40-pwm",
+ .data = &sunxi_pwm_data_r40,
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, sunxi_pwm_dt_ids);
+
+static int sunxi_pwm_probe(struct platform_device *pdev)
+{
+ struct sunxi_pwm_chip *pwm;
+ struct resource *res;
+ int ret;
+ const struct of_device_id *match;
+
+ match = of_match_device(sunxi_pwm_dt_ids, &pdev->dev);
+
+ pwm = devm_kzalloc(&pdev->dev, sizeof(*pwm), GFP_KERNEL);
+ if (!pwm)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ pwm->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(pwm->base))
+ return PTR_ERR(pwm->base);
+
+ pwm->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(pwm->clk))
+ return PTR_ERR(pwm->clk);
+
+ pwm->data = match->data;
+ pwm->chip.dev = &pdev->dev;
+ pwm->chip.ops = &sunxi_pwm_ops;
+ pwm->chip.base = -1;
+ pwm->chip.npwm = pwm->data->npwm;
+ pwm->chip.of_xlate = of_pwm_xlate_with_flags;
+ pwm->chip.of_pwm_n_cells = 3;
+
+ dev_dbg(pwm->chip.dev, "npwm: %d\n", pwm->chip.npwm);
+
+ spin_lock_init(&pwm->ctrl_lock);
+
+ ret = pwmchip_add(&pwm->chip);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to add PWM chip: %d\n", ret);
+ return ret;
+ }
+
+ platform_set_drvdata(pdev, pwm);
+
+ return 0;
+}
+
+static int sunxi_pwm_remove(struct platform_device *pdev)
+{
+ struct sunxi_pwm_chip *pwm = platform_get_drvdata(pdev);
+
+ return pwmchip_remove(&pwm->chip);
+}
+
+static struct platform_driver sunxi_pwm_driver = {
+ .driver = {
+ .name = "sun8i-r40-pwm",
+ .of_match_table = sunxi_pwm_dt_ids,
+ },
+ .probe = sunxi_pwm_probe,
+ .remove = sunxi_pwm_remove,
+};
+module_platform_driver(sunxi_pwm_driver);
+
+MODULE_ALIAS("platform:sun8i-r40-pwm");
+MODULE_AUTHOR("Hao Zhang <hao5781286@gmail.com>");
+MODULE_DESCRIPTION("Allwinner sun8i-r40 PWM driver");
+MODULE_LICENSE("GPL v2");
--
2.7.4
^ permalink raw reply related
* [PATCH v4 1/4] dt-bindings: pwm: binding allwinner sun8i R40/V40/T3.
From: hao_zhang @ 2017-12-13 14:43 UTC (permalink / raw)
To: linux-arm-kernel
This patch adds allwinner R40, V40, T3 pwm binding documents.
Signed-off-by: hao_zhang <hao5781286@gmail.com>
---
Documentation/devicetree/bindings/pwm/pwm-sun8i.txt | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
create mode 100644 Documentation/devicetree/bindings/pwm/pwm-sun8i.txt
diff --git a/Documentation/devicetree/bindings/pwm/pwm-sun8i.txt b/Documentation/devicetree/bindings/pwm/pwm-sun8i.txt
new file mode 100644
index 0000000..76750d8
--- /dev/null
+++ b/Documentation/devicetree/bindings/pwm/pwm-sun8i.txt
@@ -0,0 +1,18 @@
+Allwinner sun8i R40/V40/T3 SoC PWM controller
+
+Required properties:
+- compatible: should be one of:
+- "allwinner,sun8i-r40-pwm"
+- reg: physical base address and length of the controller's registers
+- #pwm-cells: should be 3. See pwm.txt in this directory for a description of
+the cells format.
+- clocks: From common clock binding, handle to the parent clock.
+
+Example:
+
+pwm: pwm at 1c23400 {
+ compatible = "allwinner,sun8i-r40-pwm";
+ reg = <0x01c23400 0x154>;
+ clocks = <&osc24M>;
+ #pwm-cells = <3>;
+};
--
2.7.4
^ permalink raw reply related
* [PATCH 3/3] [v5] pinctrl: qcom: qdf2xxx: add support for new ACPI HID QCOM8002
From: Andy Shevchenko @ 2017-12-13 14:43 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1513111858-6251-4-git-send-email-timur@codeaurora.org>
On Tue, 2017-12-12 at 14:50 -0600, Timur Tabi wrote:
> Newer versions of the firmware for the Qualcomm Datacenter
> Technologies
> QDF2400 restricts access to a subset of the GPIOs on the TLMM. To
> prevent older kernels from accidentally accessing the restricted
> GPIOs,
> we change the ACPI HID for the TLMM block from QCOM8001 to QCOM8002,
> and introduce a new property "gpios". This property is an array of
> specific GPIOs that are accessible. When an older kernel boots on
> newer (restricted) firmware, it will fail to probe.
>
> To implement the sparse GPIO map, we register all of the GPIOs, but
> set
> the pin count for the unavailable GPIOs to zero. The pinctrl-msm
> driver will block those unavailable GPIOs from being accessed.
>
> To allow newer kernels to support older firmware, the driver retains
> support for QCOM8001.
Please, read my comments to v8, same applies here.
--
Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Intel Finland Oy
^ permalink raw reply
* [PATCH 2/3] [v8] pinctrl: qcom: disable GPIO groups with no pins
From: Andy Shevchenko @ 2017-12-13 14:42 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1513111858-6251-3-git-send-email-timur@codeaurora.org>
On Tue, 2017-12-12 at 14:50 -0600, Timur Tabi wrote:
> pinctrl-msm only accepts an array of GPIOs from 0 to n-1, and it
> expects
> each group to support have only one pin (npins == 1).
>
> We can support "sparse" GPIO maps if we allow for some groups to have
> zero
> pins (npins == 0). These pins are "hidden" from the rest of the
> driver
> and gpiolib.
>
> Access to unavailable GPIOs is blocked via a request callback. If the
> requested GPIO is unavailable, -EACCES is returned, which prevents
> further access to that GPIO.
We recently have some interesting BIOS/Windows driver design which makes
a need of something similar. Mika did patched pinctrl-intel for that. I
dunno that approach can be used here, or your proposal be utilized in
pinctrl-intel. Mika, any comments?
See some nitpicks below.
>
> seq_printf(s, " %-8s: %-3s %d", g->name, is_out ? "out" :
> "in", func);
> seq_printf(s, " %dmA", msm_regval_to_drive(drive));
> - seq_printf(s, " %s", pulls[pull]);
> + seq_printf(s, " %s\n", pulls[pull]);
I would rather do
seq_putc(s, '\n');
which makes code slightly more flexible for maintenance and reading.
> }
>
> static void msm_gpio_dbg_show(struct seq_file *s, struct gpio_chip
> *chip)
> @@ -524,23 +529,36 @@ static void msm_gpio_dbg_show(struct seq_file
> *s, struct gpio_chip *chip)
> unsigned gpio = chip->base;
> unsigned i;
>
> - for (i = 0; i < chip->ngpio; i++, gpio++) {
> + for (i = 0; i < chip->ngpio; i++, gpio++)
> msm_gpio_dbg_show_one(s, NULL, chip, i, gpio);
> - seq_puts(s, "\n");
> - }
This kind of change looks like a candidate to a separate patch,
though I mentioned it's just a nit.
--
Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Intel Finland Oy
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox