* Re: [PATCH v4 7/7] firmware: smccc: Add ARCH_SOC_ID support
From: Arnd Bergmann @ 2020-05-20 21:51 UTC (permalink / raw)
To: Sudeep Holla
Cc: Mark Rutland, Lorenzo Pieralisi, Catalin Marinas,
linux-kernel@vger.kernel.org, Steven Price, harb, Will Deacon,
Linux ARM
In-Reply-To: <20200518115546.GB16262@bogus>
On Mon, May 18, 2020 at 1:55 PM Sudeep Holla <sudeep.holla@arm.com> wrote:
>
> On Mon, May 18, 2020 at 11:30:21AM +0200, Arnd Bergmann wrote:
> > On Mon, May 18, 2020 at 11:12 AM Sudeep Holla <sudeep.holla@arm.com> wrote:
> >
> > > +static ssize_t
> > > +jep106_cont_bank_code_show(struct device *dev, struct device_attribute *attr,
> > > + char *buf)
> > > +{
> > > + return sprintf(buf, "0x%02x\n", JEP106_BANK_CONT_CODE(soc_id_version));
> > > +}
> > > +
> > > +static DEVICE_ATTR_RO(jep106_cont_bank_code);
> > > +
> > > +static ssize_t
> > > +jep106_identification_code_show(struct device *dev,
> > > + struct device_attribute *attr, char *buf)
> > > +{
> > > + return sprintf(buf, "0x%02x\n", JEP106_ID_CODE(soc_id_version));
> > > +}
> >
> > I think we should try hard to avoid nonstandard attributes for the soc device.
> >
>
> I agree with that in general but this is bit different for below mentioned
> reason.
>
> > Did you run into a problem with finding one of the existing attributes
> > that can be used to hold the fields?
> >
>
> Not really! The 2 JEP106 codes can be used to derive the manufacturer which
> could match one of the existing attributes. However doing so might require
> importing the huge JEP106 list as it needs to be maintained and updated
> in the kernel. Also that approach will have the compatibility issue and
> that is the reason for introducing these attributes representing raw
> values for userspace.
I was thinking they codes could just be part of the normal strings rather
than get translated. Can you give an example what they would look like
with your current code?
If you think they should be standard attributes, how about adding them
to the default list, and hardcoding them in the other soc device drivers
based on the information we have available there?
Arnd
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH] media: cedrus: Add support for VP8 decoding
From: Nicolas Dufresne @ 2020-05-20 21:43 UTC (permalink / raw)
To: Jernej Skrabec, mripard, paul.kocialkowski
Cc: devel, gregkh, linux-kernel, wens, hverkuil-cisco, mchehab,
linux-arm-kernel, linux-media
In-Reply-To: <20200520210129.132816-1-jernej.skrabec@siol.net>
Le mercredi 20 mai 2020 à 23:01 +0200, Jernej Skrabec a écrit :
> VP8 in Cedrus shares same engine as H264.
>
> Note that it seems necessary to call bitstream parsing functions,
> to parse frame header, otherwise decoded image is garbage. This is
> contrary to what is driver supposed to do. However, values are not
> really used, so this might be acceptable. It's possible that bitstream
Have you verified that all values passed through controls are not used
? To remain a stateless driver, there is no requirement for parsed data
to be used, the only requirement is that the reference are used.
Otherwise doing parallel decoding of two stream of different stream
would be broken. Have you verified that parallel decoding is working as
expected ?
> parsing functions set some internal VPU state, which is later necessary
> for proper decoding. Biggest suspect is "VP8 probs update" trigger.
>
> Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
> ---
> drivers/staging/media/sunxi/cedrus/Makefile | 3 +-
> drivers/staging/media/sunxi/cedrus/cedrus.c | 8 +
> drivers/staging/media/sunxi/cedrus/cedrus.h | 15 +
> .../staging/media/sunxi/cedrus/cedrus_dec.c | 5 +
> .../staging/media/sunxi/cedrus/cedrus_hw.c | 1 +
> .../staging/media/sunxi/cedrus/cedrus_regs.h | 80 ++
> .../staging/media/sunxi/cedrus/cedrus_video.c | 9 +
> .../staging/media/sunxi/cedrus/cedrus_vp8.c | 699 ++++++++++++++++++
> 8 files changed, 819 insertions(+), 1 deletion(-)
> create mode 100644 drivers/staging/media/sunxi/cedrus/cedrus_vp8.c
>
> diff --git a/drivers/staging/media/sunxi/cedrus/Makefile b/drivers/staging/media/sunxi/cedrus/Makefile
> index 1bce49d3e7e2..a647b3690bf8 100644
> --- a/drivers/staging/media/sunxi/cedrus/Makefile
> +++ b/drivers/staging/media/sunxi/cedrus/Makefile
> @@ -2,4 +2,5 @@
> obj-$(CONFIG_VIDEO_SUNXI_CEDRUS) += sunxi-cedrus.o
>
> sunxi-cedrus-y = cedrus.o cedrus_video.o cedrus_hw.o cedrus_dec.o \
> - cedrus_mpeg2.o cedrus_h264.o cedrus_h265.o
> + cedrus_mpeg2.o cedrus_h264.o cedrus_h265.o \
> + cedrus_vp8.o
> diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.c b/drivers/staging/media/sunxi/cedrus/cedrus.c
> index b320aa058f74..e6b864f05364 100644
> --- a/drivers/staging/media/sunxi/cedrus/cedrus.c
> +++ b/drivers/staging/media/sunxi/cedrus/cedrus.c
> @@ -142,6 +142,13 @@ static const struct cedrus_control cedrus_controls[] = {
> .codec = CEDRUS_CODEC_H265,
> .required = false,
> },
> + {
> + .cfg = {
> + .id = V4L2_CID_MPEG_VIDEO_VP8_FRAME_HEADER,
> + },
> + .codec = CEDRUS_CODEC_VP8,
> + .required = true,
> + },
> };
>
> #define CEDRUS_CONTROLS_COUNT ARRAY_SIZE(cedrus_controls)
> @@ -388,6 +395,7 @@ static int cedrus_probe(struct platform_device *pdev)
> dev->dec_ops[CEDRUS_CODEC_MPEG2] = &cedrus_dec_ops_mpeg2;
> dev->dec_ops[CEDRUS_CODEC_H264] = &cedrus_dec_ops_h264;
> dev->dec_ops[CEDRUS_CODEC_H265] = &cedrus_dec_ops_h265;
> + dev->dec_ops[CEDRUS_CODEC_VP8] = &cedrus_dec_ops_vp8;
>
> mutex_init(&dev->dev_mutex);
>
> diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.h b/drivers/staging/media/sunxi/cedrus/cedrus.h
> index f8264953dd04..353cb04b4ce5 100644
> --- a/drivers/staging/media/sunxi/cedrus/cedrus.h
> +++ b/drivers/staging/media/sunxi/cedrus/cedrus.h
> @@ -35,6 +35,7 @@ enum cedrus_codec {
> CEDRUS_CODEC_MPEG2,
> CEDRUS_CODEC_H264,
> CEDRUS_CODEC_H265,
> + CEDRUS_CODEC_VP8,
> CEDRUS_CODEC_LAST,
> };
>
> @@ -76,6 +77,10 @@ struct cedrus_h265_run {
> const struct v4l2_ctrl_hevc_scaling_matrix *scaling_matrix;
> };
>
> +struct cedrus_vp8_run {
> + const struct v4l2_ctrl_vp8_frame_header *slice_params;
> +};
> +
> struct cedrus_run {
> struct vb2_v4l2_buffer *src;
> struct vb2_v4l2_buffer *dst;
> @@ -84,6 +89,7 @@ struct cedrus_run {
> struct cedrus_h264_run h264;
> struct cedrus_mpeg2_run mpeg2;
> struct cedrus_h265_run h265;
> + struct cedrus_vp8_run vp8;
> };
> };
>
> @@ -141,6 +147,14 @@ struct cedrus_ctx {
> void *entry_points_buf;
> dma_addr_t entry_points_buf_addr;
> } h265;
> + struct {
> + unsigned int last_frame_p_type;
> + unsigned int last_filter_type;
> + unsigned int last_sharpness_level;
> +
> + u8 *entropy_probs_buf;
> + dma_addr_t entropy_probs_buf_dma;
> + } vp8;
> } codec;
> };
>
> @@ -188,6 +202,7 @@ struct cedrus_dev {
> extern struct cedrus_dec_ops cedrus_dec_ops_mpeg2;
> extern struct cedrus_dec_ops cedrus_dec_ops_h264;
> extern struct cedrus_dec_ops cedrus_dec_ops_h265;
> +extern struct cedrus_dec_ops cedrus_dec_ops_vp8;
>
> static inline void cedrus_write(struct cedrus_dev *dev, u32 reg, u32 val)
> {
> diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_dec.c b/drivers/staging/media/sunxi/cedrus/cedrus_dec.c
> index 38c0bd7cf672..740b738fdde6 100644
> --- a/drivers/staging/media/sunxi/cedrus/cedrus_dec.c
> +++ b/drivers/staging/media/sunxi/cedrus/cedrus_dec.c
> @@ -70,6 +70,11 @@ void cedrus_device_run(void *priv)
> V4L2_CID_MPEG_VIDEO_HEVC_SCALING_MATRIX);
> break;
>
> + case V4L2_PIX_FMT_VP8_FRAME:
> + run.vp8.slice_params = cedrus_find_control_data(ctx,
> + V4L2_CID_MPEG_VIDEO_VP8_FRAME_HEADER);
> + break;
> +
> default:
> break;
> }
> diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_hw.c b/drivers/staging/media/sunxi/cedrus/cedrus_hw.c
> index fb0cf8adcf1e..7c0ab4015e8f 100644
> --- a/drivers/staging/media/sunxi/cedrus/cedrus_hw.c
> +++ b/drivers/staging/media/sunxi/cedrus/cedrus_hw.c
> @@ -48,6 +48,7 @@ int cedrus_engine_enable(struct cedrus_ctx *ctx, enum cedrus_codec codec)
> break;
>
> case CEDRUS_CODEC_H264:
> + case CEDRUS_CODEC_VP8:
> reg |= VE_MODE_DEC_H264;
> break;
>
> diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_regs.h b/drivers/staging/media/sunxi/cedrus/cedrus_regs.h
> index 150eae2d92d2..6cb1c279790f 100644
> --- a/drivers/staging/media/sunxi/cedrus/cedrus_regs.h
> +++ b/drivers/staging/media/sunxi/cedrus/cedrus_regs.h
> @@ -552,6 +552,7 @@
> #define VE_H264_SHS_QP_SCALING_MATRIX_DEFAULT BIT(24)
>
> #define VE_H264_CTRL 0x220
> +#define VE_H264_CTRL_VP8 BIT(29)
> #define VE_H264_CTRL_VLD_DATA_REQ_INT BIT(2)
> #define VE_H264_CTRL_DECODE_ERR_INT BIT(1)
> #define VE_H264_CTRL_SLICE_DECODE_INT BIT(0)
> @@ -561,7 +562,12 @@
> VE_H264_CTRL_SLICE_DECODE_INT)
>
> #define VE_H264_TRIGGER_TYPE 0x224
> +#define VE_H264_TRIGGER_TYPE_PROBABILITY(x) SHIFT_AND_MASK_BITS(x, 31, 24)
> +#define VE_H264_TRIGGER_TYPE_BIN_LENS(x) SHIFT_AND_MASK_BITS((x) - 1, 18, 16)
> #define VE_H264_TRIGGER_TYPE_N_BITS(x) (((x) & 0x3f) << 8)
> +#define VE_H264_TRIGGER_TYPE_VP8_GET_BITS (15 << 0)
> +#define VE_H264_TRIGGER_TYPE_VP8_UPDATE_COEF (14 << 0)
> +#define VE_H264_TRIGGER_TYPE_VP8_SLICE_DECODE (10 << 0)
> #define VE_H264_TRIGGER_TYPE_AVC_SLICE_DECODE (8 << 0)
> #define VE_H264_TRIGGER_TYPE_INIT_SWDEC (7 << 0)
> #define VE_H264_TRIGGER_TYPE_FLUSH_BITS (3 << 0)
> @@ -571,6 +577,7 @@
> #define VE_H264_STATUS_DECODE_ERR_INT VE_H264_CTRL_DECODE_ERR_INT
> #define VE_H264_STATUS_SLICE_DECODE_INT VE_H264_CTRL_SLICE_DECODE_INT
> #define VE_H264_STATUS_VLD_BUSY BIT(8)
> +#define VE_H264_STATUS_VP8_UPPROB_BUSY BIT(17)
>
> #define VE_H264_STATUS_INT_MASK VE_H264_CTRL_INT_MASK
>
> @@ -589,10 +596,83 @@
> #define VE_H264_OUTPUT_FRAME_IDX 0x24c
> #define VE_H264_EXTRA_BUFFER1 0x250
> #define VE_H264_EXTRA_BUFFER2 0x254
> +#define VE_H264_MB_ADDR 0x260
> +#define VE_H264_ERROR_CASE 0x2b8
> #define VE_H264_BASIC_BITS 0x2dc
> #define VE_AVC_SRAM_PORT_OFFSET 0x2e0
> #define VE_AVC_SRAM_PORT_DATA 0x2e4
>
> +#define VE_VP8_PPS 0x214
> +#define VE_VP8_PPS_PIC_TYPE_P_FRAME BIT(31)
> +#define VE_VP8_PPS_LAST_SHARPNESS_LEVEL(v) SHIFT_AND_MASK_BITS(v, 30, 28)
> +#define VE_VP8_PPS_LAST_PIC_TYPE_P_FRAME BIT(27)
> +#define VE_VP8_PPS_ALTREF_SIGN_BIAS BIT(26)
> +#define VE_VP8_PPS_GOLDEN_SIGN_BIAS BIT(25)
> +#define VE_VP8_PPS_RELOAD_ENTROPY_PROBS BIT(24)
> +#define VE_VP8_PPS_REFRESH_ENTROPY_PROBS BIT(23)
> +#define VE_VP8_PPS_MB_NO_COEFF_SKIP BIT(22)
> +#define VE_VP8_PPS_TOKEN_PARTITION(v) SHIFT_AND_MASK_BITS(v, 21, 20)
> +#define VE_VP8_PPS_MODE_REF_LF_DELTA_UPDATE BIT(19)
> +#define VE_VP8_PPS_MODE_REF_LF_DELTA_ENABLE BIT(18)
> +#define VE_VP8_PPS_LOOP_FILTER_LEVEL(v) SHIFT_AND_MASK_BITS(v, 17, 12)
> +#define VE_VP8_PPS_LOOP_FILTER_SIMPLE BIT(11)
> +#define VE_VP8_PPS_SHARPNESS_LEVEL(v) SHIFT_AND_MASK_BITS(v, 10, 8)
> +#define VE_VP8_PPS_LAST_LOOP_FILTER_SIMPLE BIT(7)
> +#define VE_VP8_PPS_SEGMENTATION_ENABLE BIT(6)
> +#define VE_VP8_PPS_MB_SEGMENT_ABS_DELTA BIT(5)
> +#define VE_VP8_PPS_UPDATE_MB_SEGMENTATION_MAP BIT(4)
> +#define VE_VP8_PPS_FULL_PIXEL BIT(3)
> +#define VE_VP8_PPS_BILINEAR_MC_FILTER BIT(2)
> +#define VE_VP8_PPS_FILTER_TYPE_SIMPLE BIT(1)
> +#define VE_VP8_PPS_LPF_DISABLE BIT(0)
> +
> +#define VE_VP8_QP_INDEX_DELTA 0x218
> +#define VE_VP8_QP_INDEX_DELTA_UVAC(v) SHIFT_AND_MASK_BITS(v, 31, 27)
> +#define VE_VP8_QP_INDEX_DELTA_UVDC(v) SHIFT_AND_MASK_BITS(v, 26, 22)
> +#define VE_VP8_QP_INDEX_DELTA_Y2AC(v) SHIFT_AND_MASK_BITS(v, 21, 17)
> +#define VE_VP8_QP_INDEX_DELTA_Y2DC(v) SHIFT_AND_MASK_BITS(v, 16, 12)
> +#define VE_VP8_QP_INDEX_DELTA_Y1DC(v) SHIFT_AND_MASK_BITS(v, 11, 7)
> +#define VE_VP8_QP_INDEX_DELTA_BASE_QINDEX(v) SHIFT_AND_MASK_BITS(v, 6, 0)
> +
> +#define VE_VP8_PART_SIZE_OFFSET 0x21c
> +#define VE_VP8_ENTROPY_PROBS_ADDR 0x250
> +#define VE_VP8_FIRST_DATA_PART_LEN 0x254
> +
> +#define VE_VP8_FSIZE 0x258
> +#define VE_VP8_FSIZE_WIDTH(w) \
> + SHIFT_AND_MASK_BITS(DIV_ROUND_UP(w, 16), 15, 8)
> +#define VE_VP8_FSIZE_HEIGHT(h) \
> + SHIFT_AND_MASK_BITS(DIV_ROUND_UP(h, 16), 7, 0)
> +
> +#define VE_VP8_PICSIZE 0x25c
> +#define VE_VP8_PICSIZE_WIDTH(w) SHIFT_AND_MASK_BITS(w, 27, 16)
> +#define VE_VP8_PICSIZE_HEIGHT(h) SHIFT_AND_MASK_BITS(h, 11, 0)
> +
> +#define VE_VP8_REC_LUMA 0x2ac
> +#define VE_VP8_FWD_LUMA 0x2b0
> +#define VE_VP8_BWD_LUMA 0x2b4
> +#define VE_VP8_REC_CHROMA 0x2d0
> +#define VE_VP8_FWD_CHROMA 0x2d4
> +#define VE_VP8_BWD_CHROMA 0x2d8
> +#define VE_VP8_ALT_LUMA 0x2e8
> +#define VE_VP8_ALT_CHROMA 0x2ec
> +
> +#define VE_VP8_SEGMENT_FEAT_MB_LV0 0x2f0
> +#define VE_VP8_SEGMENT_FEAT_MB_LV1 0x2f4
> +
> +#define VE_VP8_SEGMENT3(v) SHIFT_AND_MASK_BITS(v, 31, 24)
> +#define VE_VP8_SEGMENT2(v) SHIFT_AND_MASK_BITS(v, 23, 16)
> +#define VE_VP8_SEGMENT1(v) SHIFT_AND_MASK_BITS(v, 15, 8)
> +#define VE_VP8_SEGMENT0(v) SHIFT_AND_MASK_BITS(v, 7, 0)
> +
> +#define VE_VP8_REF_LF_DELTA 0x2f8
> +#define VE_VP8_MODE_LF_DELTA 0x2fc
> +
> +#define VE_VP8_LF_DELTA3(v) SHIFT_AND_MASK_BITS(v, 30, 24)
> +#define VE_VP8_LF_DELTA2(v) SHIFT_AND_MASK_BITS(v, 22, 16)
> +#define VE_VP8_LF_DELTA1(v) SHIFT_AND_MASK_BITS(v, 14, 8)
> +#define VE_VP8_LF_DELTA0(v) SHIFT_AND_MASK_BITS(v, 6, 0)
> +
> #define VE_ISP_INPUT_SIZE 0xa00
> #define VE_ISP_INPUT_STRIDE 0xa04
> #define VE_ISP_CTRL 0xa08
> diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_video.c b/drivers/staging/media/sunxi/cedrus/cedrus_video.c
> index a78d6b1a3b64..6801ffa77a6b 100644
> --- a/drivers/staging/media/sunxi/cedrus/cedrus_video.c
> +++ b/drivers/staging/media/sunxi/cedrus/cedrus_video.c
> @@ -48,6 +48,10 @@ static struct cedrus_format cedrus_formats[] = {
> .directions = CEDRUS_DECODE_SRC,
> .capabilities = CEDRUS_CAPABILITY_H265_DEC,
> },
> + {
> + .pixelformat = V4L2_PIX_FMT_VP8_FRAME,
> + .directions = CEDRUS_DECODE_SRC,
> + },
> {
> .pixelformat = V4L2_PIX_FMT_SUNXI_TILED_NV12,
> .directions = CEDRUS_DECODE_DST,
> @@ -125,6 +129,7 @@ void cedrus_prepare_format(struct v4l2_pix_format *pix_fmt, int extended)
> case V4L2_PIX_FMT_MPEG2_SLICE:
> case V4L2_PIX_FMT_H264_SLICE:
> case V4L2_PIX_FMT_HEVC_SLICE:
> + case V4L2_PIX_FMT_VP8_FRAME:
> /* Zero bytes per line for encoded source. */
> bytesperline = 0;
> /* Choose some minimum size since this can't be 0 */
> @@ -499,6 +504,10 @@ static int cedrus_start_streaming(struct vb2_queue *vq, unsigned int count)
> ctx->current_codec = CEDRUS_CODEC_H265;
> break;
>
> + case V4L2_PIX_FMT_VP8_FRAME:
> + ctx->current_codec = CEDRUS_CODEC_VP8;
> + break;
> +
> default:
> return -EINVAL;
> }
> diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_vp8.c b/drivers/staging/media/sunxi/cedrus/cedrus_vp8.c
> new file mode 100644
> index 000000000000..93beffd07c35
> --- /dev/null
> +++ b/drivers/staging/media/sunxi/cedrus/cedrus_vp8.c
> @@ -0,0 +1,699 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Cedrus VPU driver
> + *
> + * Copyright (c) 2019 Jernej Skrabec <jernej.skrabec@siol.net>
> + */
> +
> +#include <linux/delay.h>
> +#include <linux/types.h>
> +
> +#include <media/videobuf2-dma-contig.h>
> +
> +#include "cedrus.h"
> +#include "cedrus_hw.h"
> +#include "cedrus_regs.h"
> +
> +#define CEDRUS_ENTROPY_PROBS_SIZE 0x2400
> +#define VP8_PROB_HALF 128
> +
> +static const u8 prob_table_init[] = {
> + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
> + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
> + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0xB0, 0xF6, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
> + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDF, 0xF1, 0xFC, 0xFF,
> + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0xF9, 0xFD, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xF4, 0xFC, 0xFF,
> + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0xEA, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
> + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0xFF, 0xF6, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0xEF, 0xFD, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
> + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFE, 0xFF,
> + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xF8, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
> + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFB, 0xFF, 0xFE, 0xFF,
> + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFD, 0xFE, 0xFF,
> + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0xFB, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
> + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0xFF, 0xFE, 0xFD, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0xFA, 0xFF, 0xFE, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF,
> + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0xFF,
> + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
> + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
> + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD9, 0xFF, 0xFF, 0xFF,
> + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0xE1, 0xFC, 0xF1, 0xFD, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0xEA, 0xFA, 0xF1, 0xFA, 0xFD, 0xFF, 0xFD, 0xFE,
> + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0xDF, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
> + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEE, 0xFD, 0xFE, 0xFE,
> + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xF8, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
> + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF9, 0xFE, 0xFF, 0xFF,
> + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFD, 0xFF, 0xFF,
> + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0xF7, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
> + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0xFF, 0xFD, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
> + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
> + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
> + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0xFF, 0xFF, 0xFF,
> + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFE, 0xFD, 0xFF,
> + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0xFA, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
> + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
> + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
> + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0xBA, 0xFB, 0xFA, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
> + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEA, 0xFB, 0xF4, 0xFE,
> + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0xFB, 0xFB, 0xF3, 0xFD, 0xFE, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFD, 0xFE, 0xFF,
> + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0xEC, 0xFD, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0xFB, 0xFD, 0xFD, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF,
> + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0xFF, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
> + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
> + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
> + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFE, 0xFF, 0xFF,
> + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
> + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
> + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
> + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
> + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
> + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
> + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
> + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
> + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0xFA, 0xFE, 0xFC, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF,
> + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFE, 0xF9, 0xFD,
> + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFD, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
> + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF6, 0xFD, 0xFD, 0xFF,
> + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0xFC, 0xFE, 0xFB, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFE, 0xFC, 0xFF,
> + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0xF8, 0xFE, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0xFD, 0xFF, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF,
> + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0xFF, 0xFB, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0xF5, 0xFB, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
> + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0xFD, 0xFE, 0xFF,
> + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFB, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
> + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFD, 0xFE, 0xFF,
> + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFC, 0xFF, 0xFF,
> + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0xF9, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
> + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0xFF, 0xFF, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0xFA, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
> + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
> + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
> + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0xFF,
> + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x91, 0x9C, 0xA3, 0x80,
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6E, 0x6F, 0x96, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0x78, 0x5A, 0x4F, 0x85, 0x57, 0x55, 0x50, 0x6F,
> + 0x97, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0x93, 0x88, 0x12, 0x00, 0x6A, 0x91, 0x01, 0x00, 0xB3, 0x79, 0x01, 0x00,
> + 0xDF, 0x01, 0x22, 0x00, 0xD0, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x01, 0x01, 0x8F,
> + 0x0E, 0x12, 0x0E, 0x6B, 0x87, 0x40, 0x39, 0x44, 0x3C, 0x38, 0x80, 0x41,
> + 0x9F, 0x86, 0x80, 0x22, 0xEA, 0xBC, 0x80, 0x1C, 0x00, 0x00, 0x00, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0x84, 0x02, 0x04, 0x06, 0x80, 0x81, 0x82, 0x83, 0x80, 0x02, 0x04, 0x06,
> + 0x81, 0x82, 0x83, 0x84, 0x80, 0x02, 0x81, 0x04, 0x82, 0x83, 0x00, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x08,
> + 0x04, 0x06, 0x80, 0x81, 0x82, 0x83, 0x0A, 0x0C, 0x84, 0x85, 0x86, 0x87,
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x08, 0x04, 0x06, 0x80, 0x81,
> + 0x82, 0x83, 0x0A, 0x0C, 0x84, 0x85, 0x86, 0x87, 0x00, 0x00, 0x00, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0x83, 0x02, 0x82, 0x04, 0x80, 0x81, 0x00, 0x00, 0x80, 0x02, 0x81, 0x04,
> + 0x82, 0x06, 0x08, 0x0C, 0x83, 0x0A, 0x85, 0x86, 0x84, 0x0E, 0x87, 0x10,
> + 0x88, 0x89, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0x8A, 0x02, 0x8B, 0x04, 0x8C, 0x8D, 0x00, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0x87, 0x02, 0x85, 0x04, 0x86, 0x06, 0x88, 0x89,
> +};
> +
> +static const u8 vp8_mv_update_prob[2][19] = {
> + { 237, 246, 253, 253, 254, 254, 254, 254, 254,
> + 254, 254, 254, 254, 254, 250, 250, 252, 254, 254 },
> + { 231, 243, 245, 253, 254, 254, 254, 254, 254,
> + 254, 254, 254, 254, 254, 251, 251, 254, 254, 254 }
> +};
> +
> +static uint8_t read_bits(struct cedrus_dev *dev, unsigned int bits_count,
> + unsigned int probability)
> +{
> + cedrus_write(dev, VE_H264_TRIGGER_TYPE,
> + VE_H264_TRIGGER_TYPE_VP8_GET_BITS |
> + VE_H264_TRIGGER_TYPE_BIN_LENS(bits_count) |
> + VE_H264_TRIGGER_TYPE_PROBABILITY(probability));
> +
> + while (cedrus_read(dev, VE_H264_STATUS) & VE_H264_STATUS_VLD_BUSY)
> + ;
> +
> + return cedrus_read(dev, VE_H264_BASIC_BITS);
> +}
> +
> +static void get_delta_q(struct cedrus_dev *dev)
> +{
> + if (read_bits(dev, 1, VP8_PROB_HALF)) {
> + read_bits(dev, 4, VP8_PROB_HALF);
> + read_bits(dev, 1, VP8_PROB_HALF);
> + }
> +}
> +
> +static void process_segmentation_info(struct cedrus_dev *dev)
> +{
> + int update = read_bits(dev, 1, VP8_PROB_HALF);
> + int i;
> +
> + if (read_bits(dev, 1, VP8_PROB_HALF)) {
> + read_bits(dev, 1, VP8_PROB_HALF);
> +
> + for (i = 0; i < 4; i++)
> + if (read_bits(dev, 1, VP8_PROB_HALF)) {
> + read_bits(dev, 7, VP8_PROB_HALF);
> + read_bits(dev, 1, VP8_PROB_HALF);
> + }
> +
> + for (i = 0; i < 4; i++)
> + if (read_bits(dev, 1, VP8_PROB_HALF)) {
> + read_bits(dev, 6, VP8_PROB_HALF);
> + read_bits(dev, 1, VP8_PROB_HALF);
> + }
> + }
> +
> + if (update)
> + for (i = 0; i < 3; i++)
> + if (read_bits(dev, 1, VP8_PROB_HALF))
> + read_bits(dev, 8, VP8_PROB_HALF);
> +}
> +
> +static void process_ref_lf_delta_info(struct cedrus_dev *dev)
> +{
> + if (read_bits(dev, 1, VP8_PROB_HALF)) {
> + int i;
> +
> + for (i = 0; i < 4; i++)
> + if (read_bits(dev, 1, VP8_PROB_HALF)) {
> + read_bits(dev, 6, VP8_PROB_HALF);
> + read_bits(dev, 1, VP8_PROB_HALF);
> + }
> +
> + for (i = 0; i < 4; i++)
> + if (read_bits(dev, 1, VP8_PROB_HALF)) {
> + read_bits(dev, 6, VP8_PROB_HALF);
> + read_bits(dev, 1, VP8_PROB_HALF);
> + }
> + }
> +}
> +
> +static void process_ref_frame_info(struct cedrus_dev *dev)
> +{
> + u8 refresh_golden_frame = read_bits(dev, 1, VP8_PROB_HALF);
> + u8 refresh_alt_ref_frame = read_bits(dev, 1, VP8_PROB_HALF);
> +
> + if (!refresh_golden_frame)
> + read_bits(dev, 2, VP8_PROB_HALF);
> +
> + if (!refresh_alt_ref_frame)
> + read_bits(dev, 2, VP8_PROB_HALF);
> +
> + read_bits(dev, 1, VP8_PROB_HALF);
> + read_bits(dev, 1, VP8_PROB_HALF);
> +}
> +
> +static void cedrus_read_header(struct cedrus_dev *dev,
> + const struct v4l2_ctrl_vp8_frame_header *slice)
> +{
> + int i, j;
> +
> + if (VP8_FRAME_IS_KEY_FRAME(slice)) {
> + read_bits(dev, 1, VP8_PROB_HALF);
> + read_bits(dev, 1, VP8_PROB_HALF);
> + }
> +
> + if (read_bits(dev, 1, VP8_PROB_HALF))
> + process_segmentation_info(dev);
> +
> + read_bits(dev, 1, VP8_PROB_HALF);
> + read_bits(dev, 6, VP8_PROB_HALF);
> + read_bits(dev, 3, VP8_PROB_HALF);
> +
> + if (read_bits(dev, 1, VP8_PROB_HALF))
> + process_ref_lf_delta_info(dev);
> +
> + read_bits(dev, 2, VP8_PROB_HALF);
> + read_bits(dev, 7, VP8_PROB_HALF);
> +
> + get_delta_q(dev);
> + get_delta_q(dev);
> + get_delta_q(dev);
> + get_delta_q(dev);
> + get_delta_q(dev);
> +
> + if (!VP8_FRAME_IS_KEY_FRAME(slice))
> + process_ref_frame_info(dev);
> +
> + read_bits(dev, 1, VP8_PROB_HALF);
> +
> + if (!VP8_FRAME_IS_KEY_FRAME(slice))
> + read_bits(dev, 1, VP8_PROB_HALF);
> +
> + cedrus_write(dev, VE_H264_TRIGGER_TYPE, VE_H264_TRIGGER_TYPE_VP8_UPDATE_COEF);
> + while (cedrus_read(dev, VE_H264_STATUS) & VE_H264_STATUS_VP8_UPPROB_BUSY)
> + ;
> +
> + cedrus_write(dev, VE_H264_STATUS, VE_H264_CTRL_INT_MASK);
> +
> + if (read_bits(dev, 1, VP8_PROB_HALF))
> + read_bits(dev, 8, VP8_PROB_HALF);
> +
> + if (!VP8_FRAME_IS_KEY_FRAME(slice)) {
> + read_bits(dev, 8, VP8_PROB_HALF);
> + read_bits(dev, 8, VP8_PROB_HALF);
> + read_bits(dev, 8, VP8_PROB_HALF);
> +
> + if (read_bits(dev, 1, VP8_PROB_HALF)) {
> + read_bits(dev, 8, VP8_PROB_HALF);
> + read_bits(dev, 8, VP8_PROB_HALF);
> + read_bits(dev, 8, VP8_PROB_HALF);
> + read_bits(dev, 8, VP8_PROB_HALF);
> + }
> +
> + if (read_bits(dev, 1, VP8_PROB_HALF)) {
> + read_bits(dev, 8, VP8_PROB_HALF);
> + read_bits(dev, 8, VP8_PROB_HALF);
> + read_bits(dev, 8, VP8_PROB_HALF);
> + }
> +
> + for (i = 0; i < 2; i++)
> + for (j = 0; j < 19; j++)
> + if (read_bits(dev, 1, vp8_mv_update_prob[i][j]))
> + read_bits(dev, 7, VP8_PROB_HALF);
> + }
> +}
> +
> +static void cedrus_vp8_update_probs(const struct v4l2_ctrl_vp8_frame_header *slice,
> + u8 *prob_table)
> +{
> + int i, j, k;
> +
> + memcpy(&prob_table[0x1008], slice->entropy_header.y_mode_probs, 4);
> + memcpy(&prob_table[0x1010], slice->entropy_header.uv_mode_probs, 3);
> +
> + memcpy(&prob_table[0x1018], slice->segment_header.segment_probs, 3);
> +
> + prob_table[0x101c] = slice->prob_skip_false;
> + prob_table[0x101d] = slice->prob_intra;
> + prob_table[0x101e] = slice->prob_last;
> + prob_table[0x101f] = slice->prob_gf;
> +
> + memcpy(&prob_table[0x1020], slice->entropy_header.mv_probs[0], 19);
> + memcpy(&prob_table[0x1040], slice->entropy_header.mv_probs[1], 19);
> +
> + for (i = 0; i < 4; ++i)
> + for (j = 0; j < 8; ++j)
> + for (k = 0; k < 3; ++k)
> + memcpy(&prob_table[i * 512 + j * 64 + k * 16],
> + slice->entropy_header.coeff_probs[i][j][k], 11);
> +}
> +
> +static enum cedrus_irq_status
> +cedrus_vp8_irq_status(struct cedrus_ctx *ctx)
> +{
> + struct cedrus_dev *dev = ctx->dev;
> + u32 reg = cedrus_read(dev, VE_H264_STATUS);
> +
> + if (reg & (VE_H264_STATUS_DECODE_ERR_INT |
> + VE_H264_STATUS_VLD_DATA_REQ_INT))
> + return CEDRUS_IRQ_ERROR;
> +
> + if (reg & VE_H264_CTRL_SLICE_DECODE_INT)
> + return CEDRUS_IRQ_OK;
> +
> + return CEDRUS_IRQ_NONE;
> +}
> +
> +static void cedrus_vp8_irq_clear(struct cedrus_ctx *ctx)
> +{
> + struct cedrus_dev *dev = ctx->dev;
> +
> + cedrus_write(dev, VE_H264_STATUS,
> + VE_H264_STATUS_INT_MASK);
> +}
> +
> +static void cedrus_vp8_irq_disable(struct cedrus_ctx *ctx)
> +{
> + struct cedrus_dev *dev = ctx->dev;
> + u32 reg = cedrus_read(dev, VE_H264_CTRL);
> +
> + cedrus_write(dev, VE_H264_CTRL,
> + reg & ~VE_H264_CTRL_INT_MASK);
> +}
> +
> +static void cedrus_vp8_setup(struct cedrus_ctx *ctx,
> + struct cedrus_run *run)
> +{
> + const struct v4l2_ctrl_vp8_frame_header *slice = run->vp8.slice_params;
> + struct vb2_queue *cap_q = &ctx->fh.m2m_ctx->cap_q_ctx.q;
> + struct vb2_buffer *src_buf = &run->src->vb2_buf;
> + struct cedrus_dev *dev = ctx->dev;
> + dma_addr_t luma_addr, chroma_addr;
> + dma_addr_t src_buf_addr;
> + int header_size;
> + int qindex;
> + u32 reg;
> +
> + cedrus_engine_enable(ctx, CEDRUS_CODEC_VP8);
> +
> + cedrus_write(dev, VE_H264_CTRL, VE_H264_CTRL_VP8);
> +
> + cedrus_vp8_update_probs(slice, ctx->codec.vp8.entropy_probs_buf);
> +
> + reg = slice->first_part_size * 8;
> + cedrus_write(dev, VE_VP8_FIRST_DATA_PART_LEN, reg);
> +
> + header_size = VP8_FRAME_IS_KEY_FRAME(slice) ? 10 : 3;
> +
> + reg = slice->first_part_size + header_size;
> + cedrus_write(dev, VE_VP8_PART_SIZE_OFFSET, reg);
> +
> + reg = vb2_plane_size(src_buf, 0) * 8;
> + cedrus_write(dev, VE_H264_VLD_LEN, reg);
> +
> + /*
> + * FIXME: There is a problem if frame header is skipped (adding
> + * first_part_header_bits to offset). It seems that functions
> + * for parsing bitstreams change internal state of VPU in some
> + * way that can't be otherwise set. Maybe this can be bypassed
> + * by somehow fixing probability table buffer?
> + */
> + reg = header_size * 8;
> + cedrus_write(dev, VE_H264_VLD_OFFSET, reg);
> +
> + src_buf_addr = vb2_dma_contig_plane_dma_addr(src_buf, 0);
> + cedrus_write(dev, VE_H264_VLD_END,
> + src_buf_addr + vb2_get_plane_payload(src_buf, 0));
> + cedrus_write(dev, VE_H264_VLD_ADDR,
> + VE_H264_VLD_ADDR_VAL(src_buf_addr) |
> + VE_H264_VLD_ADDR_FIRST | VE_H264_VLD_ADDR_VALID |
> + VE_H264_VLD_ADDR_LAST);
> +
> + cedrus_write(dev, VE_H264_TRIGGER_TYPE,
> + VE_H264_TRIGGER_TYPE_INIT_SWDEC);
> +
> + cedrus_write(dev, VE_VP8_ENTROPY_PROBS_ADDR,
> + ctx->codec.vp8.entropy_probs_buf_dma);
> +
> + reg = 0;
> + switch (slice->version) {
> + case 1:
> + reg |= VE_VP8_PPS_FILTER_TYPE_SIMPLE;
> + reg |= VE_VP8_PPS_BILINEAR_MC_FILTER;
> + break;
> + case 2:
> + reg |= VE_VP8_PPS_LPF_DISABLE;
> + reg |= VE_VP8_PPS_BILINEAR_MC_FILTER;
> + break;
> + case 3:
> + reg |= VE_VP8_PPS_LPF_DISABLE;
> + reg |= VE_VP8_PPS_FULL_PIXEL;
> + break;
> + }
> + if (slice->segment_header.flags & V4L2_VP8_SEGMENT_HEADER_FLAG_UPDATE_MAP)
> + reg |= VE_VP8_PPS_UPDATE_MB_SEGMENTATION_MAP;
> + if (!(slice->segment_header.flags & V4L2_VP8_SEGMENT_HEADER_FLAG_DELTA_VALUE_MODE))
> + reg |= VE_VP8_PPS_MB_SEGMENT_ABS_DELTA;
> + if (slice->segment_header.flags & V4L2_VP8_SEGMENT_HEADER_FLAG_ENABLED)
> + reg |= VE_VP8_PPS_SEGMENTATION_ENABLE;
> + if (ctx->codec.vp8.last_filter_type)
> + reg |= VE_VP8_PPS_LAST_LOOP_FILTER_SIMPLE;
> + reg |= VE_VP8_PPS_SHARPNESS_LEVEL(slice->lf_header.sharpness_level);
> + if (slice->lf_header.flags & V4L2_VP8_LF_FILTER_TYPE_SIMPLE)
> + reg |= VE_VP8_PPS_LOOP_FILTER_SIMPLE;
> + reg |= VE_VP8_PPS_LOOP_FILTER_LEVEL(slice->lf_header.level);
> + if (slice->lf_header.flags & V4L2_VP8_LF_HEADER_ADJ_ENABLE)
> + reg |= VE_VP8_PPS_MODE_REF_LF_DELTA_ENABLE;
> + if (slice->lf_header.flags & V4L2_VP8_LF_HEADER_DELTA_UPDATE)
> + reg |= VE_VP8_PPS_MODE_REF_LF_DELTA_UPDATE;
> + reg |= VE_VP8_PPS_TOKEN_PARTITION(ilog2(slice->num_dct_parts));
> + if (slice->flags & V4L2_VP8_FRAME_HEADER_FLAG_MB_NO_SKIP_COEFF)
> + reg |= VE_VP8_PPS_MB_NO_COEFF_SKIP;
> + reg |= VE_VP8_PPS_RELOAD_ENTROPY_PROBS;
> + if (slice->flags & V4L2_VP8_FRAME_HEADER_FLAG_SIGN_BIAS_GOLDEN)
> + reg |= VE_VP8_PPS_GOLDEN_SIGN_BIAS;
> + if (slice->flags & V4L2_VP8_FRAME_HEADER_FLAG_SIGN_BIAS_ALT)
> + reg |= VE_VP8_PPS_ALTREF_SIGN_BIAS;
> + if (ctx->codec.vp8.last_frame_p_type)
> + reg |= VE_VP8_PPS_LAST_PIC_TYPE_P_FRAME;
> + reg |= VE_VP8_PPS_LAST_SHARPNESS_LEVEL(ctx->codec.vp8.last_sharpness_level);
> + if (!(slice->flags & V4L2_VP8_FRAME_HEADER_FLAG_KEY_FRAME))
> + reg |= VE_VP8_PPS_PIC_TYPE_P_FRAME;
> + cedrus_write(dev, VE_VP8_PPS, reg);
> +
> + cedrus_read_header(dev, slice);
> +
> + /* reset registers changed by HW */
> + cedrus_write(dev, VE_H264_CUR_MB_NUM, 0);
> + cedrus_write(dev, VE_H264_MB_ADDR, 0);
> + cedrus_write(dev, VE_H264_ERROR_CASE, 0);
> +
> + reg = 0;
> + reg |= VE_VP8_QP_INDEX_DELTA_UVAC(slice->quant_header.uv_ac_delta);
> + reg |= VE_VP8_QP_INDEX_DELTA_UVDC(slice->quant_header.uv_dc_delta);
> + reg |= VE_VP8_QP_INDEX_DELTA_Y2AC(slice->quant_header.y2_ac_delta);
> + reg |= VE_VP8_QP_INDEX_DELTA_Y2DC(slice->quant_header.y2_dc_delta);
> + reg |= VE_VP8_QP_INDEX_DELTA_Y1DC(slice->quant_header.y_dc_delta);
> + reg |= VE_VP8_QP_INDEX_DELTA_BASE_QINDEX(slice->quant_header.y_ac_qi);
> + cedrus_write(dev, VE_VP8_QP_INDEX_DELTA, reg);
> +
> + reg = 0;
> + reg |= VE_VP8_FSIZE_WIDTH(slice->width);
> + reg |= VE_VP8_FSIZE_HEIGHT(slice->height);
> + cedrus_write(dev, VE_VP8_FSIZE, reg);
> +
> + reg = 0;
> + reg |= VE_VP8_PICSIZE_WIDTH(slice->width);
> + reg |= VE_VP8_PICSIZE_HEIGHT(slice->height);
> + cedrus_write(dev, VE_VP8_PICSIZE, reg);
> +
> + reg = 0;
> + reg |= VE_VP8_SEGMENT3(slice->segment_header.quant_update[3]);
> + reg |= VE_VP8_SEGMENT2(slice->segment_header.quant_update[2]);
> + reg |= VE_VP8_SEGMENT1(slice->segment_header.quant_update[1]);
> + reg |= VE_VP8_SEGMENT0(slice->segment_header.quant_update[0]);
> + cedrus_write(dev, VE_VP8_SEGMENT_FEAT_MB_LV0, reg);
> +
> + reg = 0;
> + reg |= VE_VP8_SEGMENT3(slice->segment_header.lf_update[3]);
> + reg |= VE_VP8_SEGMENT2(slice->segment_header.lf_update[2]);
> + reg |= VE_VP8_SEGMENT1(slice->segment_header.lf_update[1]);
> + reg |= VE_VP8_SEGMENT0(slice->segment_header.lf_update[0]);
> + cedrus_write(dev, VE_VP8_SEGMENT_FEAT_MB_LV1, reg);
> +
> + reg = 0;
> + reg |= VE_VP8_LF_DELTA3(slice->lf_header.ref_frm_delta[3]);
> + reg |= VE_VP8_LF_DELTA2(slice->lf_header.ref_frm_delta[2]);
> + reg |= VE_VP8_LF_DELTA1(slice->lf_header.ref_frm_delta[1]);
> + reg |= VE_VP8_LF_DELTA0(slice->lf_header.ref_frm_delta[0]);
> + cedrus_write(dev, VE_VP8_REF_LF_DELTA, reg);
> +
> + reg = 0;
> + reg |= VE_VP8_LF_DELTA3(slice->lf_header.mb_mode_delta[3]);
> + reg |= VE_VP8_LF_DELTA2(slice->lf_header.mb_mode_delta[2]);
> + reg |= VE_VP8_LF_DELTA1(slice->lf_header.mb_mode_delta[1]);
> + reg |= VE_VP8_LF_DELTA0(slice->lf_header.mb_mode_delta[0]);
> + cedrus_write(dev, VE_VP8_MODE_LF_DELTA, reg);
> +
> + luma_addr = cedrus_dst_buf_addr(ctx, run->dst->vb2_buf.index, 0);
> + chroma_addr = cedrus_dst_buf_addr(ctx, run->dst->vb2_buf.index, 1);
> + cedrus_write(dev, VE_VP8_REC_LUMA, luma_addr);
> + cedrus_write(dev, VE_VP8_REC_CHROMA, chroma_addr);
> +
> + qindex = vb2_find_timestamp(cap_q, slice->last_frame_ts, 0);
> + if (qindex >= 0) {
> + luma_addr = cedrus_dst_buf_addr(ctx, qindex, 0);
> + chroma_addr = cedrus_dst_buf_addr(ctx, qindex, 1);
> + cedrus_write(dev, VE_VP8_FWD_LUMA, luma_addr);
> + cedrus_write(dev, VE_VP8_FWD_CHROMA, chroma_addr);
> + } else {
> + cedrus_write(dev, VE_VP8_FWD_LUMA, 0);
> + cedrus_write(dev, VE_VP8_FWD_CHROMA, 0);
> + }
> +
> + qindex = vb2_find_timestamp(cap_q, slice->golden_frame_ts, 0);
> + if (qindex >= 0) {
> + luma_addr = cedrus_dst_buf_addr(ctx, qindex, 0);
> + chroma_addr = cedrus_dst_buf_addr(ctx, qindex, 1);
> + cedrus_write(dev, VE_VP8_BWD_LUMA, luma_addr);
> + cedrus_write(dev, VE_VP8_BWD_CHROMA, chroma_addr);
> + } else {
> + cedrus_write(dev, VE_VP8_BWD_LUMA, 0);
> + cedrus_write(dev, VE_VP8_BWD_CHROMA, 0);
> + }
> +
> + qindex = vb2_find_timestamp(cap_q, slice->alt_frame_ts, 0);
> + if (qindex >= 0) {
> + luma_addr = cedrus_dst_buf_addr(ctx, qindex, 0);
> + chroma_addr = cedrus_dst_buf_addr(ctx, qindex, 1);
> + cedrus_write(dev, VE_VP8_ALT_LUMA, luma_addr);
> + cedrus_write(dev, VE_VP8_ALT_CHROMA, chroma_addr);
> + } else {
> + cedrus_write(dev, VE_VP8_ALT_LUMA, 0);
> + cedrus_write(dev, VE_VP8_ALT_CHROMA, 0);
> + }
> +
> + cedrus_write(dev, VE_H264_CTRL, VE_H264_CTRL_VP8 |
> + VE_H264_CTRL_DECODE_ERR_INT |
> + VE_H264_CTRL_SLICE_DECODE_INT);
> +
> + if (slice->lf_header.level) {
> + ctx->codec.vp8.last_filter_type =
> + !!(slice->lf_header.flags & V4L2_VP8_LF_FILTER_TYPE_SIMPLE);
> + ctx->codec.vp8.last_frame_p_type =
> + !VP8_FRAME_IS_KEY_FRAME(slice);
> + ctx->codec.vp8.last_sharpness_level =
> + slice->lf_header.sharpness_level;
> + }
> +}
> +
> +static int cedrus_vp8_start(struct cedrus_ctx *ctx)
> +{
> + struct cedrus_dev *dev = ctx->dev;
> +
> + ctx->codec.vp8.entropy_probs_buf =
> + dma_alloc_coherent(dev->dev, CEDRUS_ENTROPY_PROBS_SIZE,
> + &ctx->codec.vp8.entropy_probs_buf_dma,
> + GFP_KERNEL);
> + if (!ctx->codec.vp8.entropy_probs_buf)
> + return -ENOMEM;
> +
> + memcpy(&ctx->codec.vp8.entropy_probs_buf[2048],
> + prob_table_init, sizeof(prob_table_init));
> +
> + return 0;
> +}
> +
> +static void cedrus_vp8_stop(struct cedrus_ctx *ctx)
> +{
> + struct cedrus_dev *dev = ctx->dev;
> +
> + cedrus_engine_disable(dev);
> +
> + dma_free_coherent(dev->dev, CEDRUS_ENTROPY_PROBS_SIZE,
> + ctx->codec.vp8.entropy_probs_buf,
> + ctx->codec.vp8.entropy_probs_buf_dma);
> +}
> +
> +static void cedrus_vp8_trigger(struct cedrus_ctx *ctx)
> +{
> + struct cedrus_dev *dev = ctx->dev;
> +
> + cedrus_write(dev, VE_H264_TRIGGER_TYPE,
> + VE_H264_TRIGGER_TYPE_VP8_SLICE_DECODE);
> +}
> +
> +struct cedrus_dec_ops cedrus_dec_ops_vp8 = {
> + .irq_clear = cedrus_vp8_irq_clear,
> + .irq_disable = cedrus_vp8_irq_disable,
> + .irq_status = cedrus_vp8_irq_status,
> + .setup = cedrus_vp8_setup,
> + .start = cedrus_vp8_start,
> + .stop = cedrus_vp8_stop,
> + .trigger = cedrus_vp8_trigger,
> +};
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH v4 08/14] PCI: cadence: Fix updating Vendor ID and Subsystem Vendor ID register
From: Rob Herring @ 2020-05-20 21:36 UTC (permalink / raw)
To: Kishon Vijay Abraham I
Cc: devicetree, Lorenzo Pieralisi, Arnd Bergmann, Greg Kroah-Hartman,
linux-kernel, Tom Joseph, linux-pci, Bjorn Helgaas, linux-omap,
linux-arm-kernel
In-Reply-To: <20200506151429.12255-9-kishon@ti.com>
On Wed, May 06, 2020 at 08:44:23PM +0530, Kishon Vijay Abraham I wrote:
> Commit 1b79c5284439 ("PCI: cadence: Add host driver for Cadence PCIe
> controller") in order to update Vendor ID, directly wrote to
> PCI_VENDOR_ID register. However PCI_VENDOR_ID in root port configuration
> space is read-only register and writing to it will have no effect.
> Use local management register to configure Vendor ID and Subsystem Vendor
> ID.
>
> Fixes: 1b79c5284439 ("PCI: cadence: Add host driver for Cadence PCIe controller")
Fixes should come first.
> Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
> ---
> drivers/pci/controller/cadence/pcie-cadence-host.c | 9 +++++++--
> 1 file changed, 7 insertions(+), 2 deletions(-)
Reviewed-by: Rob Herring <robh@kernel.org>
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH v4 07/14] PCI: cadence: Add new *ops* for CPU addr fixup
From: Rob Herring @ 2020-05-20 21:34 UTC (permalink / raw)
To: Kishon Vijay Abraham I
Cc: devicetree, Lorenzo Pieralisi, Arnd Bergmann, Greg Kroah-Hartman,
linux-kernel, Tom Joseph, linux-pci, Bjorn Helgaas, linux-omap,
linux-arm-kernel
In-Reply-To: <20200506151429.12255-8-kishon@ti.com>
On Wed, May 06, 2020 at 08:44:22PM +0530, Kishon Vijay Abraham I wrote:
> Cadence driver uses "mem" memory resource to obtain the offset of
> configuration space address region, memory space address region and
> message space address region. The obtained offset is used to program
> the Address Translation Unit (ATU). However certain platforms like TI's
> J721E SoC require the absolute address to be programmed in the ATU and not
> just the offset.
Once again, Cadence host binding is broken (or at least the example is).
The 'mem' region shouldn't even exist. It is overlapping the config
space and 'ranges':
reg = <0x0 0xfb000000 0x0 0x01000000>,
<0x0 0x41000000 0x0 0x00001000>,
<0x0 0x40000000 0x0 0x04000000>;
reg-names = "reg", "cfg", "mem";
ranges = <0x02000000 0x0 0x42000000 0x0 0x42000000 0x0 0x1000000>,
<0x01000000 0x0 0x43000000 0x0 0x43000000 0x0 0x0010000>;
16M of registers looks a bit odd. I guess it doesn't matter
unless you have a 32-bit platform and care about your virtual
space. Probably should have been 3 regions for LM, RP, and AT looking
at the driver.
Whatever outbound address translation you need should be based on
'ranges'.
Rob
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [GIT PULL v2] ARM: simplify handover from UEFI to decompressor
From: Ard Biesheuvel @ 2020-05-20 21:32 UTC (permalink / raw)
To: linux-efi; +Cc: linux+pull, linux-arm-kernel
Hello Russell,
As discussed in the context of Geert's reverted v6 of the DTB memory
node discovery patch [0], EFI boot is one possible workaround for systems
where the base of memory is not a round multiple of 128 MB. U-boot today
supports the bootefi command out of the box, so this does not require any
special firmware.
So please pull the changes below for v5.8
[0] https://lore.kernel.org/linux-arm-kernel/20200429082120.16259-1-geert+renesas@glider.be/
The following changes since commit a780e485b5768e78aef087502499714901b68cc4:
ARM: 8971/1: replace the sole use of a symbol with its definition (2020-04-29 13:30:20 +0100)
are available in the Git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/ardb/linux.git tags/efi-arm-no-relocate-for-rmk
for you to fetch changes up to d0f9ca9be11f25ef4151195eab7ea36d136084f6:
ARM: decompressor: run decompressor in place if loaded via UEFI (2020-05-19 18:23:22 +0200)
----------------------------------------------------------------
Simplify EFI handover to decompressor
The EFI stub in the ARM kernel runs in the context of the firmware, which
means it usually runs with the caches and MMU on. Currently, we relocate
the zImage so it appears in the first 128 MiB, disable the MMU and caches
and invoke the decompressor via its ordinary entry point. However, since we
can pass the base of DRAM directly, there is no need to relocate the zImage,
which also means there is no need to disable and re-enable the caches and
create new page tables etc.
This also allows systems whose DRAM start address is not a round multiple
of 128 MB to decompress the kernel proper to the base of memory, ensuring
that all memory is usable at runtime.
----------------------------------------------------------------
Ard Biesheuvel (5):
ARM: decompressor: move headroom variable out of LC0
ARM: decompressor: split off _edata and stack base into separate object
ARM: decompressor: defer loading of the contents of the LC0 structure
ARM: decompressor: move GOT into .data for EFI enabled builds
ARM: decompressor: run decompressor in place if loaded via UEFI
arch/arm/boot/compressed/head.S | 79 +++++++++++++------------------
arch/arm/boot/compressed/vmlinux.lds.S | 5 ++
drivers/firmware/efi/libstub/arm32-stub.c | 45 +++---------------
3 files changed, 43 insertions(+), 86 deletions(-)
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH v4 0/7] firmware: smccc: Add basic SMCCC v1.2 + ARCH_SOC_ID support
From: Will Deacon @ 2020-05-20 21:29 UTC (permalink / raw)
To: Sudeep Holla, linux-arm-kernel
Cc: Mark Rutland, Lorenzo Pieralisi, Arnd Bergmann, catalin.marinas,
linux-kernel, Steven Price, harb, Will Deacon
In-Reply-To: <20200518091222.27467-1-sudeep.holla@arm.com>
On Mon, 18 May 2020 10:12:15 +0100, Sudeep Holla wrote:
> This patch series adds support for SMCCCv1.2 ARCH_SOC_ID.
> This doesn't add other changes added in SMCCC v1.2 yet. They will
> follow these soon along with its first user SPCI/PSA-FF.
>
> This is tested using upstream TF-A + the patch[3] fixing the original
> implementation there.
>
> [...]
Applied to arm64 (for-next/smccc), thanks!
[1/7] firmware: smccc: Add HAVE_ARM_SMCCC_DISCOVERY to identify SMCCC v1.1 and above
https://git.kernel.org/arm64/c/e5bfb21d98b6
[2/7] firmware: smccc: Update link to latest SMCCC specification
https://git.kernel.org/arm64/c/15c704ab6244
[3/7] firmware: smccc: Add the definition for SMCCCv1.2 version/error codes
https://git.kernel.org/arm64/c/0441bfe7f00a
[4/7] firmware: smccc: Drop smccc_version enum and use ARM_SMCCC_VERSION_1_x instead
https://git.kernel.org/arm64/c/ad5a57dfe434
[5/7] firmware: smccc: Refactor SMCCC specific bits into separate file
https://git.kernel.org/arm64/c/f2ae97062a48
[6/7] firmware: smccc: Add function to fetch SMCCC version
https://git.kernel.org/arm64/c/a4fb17465182
[7/7] firmware: smccc: Add ARCH_SOC_ID support
https://git.kernel.org/arm64/c/ce6488f0ce09
Arnd -- Sudeep's reply to you about the sysfs groups seemed reasonable to me,
but please shout if you'd rather I dropped this in order to pursue an
alternative approach.
Cheers,
--
Will
https://fixes.arm64.dev
https://next.arm64.dev
https://will.arm64.dev
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH v4 06/11] net: ethernet: mtk-eth-mac: new driver
From: Arnd Bergmann @ 2020-05-20 21:22 UTC (permalink / raw)
To: Bartosz Golaszewski
Cc: Edwin Peer, DTML, Stephane Le Provost, Bartosz Golaszewski,
Pedro Tsai, Sean Wang, linux-kernel@vger.kernel.org, Mark Lee,
Fabien Parent, Rob Herring, moderated list:ARM/Mediatek SoC...,
Andrew Perepech, John Crispin, Matthias Brugger, Jakub Kicinski,
Networking, David S . Miller, Linux ARM, Heiner Kallweit
In-Reply-To: <CAMRc=MeuQk9rFDFGWK0ijsiM-r296cVz9Rth8hWhW5Aeeti_cA@mail.gmail.com>
On Wed, May 20, 2020 at 7:35 PM Bartosz Golaszewski <brgl@bgdev.pl> wrote:
> śr., 20 maj 2020 o 16:37 Arnd Bergmann <arnd@arndb.de> napisał(a):
> > I just noticed how the naming of NET_MEDIATEK_MAC and NET_MEDIATEK_SOC
> > for two different drivers doing the same thing is really confusing.
> >
> > Maybe someone can come up with a better name, such as one
> > based on the soc it first showed up in.
> >
>
> This has been discussed under one of the previous submissions.
> MediaTek wants to use this IP on future designs as well and it's
> already used on multiple SoCs so they want the name to be generic. I
> also argued that this is a driver strongly tied to a specific
> platform(s) so if someone wants to compile it - they probably know
> what they're doing.
>
> That being said: I verified with MediaTek and the name of the IP I can
> use is "star" so they proposed "mtk-star-eth". I would personally
> maybe go with "mtk-star-mac". How about those two?
Both seem fine to me. If this was previously discussed, I don't want
do further bike-shedding and I'd trust you to pick a sensible name
based on the earlier discussions.
> > + /* One of the counters reached 0x8000000 - update stats and
> > > + * reset all counters.
> > > + */
> > > + if (unlikely(status & MTK_MAC_REG_INT_STS_MIB_CNT_TH)) {
> > > + mtk_mac_intr_disable_stats(priv);
> > > + schedule_work(&priv->stats_work);
> > > + }
> > > + befor
> > > + mtk_mac_intr_ack_all(priv);
> >
> > The ack here needs to be dropped, otherwise you can get further
> > interrupts before the bottom half has had a chance to run.
> >
>
> My thinking was this: if I mask the relevant interrupt (TX/RX
> complete) and ack it right away, the status bit will be asserted on
> the next packet received/sent but the process won't get interrupted
> and when I unmask it, it will fire right away and I won't have to
> recheck the status register. I noticed that if I ack it at the end of
> napi poll callback, I end up missing certain TX complete interrupts
> and end up seeing a lot of retransmissions even if I reread the status
> register. I'm not yet sure where this race happens.
Right, I see. If you just ack at the end of the poll function, you need
to check the rings again to ensure you did not miss an interrupt
between checking observing both rings to be empty and the irq-ack.
I suspect it's still cheaper to check the two rings with an uncached
read from memory than to to do the read-modify-write on the mmio,
but you'd have to measure that to be sure.
> > > +static void mtk_mac_tx_complete_all(struct mtk_mac_priv *priv)
> > > +{
> > > + struct mtk_mac_ring *ring = &priv->tx_ring;
> > > + struct net_device *ndev = priv->ndev;
> > > + int ret, pkts_compl, bytes_compl;
> > > + bool wake = false;
> > > +
> > > + mtk_mac_lock(priv);
> > > +
> > > + for (pkts_compl = 0, bytes_compl = 0;;
> > > + pkts_compl++, bytes_compl += ret, wake = true) {
> > > + if (!mtk_mac_ring_descs_available(ring))
> > > + break;
> > > +
> > > + ret = mtk_mac_tx_complete_one(priv);
> > > + if (ret < 0)
> > > + break;
> > > + }
> > > +
> > > + netdev_completed_queue(ndev, pkts_compl, bytes_compl);
> > > +
> > > + if (wake && netif_queue_stopped(ndev))
> > > + netif_wake_queue(ndev);
> > > +
> > > + mtk_mac_intr_enable_tx(priv);
> >
> > No need to ack the interrupt here if napi is still active. Just
> > ack both rx and tx when calling napi_complete().
> >
> > Some drivers actually use the napi budget for both rx and tx:
> > if you have more than 'budget' completed tx frames, return
> > early from this function and skip the napi_complete even
> > when less than 'budget' rx frames have arrived.
> >
>
> IIRC Jakub said that the most seen approach is to free all TX descs
> and receive up to budget packets, so this is what I did. I think it
> makes the most sense.
Ok, he's probably right then.
My idea was that the dma_unmap operation for the tx cleanup is
rather expensive on chips without cache-coherent DMA, so you
might not want to do too much of it but rather do it in reasonably
sized batches. It would also avoid the case where you renable the
tx-complete interrupt after cleaning the already-sent frames but
then immediately get an irq when the next frame that is already
queued is done.
This probably depends on the specific workload which one works
better here.
Arnd
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [PATCH 6/6] ARM: dts: Configure omap4 and 5 l4_abe for genpd and drop platform data
From: Tony Lindgren @ 2020-05-20 21:13 UTC (permalink / raw)
To: linux-omap
Cc: Rob Herring, devicetree, linux-kernel, Andrew F . Davis,
Tero Kristo, Santosh Shilimkar, Suman Anna, linux-arm-kernel
In-Reply-To: <20200520211334.61814-1-tony@atomide.com>
We can power off l4_abe domain when not in use when we configure it for
genpd. And with that change, we can now also drop the old unused legacy
platform data.
Note that we also need to now use "simple-pm-bus" instead of "simple-bus"
for PM runtime to get enabled for the bus.
Signed-off-by: Tony Lindgren <tony@atomide.com>
---
arch/arm/boot/dts/omap4-l4-abe.dtsi | 6 ++--
arch/arm/boot/dts/omap4.dtsi | 6 ++++
arch/arm/boot/dts/omap5-l4-abe.dtsi | 6 ++--
arch/arm/boot/dts/omap5.dtsi | 6 ++++
arch/arm/mach-omap2/omap_hwmod_44xx_data.c | 33 ----------------------
arch/arm/mach-omap2/omap_hwmod_54xx_data.c | 31 --------------------
6 files changed, 20 insertions(+), 68 deletions(-)
diff --git a/arch/arm/boot/dts/omap4-l4-abe.dtsi b/arch/arm/boot/dts/omap4-l4-abe.dtsi
--- a/arch/arm/boot/dts/omap4-l4-abe.dtsi
+++ b/arch/arm/boot/dts/omap4-l4-abe.dtsi
@@ -1,14 +1,16 @@
&l4_abe { /* 0x40100000 */
- compatible = "ti,omap4-l4-abe", "simple-bus";
+ compatible = "ti,omap4-l4-abe", "simple-pm-bus";
reg = <0x40100000 0x400>,
<0x40100400 0x400>;
reg-names = "la", "ap";
+ power-domains = <&prm_abe>;
+ /* OMAP4_L4_ABE_CLKCTRL is read-only */
#address-cells = <1>;
#size-cells = <1>;
ranges = <0x00000000 0x40100000 0x100000>, /* segment 0 */
<0x49000000 0x49000000 0x100000>;
segment@0 { /* 0x40100000 */
- compatible = "simple-bus";
+ compatible = "simple-pm-bus";
#address-cells = <1>;
#size-cells = <1>;
ranges =
diff --git a/arch/arm/boot/dts/omap4.dtsi b/arch/arm/boot/dts/omap4.dtsi
--- a/arch/arm/boot/dts/omap4.dtsi
+++ b/arch/arm/boot/dts/omap4.dtsi
@@ -637,6 +637,12 @@ prm_tesla: prm@400 {
#reset-cells = <1>;
};
+ prm_abe: prm@500 {
+ compatible = "ti,omap4-prm-inst", "ti,omap-prm-inst";
+ reg = <0x500 0x100>;
+ #power-domain-cells = <0>;
+ };
+
prm_core: prm@700 {
compatible = "ti,omap4-prm-inst", "ti,omap-prm-inst";
reg = <0x700 0x100>;
diff --git a/arch/arm/boot/dts/omap5-l4-abe.dtsi b/arch/arm/boot/dts/omap5-l4-abe.dtsi
--- a/arch/arm/boot/dts/omap5-l4-abe.dtsi
+++ b/arch/arm/boot/dts/omap5-l4-abe.dtsi
@@ -1,14 +1,16 @@
&l4_abe { /* 0x40100000 */
- compatible = "ti,omap5-l4-abe", "simple-bus";
+ compatible = "ti,omap5-l4-abe", "simple-pm-bus";
reg = <0x40100000 0x400>,
<0x40100400 0x400>;
reg-names = "la", "ap";
+ power-domains = <&prm_abe>;
+ /* OMAP5_L4_ABE_CLKCTRL is read-only */
#address-cells = <1>;
#size-cells = <1>;
ranges = <0x00000000 0x40100000 0x100000>, /* segment 0 */
<0x49000000 0x49000000 0x100000>;
segment@0 { /* 0x40100000 */
- compatible = "simple-bus";
+ compatible = "simple-pm-bus";
#address-cells = <1>;
#size-cells = <1>;
ranges =
diff --git a/arch/arm/boot/dts/omap5.dtsi b/arch/arm/boot/dts/omap5.dtsi
--- a/arch/arm/boot/dts/omap5.dtsi
+++ b/arch/arm/boot/dts/omap5.dtsi
@@ -563,6 +563,12 @@ prm_dsp: prm@400 {
#reset-cells = <1>;
};
+ prm_abe: prm@500 {
+ compatible = "ti,omap5-prm-inst", "ti,omap-prm-inst";
+ reg = <0x500 0x100>;
+ #power-domain-cells = <0>;
+ };
+
prm_core: prm@700 {
compatible = "ti,omap5-prm-inst", "ti,omap-prm-inst";
reg = <0x700 0x100>;
diff --git a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
--- a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
@@ -124,21 +124,6 @@ static struct omap_hwmod_class omap44xx_l4_hwmod_class = {
.name = "l4",
};
-/* l4_abe */
-static struct omap_hwmod omap44xx_l4_abe_hwmod = {
- .name = "l4_abe",
- .class = &omap44xx_l4_hwmod_class,
- .clkdm_name = "abe_clkdm",
- .prcm = {
- .omap4 = {
- .clkctrl_offs = OMAP4_CM1_ABE_L4ABE_CLKCTRL_OFFSET,
- .context_offs = OMAP4_RM_ABE_AESS_CONTEXT_OFFSET,
- .lostcontext_mask = OMAP4430_LOSTMEM_AESSMEM_MASK,
- .flags = HWMOD_OMAP4_NO_CONTEXT_LOSS_BIT,
- },
- },
-};
-
/* l4_cfg */
static struct omap_hwmod omap44xx_l4_cfg_hwmod = {
.name = "l4_cfg",
@@ -1007,22 +992,6 @@ static struct omap_hwmod_ocp_if omap44xx_l4_cfg__l3_main_3 = {
.user = OCP_USER_MPU | OCP_USER_SDMA,
};
-/* l3_main_1 -> l4_abe */
-static struct omap_hwmod_ocp_if omap44xx_l3_main_1__l4_abe = {
- .master = &omap44xx_l3_main_1_hwmod,
- .slave = &omap44xx_l4_abe_hwmod,
- .clk = "l3_div_ck",
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* mpu -> l4_abe */
-static struct omap_hwmod_ocp_if omap44xx_mpu__l4_abe = {
- .master = &omap44xx_mpu_hwmod,
- .slave = &omap44xx_l4_abe_hwmod,
- .clk = "ocp_abe_iclk",
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
/* l3_main_1 -> l4_cfg */
static struct omap_hwmod_ocp_if omap44xx_l3_main_1__l4_cfg = {
.master = &omap44xx_l3_main_1_hwmod,
@@ -1266,8 +1235,6 @@ static struct omap_hwmod_ocp_if *omap44xx_hwmod_ocp_ifs[] __initdata = {
&omap44xx_l3_main_1__l3_main_3,
&omap44xx_l3_main_2__l3_main_3,
&omap44xx_l4_cfg__l3_main_3,
- &omap44xx_l3_main_1__l4_abe,
- &omap44xx_mpu__l4_abe,
&omap44xx_l3_main_1__l4_cfg,
&omap44xx_l3_main_2__l4_per,
&omap44xx_l4_cfg__l4_wkup,
diff --git a/arch/arm/mach-omap2/omap_hwmod_54xx_data.c b/arch/arm/mach-omap2/omap_hwmod_54xx_data.c
--- a/arch/arm/mach-omap2/omap_hwmod_54xx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_54xx_data.c
@@ -121,19 +121,6 @@ static struct omap_hwmod_class omap54xx_l4_hwmod_class = {
.name = "l4",
};
-/* l4_abe */
-static struct omap_hwmod omap54xx_l4_abe_hwmod = {
- .name = "l4_abe",
- .class = &omap54xx_l4_hwmod_class,
- .clkdm_name = "abe_clkdm",
- .prcm = {
- .omap4 = {
- .clkctrl_offs = OMAP54XX_CM_ABE_L4_ABE_CLKCTRL_OFFSET,
- .flags = HWMOD_OMAP4_NO_CONTEXT_LOSS_BIT,
- },
- },
-};
-
/* l4_cfg */
static struct omap_hwmod omap54xx_l4_cfg_hwmod = {
.name = "l4_cfg",
@@ -618,22 +605,6 @@ static struct omap_hwmod_ocp_if omap54xx_l4_cfg__l3_main_3 = {
.user = OCP_USER_MPU | OCP_USER_SDMA,
};
-/* l3_main_1 -> l4_abe */
-static struct omap_hwmod_ocp_if omap54xx_l3_main_1__l4_abe = {
- .master = &omap54xx_l3_main_1_hwmod,
- .slave = &omap54xx_l4_abe_hwmod,
- .clk = "abe_iclk",
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* mpu -> l4_abe */
-static struct omap_hwmod_ocp_if omap54xx_mpu__l4_abe = {
- .master = &omap54xx_mpu_hwmod,
- .slave = &omap54xx_l4_abe_hwmod,
- .clk = "abe_iclk",
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
/* l3_main_1 -> l4_cfg */
static struct omap_hwmod_ocp_if omap54xx_l3_main_1__l4_cfg = {
.master = &omap54xx_l3_main_1_hwmod,
@@ -741,8 +712,6 @@ static struct omap_hwmod_ocp_if *omap54xx_hwmod_ocp_ifs[] __initdata = {
&omap54xx_l3_main_1__l3_main_3,
&omap54xx_l3_main_2__l3_main_3,
&omap54xx_l4_cfg__l3_main_3,
- &omap54xx_l3_main_1__l4_abe,
- &omap54xx_mpu__l4_abe,
&omap54xx_l3_main_1__l4_cfg,
&omap54xx_l3_main_2__l4_per,
&omap54xx_l3_main_1__l4_wkup,
--
2.26.2
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [PATCH 5/6] ARM: dts: Configure am3 and am4 sgx for genpd and drop platform data
From: Tony Lindgren @ 2020-05-20 21:13 UTC (permalink / raw)
To: linux-omap
Cc: Rob Herring, devicetree, linux-kernel, Andrew F . Davis,
Tero Kristo, Santosh Shilimkar, Suman Anna, linux-arm-kernel
In-Reply-To: <20200520211334.61814-1-tony@atomide.com>
We can power off the SGX power domain when not in use when we configure
it for genpd. And with that change, we can now also drop the old unused
legacy platform data.
Signed-off-by: Tony Lindgren <tony@atomide.com>
---
arch/arm/boot/dts/am33xx.dtsi | 2 +
arch/arm/boot/dts/am4372.dtsi | 2 +
.../omap_hwmod_33xx_43xx_interconnect_data.c | 16 --------
.../omap_hwmod_33xx_43xx_ipblock_data.c | 40 -------------------
arch/arm/mach-omap2/omap_hwmod_33xx_data.c | 2 -
arch/arm/mach-omap2/omap_hwmod_43xx_data.c | 2 -
6 files changed, 4 insertions(+), 60 deletions(-)
diff --git a/arch/arm/boot/dts/am33xx.dtsi b/arch/arm/boot/dts/am33xx.dtsi
--- a/arch/arm/boot/dts/am33xx.dtsi
+++ b/arch/arm/boot/dts/am33xx.dtsi
@@ -577,6 +577,7 @@ target-module@56000000 {
<SYSC_IDLE_SMART>;
clocks = <&gfx_l3_clkctrl AM3_GFX_L3_GFX_CLKCTRL 0>;
clock-names = "fck";
+ power-domains = <&prm_gfx>;
resets = <&prm_gfx 0>;
reset-names = "rstctrl";
#address-cells = <1>;
@@ -616,6 +617,7 @@ prm_device: prm@f00 {
prm_gfx: prm@1100 {
compatible = "ti,am3-prm-inst", "ti,omap-prm-inst";
reg = <0x1100 0x100>;
+ #power-domain-cells = <0>;
#reset-cells = <1>;
};
};
diff --git a/arch/arm/boot/dts/am4372.dtsi b/arch/arm/boot/dts/am4372.dtsi
--- a/arch/arm/boot/dts/am4372.dtsi
+++ b/arch/arm/boot/dts/am4372.dtsi
@@ -516,6 +516,7 @@ target-module@56000000 {
<SYSC_IDLE_SMART>;
clocks = <&gfx_l3_clkctrl AM4_GFX_L3_GFX_CLKCTRL 0>;
clock-names = "fck";
+ power-domains = <&prm_gfx>;
resets = <&prm_gfx 0>;
reset-names = "rstctrl";
#address-cells = <1>;
@@ -532,6 +533,7 @@ &prcm {
prm_gfx: prm@400 {
compatible = "ti,am4-prm-inst", "ti,omap-prm-inst";
reg = <0x400 0x100>;
+ #power-domain-cells = <0>;
#reset-cells = <1>;
};
diff --git a/arch/arm/mach-omap2/omap_hwmod_33xx_43xx_interconnect_data.c b/arch/arm/mach-omap2/omap_hwmod_33xx_43xx_interconnect_data.c
--- a/arch/arm/mach-omap2/omap_hwmod_33xx_43xx_interconnect_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_33xx_43xx_interconnect_data.c
@@ -74,22 +74,6 @@ struct omap_hwmod_ocp_if am33xx_l3_s__l3_main = {
.user = OCP_USER_MPU | OCP_USER_SDMA,
};
-/* gfx -> l3 main */
-struct omap_hwmod_ocp_if am33xx_gfx__l3_main = {
- .master = &am33xx_gfx_hwmod,
- .slave = &am33xx_l3_main_hwmod,
- .clk = "dpll_core_m4_ck",
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l3 main -> gfx */
-struct omap_hwmod_ocp_if am33xx_l3_main__gfx = {
- .master = &am33xx_l3_main_hwmod,
- .slave = &am33xx_gfx_hwmod,
- .clk = "dpll_core_m4_ck",
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
/* l4 wkup -> rtc */
struct omap_hwmod_ocp_if am33xx_l4_wkup__rtc = {
.master = &am33xx_l4_wkup_hwmod,
diff --git a/arch/arm/mach-omap2/omap_hwmod_33xx_43xx_ipblock_data.c b/arch/arm/mach-omap2/omap_hwmod_33xx_43xx_ipblock_data.c
--- a/arch/arm/mach-omap2/omap_hwmod_33xx_43xx_ipblock_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_33xx_43xx_ipblock_data.c
@@ -133,30 +133,6 @@ struct omap_hwmod_class am33xx_wkup_m3_hwmod_class = {
.name = "wkup_m3",
};
-/* gfx */
-/* Pseudo hwmod for reset control purpose only */
-static struct omap_hwmod_class am33xx_gfx_hwmod_class = {
- .name = "gfx",
-};
-
-static struct omap_hwmod_rst_info am33xx_gfx_resets[] = {
- { .name = "gfx", .rst_shift = 0, .st_shift = 0},
-};
-
-struct omap_hwmod am33xx_gfx_hwmod = {
- .name = "gfx",
- .class = &am33xx_gfx_hwmod_class,
- .clkdm_name = "gfx_l3_clkdm",
- .main_clk = "gfx_fck_div_ck",
- .prcm = {
- .omap4 = {
- .modulemode = MODULEMODE_SWCTRL,
- },
- },
- .rst_lines = am33xx_gfx_resets,
- .rst_lines_cnt = ARRAY_SIZE(am33xx_gfx_resets),
-};
-
/*
* 'prcm' class
* power and reset manager (whole prcm infrastructure)
@@ -379,22 +355,14 @@ static void omap_hwmod_am33xx_clkctrl(void)
CLKCTRL(am33xx_l4_ls_hwmod, AM33XX_CM_PER_L4LS_CLKCTRL_OFFSET);
CLKCTRL(am33xx_l4_wkup_hwmod, AM33XX_CM_WKUP_L4WKUP_CLKCTRL_OFFSET);
CLKCTRL(am33xx_l3_main_hwmod, AM33XX_CM_PER_L3_CLKCTRL_OFFSET);
- CLKCTRL(am33xx_gfx_hwmod, AM33XX_CM_GFX_GFX_CLKCTRL_OFFSET);
CLKCTRL(am33xx_mpu_hwmod , AM33XX_CM_MPU_MPU_CLKCTRL_OFFSET);
CLKCTRL(am33xx_l3_instr_hwmod , AM33XX_CM_PER_L3_INSTR_CLKCTRL_OFFSET);
CLKCTRL(am33xx_ocmcram_hwmod , AM33XX_CM_PER_OCMCRAM_CLKCTRL_OFFSET);
}
-static void omap_hwmod_am33xx_rst(void)
-{
- RSTCTRL(am33xx_gfx_hwmod, AM33XX_RM_GFX_RSTCTRL_OFFSET);
- RSTST(am33xx_gfx_hwmod, AM33XX_RM_GFX_RSTST_OFFSET);
-}
-
void omap_hwmod_am33xx_reg(void)
{
omap_hwmod_am33xx_clkctrl();
- omap_hwmod_am33xx_rst();
}
static void omap_hwmod_am43xx_clkctrl(void)
@@ -410,20 +378,12 @@ static void omap_hwmod_am43xx_clkctrl(void)
CLKCTRL(am33xx_l4_ls_hwmod, AM43XX_CM_PER_L4LS_CLKCTRL_OFFSET);
CLKCTRL(am33xx_l4_wkup_hwmod, AM43XX_CM_WKUP_L4WKUP_CLKCTRL_OFFSET);
CLKCTRL(am33xx_l3_main_hwmod, AM43XX_CM_PER_L3_CLKCTRL_OFFSET);
- CLKCTRL(am33xx_gfx_hwmod, AM43XX_CM_GFX_GFX_CLKCTRL_OFFSET);
CLKCTRL(am33xx_mpu_hwmod , AM43XX_CM_MPU_MPU_CLKCTRL_OFFSET);
CLKCTRL(am33xx_l3_instr_hwmod , AM43XX_CM_PER_L3_INSTR_CLKCTRL_OFFSET);
CLKCTRL(am33xx_ocmcram_hwmod , AM43XX_CM_PER_OCMCRAM_CLKCTRL_OFFSET);
}
-static void omap_hwmod_am43xx_rst(void)
-{
- RSTCTRL(am33xx_gfx_hwmod, AM43XX_RM_GFX_RSTCTRL_OFFSET);
- RSTST(am33xx_gfx_hwmod, AM43XX_RM_GFX_RSTST_OFFSET);
-}
-
void omap_hwmod_am43xx_reg(void)
{
omap_hwmod_am43xx_clkctrl();
- omap_hwmod_am43xx_rst();
}
diff --git a/arch/arm/mach-omap2/omap_hwmod_33xx_data.c b/arch/arm/mach-omap2/omap_hwmod_33xx_data.c
--- a/arch/arm/mach-omap2/omap_hwmod_33xx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_33xx_data.c
@@ -282,10 +282,8 @@ static struct omap_hwmod_ocp_if *am33xx_hwmod_ocp_ifs[] __initdata = {
&am33xx_l3_main__l4_hs,
&am33xx_l3_main__l3_s,
&am33xx_l3_main__l3_instr,
- &am33xx_l3_main__gfx,
&am33xx_l3_s__l3_main,
&am33xx_wkup_m3__l4_wkup,
- &am33xx_gfx__l3_main,
&am33xx_l3_main__debugss,
&am33xx_l4_wkup__wkup_m3,
&am33xx_l4_wkup__control,
diff --git a/arch/arm/mach-omap2/omap_hwmod_43xx_data.c b/arch/arm/mach-omap2/omap_hwmod_43xx_data.c
--- a/arch/arm/mach-omap2/omap_hwmod_43xx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_43xx_data.c
@@ -243,11 +243,9 @@ static struct omap_hwmod_ocp_if *am43xx_hwmod_ocp_ifs[] __initdata = {
&am43xx_l3_main__l4_hs,
&am33xx_l3_main__l3_s,
&am33xx_l3_main__l3_instr,
- &am33xx_l3_main__gfx,
&am33xx_l3_s__l3_main,
&am43xx_l3_main__emif,
&am43xx_wkup_m3__l4_wkup,
- &am33xx_gfx__l3_main,
&am43xx_l4_wkup__wkup_m3,
&am43xx_l4_wkup__control,
&am43xx_l4_wkup__smartreflex0,
--
2.26.2
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [PATCH 4/6] soc: ti: omap-prm: Configure omap4 and 5 l4_abe power domain
From: Tony Lindgren @ 2020-05-20 21:13 UTC (permalink / raw)
To: linux-omap
Cc: Rob Herring, devicetree, linux-kernel, Andrew F . Davis,
Tero Kristo, Santosh Shilimkar, Suman Anna, linux-arm-kernel
In-Reply-To: <20200520211334.61814-1-tony@atomide.com>
Let's add omap4 and 5 l4_abe interconnect instance for the power
domain.
Signed-off-by: Tony Lindgren <tony@atomide.com>
---
drivers/soc/ti/omap_prm.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/drivers/soc/ti/omap_prm.c b/drivers/soc/ti/omap_prm.c
--- a/drivers/soc/ti/omap_prm.c
+++ b/drivers/soc/ti/omap_prm.c
@@ -145,6 +145,10 @@ static const struct omap_rst_map rst_map_012[] = {
static const struct omap_prm_data omap4_prm_data[] = {
{ .name = "tesla", .base = 0x4a306400, .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_01 },
+ {
+ .name = "abe", .base = 0x4a306500,
+ .pwrstctrl = 0, .pwrstst = 0x4, .dmap = &omap_prm_all,
+ },
{ .name = "core", .base = 0x4a306700, .rstctrl = 0x210, .rstst = 0x214, .clkdm_name = "ducati", .rstmap = rst_map_012 },
{ .name = "ivahd", .base = 0x4a306f00, .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_012 },
{ .name = "device", .base = 0x4a307b00, .rstctrl = 0x0, .rstst = 0x4, .rstmap = rst_map_01, .flags = OMAP_PRM_HAS_RSTCTRL | OMAP_PRM_HAS_NO_CLKDM },
@@ -153,6 +157,10 @@ static const struct omap_prm_data omap4_prm_data[] = {
static const struct omap_prm_data omap5_prm_data[] = {
{ .name = "dsp", .base = 0x4ae06400, .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_01 },
+ {
+ .name = "abe", .base = 0x4ae06500,
+ .pwrstctrl = 0, .pwrstst = 0x4, .dmap = &omap_prm_nooff,
+ },
{ .name = "core", .base = 0x4ae06700, .rstctrl = 0x210, .rstst = 0x214, .clkdm_name = "ipu", .rstmap = rst_map_012 },
{ .name = "iva", .base = 0x4ae07200, .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_012 },
{ .name = "device", .base = 0x4ae07c00, .rstctrl = 0x0, .rstst = 0x4, .rstmap = rst_map_01, .flags = OMAP_PRM_HAS_RSTCTRL | OMAP_PRM_HAS_NO_CLKDM },
--
2.26.2
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [PATCH 2/6] soc: ti: omap-prm: Add basic power domain support
From: Tony Lindgren @ 2020-05-20 21:13 UTC (permalink / raw)
To: linux-omap
Cc: Rob Herring, devicetree, linux-kernel, Andrew F . Davis,
Tero Kristo, Santosh Shilimkar, Suman Anna, linux-arm-kernel
In-Reply-To: <20200520211334.61814-1-tony@atomide.com>
The PRM controller has currently only support for resets while the power
domains are still handled in the platform code.
Let's add basic power domain support to enable and disable a PRM
controlled power domain if configured in the devicetree. This can be
used for various hardware accelerators, and interconnect instances.
Further support can be added later on as needed for runtime configuration
based on domain-idle-states.
Signed-off-by: Tony Lindgren <tony@atomide.com>
---
arch/arm/mach-omap2/Kconfig | 1 +
drivers/soc/ti/omap_prm.c | 261 +++++++++++++++++++++++++++++++++++-
2 files changed, 261 insertions(+), 1 deletion(-)
diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig
--- a/arch/arm/mach-omap2/Kconfig
+++ b/arch/arm/mach-omap2/Kconfig
@@ -7,6 +7,7 @@ config ARCH_OMAP2
depends on ARCH_MULTI_V6
select ARCH_OMAP2PLUS
select CPU_V6
+ select PM_GENERIC_DOMAINS if PM
select SOC_HAS_OMAP2_SDRC
config ARCH_OMAP3
diff --git a/drivers/soc/ti/omap_prm.c b/drivers/soc/ti/omap_prm.c
--- a/drivers/soc/ti/omap_prm.c
+++ b/drivers/soc/ti/omap_prm.c
@@ -10,14 +10,39 @@
#include <linux/device.h>
#include <linux/io.h>
#include <linux/iopoll.h>
+#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
+#include <linux/pm_domain.h>
#include <linux/reset-controller.h>
#include <linux/delay.h>
#include <linux/platform_data/ti-prm.h>
+enum omap_prm_domain_mode {
+ OMAP_PRMD_OFF,
+ OMAP_PRMD_RETENTION,
+ OMAP_PRMD_ON_INACTIVE,
+ OMAP_PRMD_ON_ACTIVE,
+};
+
+struct omap_prm_domain_map {
+ unsigned int usable_modes; /* Mask of hardware supported modes */
+ unsigned long statechange:1; /* Optional low-power state change */
+ unsigned long logicretstate:1; /* Optional logic off mode */
+};
+
+struct omap_prm_domain {
+ struct device *dev;
+ struct omap_prm *prm;
+ struct generic_pm_domain pd;
+ u16 pwrstctrl;
+ u16 pwrstst;
+ const struct omap_prm_domain_map *cap;
+ u32 pwrstctrl_saved;
+};
+
struct omap_rst_map {
s8 rst;
s8 st;
@@ -27,6 +52,9 @@ struct omap_prm_data {
u32 base;
const char *name;
const char *clkdm_name;
+ u16 pwrstctrl;
+ u16 pwrstst;
+ const struct omap_prm_domain_map *dmap;
u16 rstctrl;
u16 rstst;
const struct omap_rst_map *rstmap;
@@ -36,6 +64,7 @@ struct omap_prm_data {
struct omap_prm {
const struct omap_prm_data *data;
void __iomem *base;
+ struct omap_prm_domain *prmd;
};
struct omap_reset_data {
@@ -47,6 +76,7 @@ struct omap_reset_data {
struct device *dev;
};
+#define genpd_to_prm_domain(gpd) container_of(gpd, struct omap_prm_domain, pd)
#define to_omap_reset_data(p) container_of((p), struct omap_reset_data, rcdev)
#define OMAP_MAX_RESETS 8
@@ -58,6 +88,43 @@ struct omap_reset_data {
#define OMAP_PRM_HAS_RESETS (OMAP_PRM_HAS_RSTCTRL | OMAP_PRM_HAS_RSTST)
+#define PRM_STATE_MAX_WAIT 10000
+#define PRM_LOGICRETSTATE BIT(2)
+#define PRM_LOWPOWERSTATECHANGE BIT(4)
+#define PRM_POWERSTATE_MASK OMAP_PRMD_ON_ACTIVE
+
+#define PRM_ST_INTRANSITION BIT(20)
+
+static const struct __maybe_unused
+omap_prm_domain_map omap_prm_all = {
+ .usable_modes = BIT(OMAP_PRMD_ON_ACTIVE) | BIT(OMAP_PRMD_ON_INACTIVE) |
+ BIT(OMAP_PRMD_RETENTION) | BIT(OMAP_PRMD_OFF),
+ .statechange = 1,
+ .logicretstate = 1,
+};
+
+static const struct __maybe_unused
+omap_prm_domain_map omap_prm_noinact = {
+ .usable_modes = BIT(OMAP_PRMD_ON_ACTIVE) | BIT(OMAP_PRMD_RETENTION) |
+ BIT(OMAP_PRMD_OFF),
+ .statechange = 1,
+ .logicretstate = 1,
+};
+
+static const struct __maybe_unused
+omap_prm_domain_map omap_prm_nooff = {
+ .usable_modes = BIT(OMAP_PRMD_ON_ACTIVE) | BIT(OMAP_PRMD_ON_INACTIVE) |
+ BIT(OMAP_PRMD_RETENTION),
+ .statechange = 1,
+ .logicretstate = 1,
+};
+
+static const struct __maybe_unused
+omap_prm_domain_map omap_prm_onoff_noauto = {
+ .usable_modes = BIT(OMAP_PRMD_ON_ACTIVE) | BIT(OMAP_PRMD_OFF),
+ .statechange = 1,
+};
+
static const struct omap_rst_map rst_map_0[] = {
{ .rst = 0, .st = 0 },
{ .rst = -1 },
@@ -151,6 +218,183 @@ static const struct of_device_id omap_prm_id_table[] = {
{ },
};
+#ifdef DEBUG
+static void omap_prm_domain_show_state(struct omap_prm_domain *prmd,
+ const char *desc)
+{
+ dev_dbg(prmd->dev, "%s %s: %08x/%08x\n",
+ prmd->pd.name, desc,
+ readl_relaxed(prmd->prm->base + prmd->pwrstctrl),
+ readl_relaxed(prmd->prm->base + prmd->pwrstst));
+}
+#else
+static inline void omap_prm_domain_show_state(struct omap_prm_domain *prmd,
+ const char *desc)
+{
+}
+#endif
+
+static int omap_prm_domain_power_on(struct generic_pm_domain *domain)
+{
+ struct omap_prm_domain *prmd;
+ int ret;
+ u32 v;
+
+ prmd = genpd_to_prm_domain(domain);
+ if (!prmd->cap)
+ return 0;
+
+ omap_prm_domain_show_state(prmd, "on: previous state");
+
+ if (prmd->pwrstctrl_saved)
+ v = prmd->pwrstctrl_saved;
+ else
+ v = readl_relaxed(prmd->prm->base + prmd->pwrstctrl);
+
+ writel_relaxed(v | OMAP_PRMD_ON_ACTIVE,
+ prmd->prm->base + prmd->pwrstctrl);
+
+ /* wait for the transition bit to get cleared */
+ ret = readl_relaxed_poll_timeout(prmd->prm->base + prmd->pwrstst,
+ v, !(v & PRM_ST_INTRANSITION), 1,
+ PRM_STATE_MAX_WAIT);
+ if (ret)
+ dev_err(prmd->dev, "%s: %s timed out\n",
+ prmd->pd.name, __func__);
+
+ omap_prm_domain_show_state(prmd, "on: new state");
+
+ return ret;
+}
+
+/* No need to check for holes in the mask for the lowest mode */
+static int omap_prm_domain_find_lowest(struct omap_prm_domain *prmd)
+{
+ return __ffs(prmd->cap->usable_modes);
+}
+
+static int omap_prm_domain_power_off(struct generic_pm_domain *domain)
+{
+ struct omap_prm_domain *prmd;
+ int ret;
+ u32 v;
+
+ prmd = genpd_to_prm_domain(domain);
+ if (!prmd->cap)
+ return 0;
+
+ omap_prm_domain_show_state(prmd, "off: previous state");
+
+ v = readl_relaxed(prmd->prm->base + prmd->pwrstctrl);
+ prmd->pwrstctrl_saved = v;
+
+ v &= ~PRM_POWERSTATE_MASK;
+ v |= omap_prm_domain_find_lowest(prmd);
+
+ if (prmd->cap->statechange)
+ v |= PRM_LOWPOWERSTATECHANGE;
+ if (prmd->cap->logicretstate)
+ v &= ~PRM_LOGICRETSTATE;
+ else
+ v |= PRM_LOGICRETSTATE;
+
+ writel_relaxed(v, prmd->prm->base + prmd->pwrstctrl);
+
+ /* wait for the transition bit to get cleared */
+ ret = readl_relaxed_poll_timeout(prmd->prm->base + prmd->pwrstst,
+ v, !(v & PRM_ST_INTRANSITION), 1,
+ PRM_STATE_MAX_WAIT);
+ if (ret)
+ dev_warn(prmd->dev, "%s: %s timed out\n",
+ __func__, prmd->pd.name);
+
+ omap_prm_domain_show_state(prmd, "off: new state");
+
+ return 0;
+}
+
+static int omap_prm_domain_attach_dev(struct generic_pm_domain *domain,
+ struct device *dev)
+{
+ struct generic_pm_domain_data *genpd_data;
+ struct of_phandle_args pd_args;
+ struct omap_prm_domain *prmd;
+ struct device_node *np;
+ int ret;
+
+ prmd = genpd_to_prm_domain(domain);
+ np = dev->of_node;
+
+ ret = of_parse_phandle_with_args(np, "power-domains",
+ "#power-domain-cells", 0, &pd_args);
+ if (ret < 0)
+ return ret;
+
+ if (pd_args.args_count != 0)
+ dev_warn(dev, "%s: unusupported #power-domain-cells: %i\n",
+ prmd->pd.name, pd_args.args_count);
+
+ genpd_data = dev_gpd_data(dev);
+ genpd_data->data = NULL;
+
+ return 0;
+}
+
+static void omap_prm_domain_detach_dev(struct generic_pm_domain *domain,
+ struct device *dev)
+{
+ struct generic_pm_domain_data *genpd_data;
+ struct omap_prm_domain *prmd;
+
+ prmd = genpd_to_prm_domain(domain);
+
+ genpd_data = dev_gpd_data(dev);
+ genpd_data->data = NULL;
+}
+
+static int omap_prm_domain_init(struct device *dev, struct omap_prm *prm)
+{
+ struct omap_prm_domain *prmd;
+ struct device_node *np = dev->of_node;
+ const struct omap_prm_data *data;
+ const char *name;
+ int error;
+
+ if (!of_find_property(dev->of_node, "#power-domain-cells", NULL))
+ return 0;
+
+ of_node_put(dev->of_node);
+
+ prmd = devm_kzalloc(dev, sizeof(*prmd), GFP_KERNEL);
+ if (!prmd)
+ return -ENOMEM;
+
+ data = prm->data;
+ name = devm_kasprintf(dev, GFP_KERNEL, "prm_%s",
+ data->name);
+
+ prmd->dev = dev;
+ prmd->prm = prm;
+ prmd->cap = prmd->prm->data->dmap;
+ prmd->pwrstctrl = prmd->prm->data->pwrstctrl;
+ prmd->pwrstst = prmd->prm->data->pwrstst;
+
+ prmd->pd.name = name;
+ prmd->pd.power_on = omap_prm_domain_power_on;
+ prmd->pd.power_off = omap_prm_domain_power_off;
+ prmd->pd.attach_dev = omap_prm_domain_attach_dev;
+ prmd->pd.detach_dev = omap_prm_domain_detach_dev;
+
+ pm_genpd_init(&prmd->pd, NULL, true);
+ error = of_genpd_add_provider_simple(np, &prmd->pd);
+ if (error)
+ pm_genpd_remove(&prmd->pd);
+ else
+ prm->prmd = prmd;
+
+ return error;
+}
+
static bool _is_valid_reset(struct omap_reset_data *reset, unsigned long id)
{
if (reset->mask & BIT(id))
@@ -351,6 +595,7 @@ static int omap_prm_probe(struct platform_device *pdev)
const struct omap_prm_data *data;
struct omap_prm *prm;
const struct of_device_id *match;
+ int ret;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
@@ -378,7 +623,21 @@ static int omap_prm_probe(struct platform_device *pdev)
if (IS_ERR(prm->base))
return PTR_ERR(prm->base);
- return omap_prm_reset_init(pdev, prm);
+ ret = omap_prm_domain_init(&pdev->dev, prm);
+ if (ret)
+ return ret;
+
+ ret = omap_prm_reset_init(pdev, prm);
+ if (ret)
+ goto err_domain;
+
+ return 0;
+
+err_domain:
+ of_genpd_del_provider(pdev->dev.of_node);
+ pm_genpd_remove(&prm->prmd->pd);
+
+ return ret;
}
static struct platform_driver omap_prm_driver = {
--
2.26.2
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [PATCH 3/6] soc: ti: omap-prm: Configure sgx power domain for am3 and am4
From: Tony Lindgren @ 2020-05-20 21:13 UTC (permalink / raw)
To: linux-omap
Cc: Rob Herring, devicetree, linux-kernel, Andrew F . Davis,
Tero Kristo, Santosh Shilimkar, Suman Anna, linux-arm-kernel
In-Reply-To: <20200520211334.61814-1-tony@atomide.com>
Let's configure only sgx power domain for am3 and am4 to start with.
Signed-off-by: Tony Lindgren <tony@atomide.com>
---
drivers/soc/ti/omap_prm.c | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/drivers/soc/ti/omap_prm.c b/drivers/soc/ti/omap_prm.c
--- a/drivers/soc/ti/omap_prm.c
+++ b/drivers/soc/ti/omap_prm.c
@@ -186,7 +186,11 @@ static const struct omap_prm_data am3_prm_data[] = {
{ .name = "per", .base = 0x44e00c00, .rstctrl = 0x0, .rstmap = am3_per_rst_map, .flags = OMAP_PRM_HAS_RSTCTRL, .clkdm_name = "pruss_ocp" },
{ .name = "wkup", .base = 0x44e00d00, .rstctrl = 0x0, .rstst = 0xc, .rstmap = am3_wkup_rst_map, .flags = OMAP_PRM_HAS_RSTCTRL | OMAP_PRM_HAS_NO_CLKDM },
{ .name = "device", .base = 0x44e00f00, .rstctrl = 0x0, .rstst = 0x8, .rstmap = rst_map_01, .flags = OMAP_PRM_HAS_RSTCTRL | OMAP_PRM_HAS_NO_CLKDM },
- { .name = "gfx", .base = 0x44e01100, .rstctrl = 0x4, .rstst = 0x14, .rstmap = rst_map_0, .clkdm_name = "gfx_l3" },
+ {
+ .name = "gfx", .base = 0x44e01100,
+ .pwrstctrl = 0, .pwrstst = 0x10, .dmap = &omap_prm_noinact,
+ .rstctrl = 0x4, .rstst = 0x14, .rstmap = rst_map_0, .clkdm_name = "gfx_l3",
+ },
{ },
};
@@ -202,7 +206,11 @@ static const struct omap_rst_map am4_device_rst_map[] = {
};
static const struct omap_prm_data am4_prm_data[] = {
- { .name = "gfx", .base = 0x44df0400, .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_0, .clkdm_name = "gfx_l3" },
+ {
+ .name = "gfx", .base = 0x44df0400,
+ .pwrstctrl = 0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto,
+ .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_0, .clkdm_name = "gfx_l3",
+ },
{ .name = "per", .base = 0x44df0800, .rstctrl = 0x10, .rstst = 0x14, .rstmap = am4_per_rst_map, .clkdm_name = "pruss_ocp" },
{ .name = "wkup", .base = 0x44df2000, .rstctrl = 0x10, .rstst = 0x14, .rstmap = am3_wkup_rst_map, .flags = OMAP_PRM_HAS_NO_CLKDM },
{ .name = "device", .base = 0x44df4000, .rstctrl = 0x0, .rstst = 0x4, .rstmap = am4_device_rst_map, .flags = OMAP_PRM_HAS_RSTCTRL | OMAP_PRM_HAS_NO_CLKDM },
--
2.26.2
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [PATCHv2 0/6] Add initial genpd support for omap PRM driver
From: Tony Lindgren @ 2020-05-20 21:13 UTC (permalink / raw)
To: linux-omap
Cc: Rob Herring, devicetree, linux-kernel, Andrew F . Davis,
Tero Kristo, Santosh Shilimkar, Suman Anna, linux-arm-kernel
Hi all,
Heris v2 set of patches to add genpd support to the PRM (Power and Reset
Module) driver.
Initially we just add one hardware accelerator power domain for sgx,
and one interconnect instance for l4_abe. The rest of the SoC specific
domain data is probably best added one SoC at a time based on generated
data.
Regards,
Tony
Changes since v1:
- Dropped clocks from the binding and prm driver as there's no need
for them as pointed out by Tero
- Add checking for domain transition bit in pwrstst register as
pointed out by Tero
- Add omap_prm_domain_show_state() for CONFIG_DEBUG
Tony Lindgren (6):
dt-bindings: omap: Update PRM binding for genpd
soc: ti: omap-prm: Add basic power domain support
soc: ti: omap-prm: Configure sgx power domain for am3 and am4
soc: ti: omap-prm: Configure omap4 and 5 l4_abe power domain
ARM: dts: Configure am3 and am4 sgx for genpd and drop platform data
ARM: dts: Configure omap4 and 5 l4_abe for genpd and drop platform
data
.../devicetree/bindings/arm/omap/prm-inst.txt | 2 +
arch/arm/boot/dts/am33xx.dtsi | 2 +
arch/arm/boot/dts/am4372.dtsi | 2 +
arch/arm/boot/dts/omap4-l4-abe.dtsi | 6 +-
arch/arm/boot/dts/omap4.dtsi | 6 +
arch/arm/boot/dts/omap5-l4-abe.dtsi | 6 +-
arch/arm/boot/dts/omap5.dtsi | 6 +
arch/arm/mach-omap2/Kconfig | 1 +
.../omap_hwmod_33xx_43xx_interconnect_data.c | 16 -
.../omap_hwmod_33xx_43xx_ipblock_data.c | 40 ---
arch/arm/mach-omap2/omap_hwmod_33xx_data.c | 2 -
arch/arm/mach-omap2/omap_hwmod_43xx_data.c | 2 -
arch/arm/mach-omap2/omap_hwmod_44xx_data.c | 33 --
arch/arm/mach-omap2/omap_hwmod_54xx_data.c | 31 --
drivers/soc/ti/omap_prm.c | 281 +++++++++++++++++-
15 files changed, 305 insertions(+), 131 deletions(-)
--
2.26.2
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [PATCH 1/6] dt-bindings: omap: Update PRM binding for genpd
From: Tony Lindgren @ 2020-05-20 21:13 UTC (permalink / raw)
To: linux-omap
Cc: devicetree, Rob Herring, linux-kernel, Andrew F . Davis,
Tero Kristo, Santosh Shilimkar, Suman Anna, linux-arm-kernel
In-Reply-To: <20200520211334.61814-1-tony@atomide.com>
The PRM (Power and Reset Module) has registers to enable and disable
power domains, so let's update the binding for that.
Cc: devicetree@vger.kernel.org
Cc: Rob Herring <robh@kernel.org>
Signed-off-by: Tony Lindgren <tony@atomide.com>
---
Documentation/devicetree/bindings/arm/omap/prm-inst.txt | 2 ++
1 file changed, 2 insertions(+)
diff --git a/Documentation/devicetree/bindings/arm/omap/prm-inst.txt b/Documentation/devicetree/bindings/arm/omap/prm-inst.txt
--- a/Documentation/devicetree/bindings/arm/omap/prm-inst.txt
+++ b/Documentation/devicetree/bindings/arm/omap/prm-inst.txt
@@ -18,6 +18,7 @@ Required properties:
(base address and length)
Optional properties:
+- #power-domain-cells: Should be 0 if the PRM instance is a power domain.
- #reset-cells: Should be 1 if the PRM instance in question supports resets.
Example:
@@ -25,5 +26,6 @@ Example:
prm_dsp2: prm@1b00 {
compatible = "ti,dra7-prm-inst", "ti,omap-prm-inst";
reg = <0x1b00 0x40>;
+ #power-domain-cells = <0>;
#reset-cells = <1>;
};
--
2.26.2
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH v4 04/14] PCI: cadence: Add support to start link and verify link status
From: Rob Herring @ 2020-05-20 21:06 UTC (permalink / raw)
To: Kishon Vijay Abraham I
Cc: devicetree, Lorenzo Pieralisi, Arnd Bergmann, linux-pci,
linux-kernel, Tom Joseph, Rob Herring, Greg Kroah-Hartman,
Bjorn Helgaas, linux-omap, linux-arm-kernel
In-Reply-To: <20200506151429.12255-5-kishon@ti.com>
On Wed, 6 May 2020 20:44:19 +0530, Kishon Vijay Abraham I wrote:
> Add cdns_pcie_ops to start link and verify link status. The registers
> to start link and to check link status is in Platform specific PCIe
> wrapper. Add support for platform specific drivers to add callback
> functions for the PCIe Cadence core to start link and verify link status.
>
> Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
> ---
> .../pci/controller/cadence/pcie-cadence-ep.c | 8 +++++
> .../controller/cadence/pcie-cadence-host.c | 28 +++++++++++++++++
> drivers/pci/controller/cadence/pcie-cadence.h | 30 +++++++++++++++++++
> 3 files changed, 66 insertions(+)
>
Reviewed-by: Rob Herring <robh@kernel.org>
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH v4 03/14] PCI: cadence: Add support to use custom read and write accessors
From: Rob Herring @ 2020-05-20 21:02 UTC (permalink / raw)
To: Kishon Vijay Abraham I
Cc: devicetree, Lorenzo Pieralisi, Arnd Bergmann, Greg Kroah-Hartman,
linux-kernel, Tom Joseph, Rob Herring, linux-pci, Bjorn Helgaas,
linux-omap, linux-arm-kernel
In-Reply-To: <20200506151429.12255-4-kishon@ti.com>
On Wed, 6 May 2020 20:44:18 +0530, Kishon Vijay Abraham I wrote:
> Add support to use custom read and write accessors. Platforms that
> don't support half word or byte access or any other constraint
> while accessing registers can use this feature to populate custom
> read and write accessors. These custom accessors are used for both
> standard register access and configuration space register access of
> the PCIe host bridge.
>
> Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
> ---
> drivers/pci/controller/cadence/pcie-cadence.h | 107 +++++++++++++++---
> 1 file changed, 94 insertions(+), 13 deletions(-)
>
Reviewed-by: Rob Herring <robh@kernel.org>
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH v4 02/14] linux/kernel.h: Add PTR_ALIGN_DOWN macro
From: Rob Herring @ 2020-05-20 21:00 UTC (permalink / raw)
To: Kishon Vijay Abraham I
Cc: devicetree, Lorenzo Pieralisi, Arnd Bergmann, linux-pci,
linux-kernel, Tom Joseph, Rob Herring, Greg Kroah-Hartman,
Bjorn Helgaas, linux-omap, linux-arm-kernel
In-Reply-To: <20200506151429.12255-3-kishon@ti.com>
On Wed, 6 May 2020 20:44:17 +0530, Kishon Vijay Abraham I wrote:
> Add a macro for aligning down a pointer. This is useful to get an
> aligned register address when a device allows only word access and
> doesn't allow half word or byte access.
>
> Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
> ---
> include/linux/kernel.h | 1 +
> 1 file changed, 1 insertion(+)
>
Acked-by: Rob Herring <robh@kernel.org>
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH v4 01/14] PCI: cadence: Fix cdns_pcie_{host|ep}_setup() error path
From: Rob Herring @ 2020-05-20 20:59 UTC (permalink / raw)
To: Kishon Vijay Abraham I
Cc: devicetree, Lorenzo Pieralisi, Arnd Bergmann, Greg Kroah-Hartman,
linux-kernel, Tom Joseph, Rob Herring, linux-pci, Bjorn Helgaas,
linux-omap, linux-arm-kernel
In-Reply-To: <20200506151429.12255-2-kishon@ti.com>
On Wed, 6 May 2020 20:44:16 +0530, Kishon Vijay Abraham I wrote:
> commit bd22885aa188 ("PCI: cadence: Refactor driver to use as a core
> library") while refactoring the Cadence PCIe driver to be used as
> library, removed pm_runtime_get_sync() from cdns_pcie_ep_setup()
> and cdns_pcie_host_setup() but missed to remove the corresponding
> pm_runtime_put_sync() in the error path. Fix it here.
>
> Fixes: bd22885aa188 ("PCI: cadence: Refactor driver to use as a core library")
> Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
> ---
> drivers/pci/controller/cadence/pcie-cadence-ep.c | 9 ++-------
> drivers/pci/controller/cadence/pcie-cadence-host.c | 6 +-----
> 2 files changed, 3 insertions(+), 12 deletions(-)
>
Reviewed-by: Rob Herring <robh@kernel.org>
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [PATCH] media: cedrus: Add support for VP8 decoding
From: Jernej Skrabec @ 2020-05-20 21:01 UTC (permalink / raw)
To: mripard, paul.kocialkowski
Cc: devel, gregkh, linux-kernel, wens, hverkuil-cisco, mchehab,
linux-arm-kernel, linux-media
VP8 in Cedrus shares same engine as H264.
Note that it seems necessary to call bitstream parsing functions,
to parse frame header, otherwise decoded image is garbage. This is
contrary to what is driver supposed to do. However, values are not
really used, so this might be acceptable. It's possible that bitstream
parsing functions set some internal VPU state, which is later necessary
for proper decoding. Biggest suspect is "VP8 probs update" trigger.
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
drivers/staging/media/sunxi/cedrus/Makefile | 3 +-
drivers/staging/media/sunxi/cedrus/cedrus.c | 8 +
drivers/staging/media/sunxi/cedrus/cedrus.h | 15 +
.../staging/media/sunxi/cedrus/cedrus_dec.c | 5 +
.../staging/media/sunxi/cedrus/cedrus_hw.c | 1 +
.../staging/media/sunxi/cedrus/cedrus_regs.h | 80 ++
.../staging/media/sunxi/cedrus/cedrus_video.c | 9 +
.../staging/media/sunxi/cedrus/cedrus_vp8.c | 699 ++++++++++++++++++
8 files changed, 819 insertions(+), 1 deletion(-)
create mode 100644 drivers/staging/media/sunxi/cedrus/cedrus_vp8.c
diff --git a/drivers/staging/media/sunxi/cedrus/Makefile b/drivers/staging/media/sunxi/cedrus/Makefile
index 1bce49d3e7e2..a647b3690bf8 100644
--- a/drivers/staging/media/sunxi/cedrus/Makefile
+++ b/drivers/staging/media/sunxi/cedrus/Makefile
@@ -2,4 +2,5 @@
obj-$(CONFIG_VIDEO_SUNXI_CEDRUS) += sunxi-cedrus.o
sunxi-cedrus-y = cedrus.o cedrus_video.o cedrus_hw.o cedrus_dec.o \
- cedrus_mpeg2.o cedrus_h264.o cedrus_h265.o
+ cedrus_mpeg2.o cedrus_h264.o cedrus_h265.o \
+ cedrus_vp8.o
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.c b/drivers/staging/media/sunxi/cedrus/cedrus.c
index b320aa058f74..e6b864f05364 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus.c
+++ b/drivers/staging/media/sunxi/cedrus/cedrus.c
@@ -142,6 +142,13 @@ static const struct cedrus_control cedrus_controls[] = {
.codec = CEDRUS_CODEC_H265,
.required = false,
},
+ {
+ .cfg = {
+ .id = V4L2_CID_MPEG_VIDEO_VP8_FRAME_HEADER,
+ },
+ .codec = CEDRUS_CODEC_VP8,
+ .required = true,
+ },
};
#define CEDRUS_CONTROLS_COUNT ARRAY_SIZE(cedrus_controls)
@@ -388,6 +395,7 @@ static int cedrus_probe(struct platform_device *pdev)
dev->dec_ops[CEDRUS_CODEC_MPEG2] = &cedrus_dec_ops_mpeg2;
dev->dec_ops[CEDRUS_CODEC_H264] = &cedrus_dec_ops_h264;
dev->dec_ops[CEDRUS_CODEC_H265] = &cedrus_dec_ops_h265;
+ dev->dec_ops[CEDRUS_CODEC_VP8] = &cedrus_dec_ops_vp8;
mutex_init(&dev->dev_mutex);
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.h b/drivers/staging/media/sunxi/cedrus/cedrus.h
index f8264953dd04..353cb04b4ce5 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus.h
+++ b/drivers/staging/media/sunxi/cedrus/cedrus.h
@@ -35,6 +35,7 @@ enum cedrus_codec {
CEDRUS_CODEC_MPEG2,
CEDRUS_CODEC_H264,
CEDRUS_CODEC_H265,
+ CEDRUS_CODEC_VP8,
CEDRUS_CODEC_LAST,
};
@@ -76,6 +77,10 @@ struct cedrus_h265_run {
const struct v4l2_ctrl_hevc_scaling_matrix *scaling_matrix;
};
+struct cedrus_vp8_run {
+ const struct v4l2_ctrl_vp8_frame_header *slice_params;
+};
+
struct cedrus_run {
struct vb2_v4l2_buffer *src;
struct vb2_v4l2_buffer *dst;
@@ -84,6 +89,7 @@ struct cedrus_run {
struct cedrus_h264_run h264;
struct cedrus_mpeg2_run mpeg2;
struct cedrus_h265_run h265;
+ struct cedrus_vp8_run vp8;
};
};
@@ -141,6 +147,14 @@ struct cedrus_ctx {
void *entry_points_buf;
dma_addr_t entry_points_buf_addr;
} h265;
+ struct {
+ unsigned int last_frame_p_type;
+ unsigned int last_filter_type;
+ unsigned int last_sharpness_level;
+
+ u8 *entropy_probs_buf;
+ dma_addr_t entropy_probs_buf_dma;
+ } vp8;
} codec;
};
@@ -188,6 +202,7 @@ struct cedrus_dev {
extern struct cedrus_dec_ops cedrus_dec_ops_mpeg2;
extern struct cedrus_dec_ops cedrus_dec_ops_h264;
extern struct cedrus_dec_ops cedrus_dec_ops_h265;
+extern struct cedrus_dec_ops cedrus_dec_ops_vp8;
static inline void cedrus_write(struct cedrus_dev *dev, u32 reg, u32 val)
{
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_dec.c b/drivers/staging/media/sunxi/cedrus/cedrus_dec.c
index 38c0bd7cf672..740b738fdde6 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus_dec.c
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_dec.c
@@ -70,6 +70,11 @@ void cedrus_device_run(void *priv)
V4L2_CID_MPEG_VIDEO_HEVC_SCALING_MATRIX);
break;
+ case V4L2_PIX_FMT_VP8_FRAME:
+ run.vp8.slice_params = cedrus_find_control_data(ctx,
+ V4L2_CID_MPEG_VIDEO_VP8_FRAME_HEADER);
+ break;
+
default:
break;
}
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_hw.c b/drivers/staging/media/sunxi/cedrus/cedrus_hw.c
index fb0cf8adcf1e..7c0ab4015e8f 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus_hw.c
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_hw.c
@@ -48,6 +48,7 @@ int cedrus_engine_enable(struct cedrus_ctx *ctx, enum cedrus_codec codec)
break;
case CEDRUS_CODEC_H264:
+ case CEDRUS_CODEC_VP8:
reg |= VE_MODE_DEC_H264;
break;
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_regs.h b/drivers/staging/media/sunxi/cedrus/cedrus_regs.h
index 150eae2d92d2..6cb1c279790f 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus_regs.h
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_regs.h
@@ -552,6 +552,7 @@
#define VE_H264_SHS_QP_SCALING_MATRIX_DEFAULT BIT(24)
#define VE_H264_CTRL 0x220
+#define VE_H264_CTRL_VP8 BIT(29)
#define VE_H264_CTRL_VLD_DATA_REQ_INT BIT(2)
#define VE_H264_CTRL_DECODE_ERR_INT BIT(1)
#define VE_H264_CTRL_SLICE_DECODE_INT BIT(0)
@@ -561,7 +562,12 @@
VE_H264_CTRL_SLICE_DECODE_INT)
#define VE_H264_TRIGGER_TYPE 0x224
+#define VE_H264_TRIGGER_TYPE_PROBABILITY(x) SHIFT_AND_MASK_BITS(x, 31, 24)
+#define VE_H264_TRIGGER_TYPE_BIN_LENS(x) SHIFT_AND_MASK_BITS((x) - 1, 18, 16)
#define VE_H264_TRIGGER_TYPE_N_BITS(x) (((x) & 0x3f) << 8)
+#define VE_H264_TRIGGER_TYPE_VP8_GET_BITS (15 << 0)
+#define VE_H264_TRIGGER_TYPE_VP8_UPDATE_COEF (14 << 0)
+#define VE_H264_TRIGGER_TYPE_VP8_SLICE_DECODE (10 << 0)
#define VE_H264_TRIGGER_TYPE_AVC_SLICE_DECODE (8 << 0)
#define VE_H264_TRIGGER_TYPE_INIT_SWDEC (7 << 0)
#define VE_H264_TRIGGER_TYPE_FLUSH_BITS (3 << 0)
@@ -571,6 +577,7 @@
#define VE_H264_STATUS_DECODE_ERR_INT VE_H264_CTRL_DECODE_ERR_INT
#define VE_H264_STATUS_SLICE_DECODE_INT VE_H264_CTRL_SLICE_DECODE_INT
#define VE_H264_STATUS_VLD_BUSY BIT(8)
+#define VE_H264_STATUS_VP8_UPPROB_BUSY BIT(17)
#define VE_H264_STATUS_INT_MASK VE_H264_CTRL_INT_MASK
@@ -589,10 +596,83 @@
#define VE_H264_OUTPUT_FRAME_IDX 0x24c
#define VE_H264_EXTRA_BUFFER1 0x250
#define VE_H264_EXTRA_BUFFER2 0x254
+#define VE_H264_MB_ADDR 0x260
+#define VE_H264_ERROR_CASE 0x2b8
#define VE_H264_BASIC_BITS 0x2dc
#define VE_AVC_SRAM_PORT_OFFSET 0x2e0
#define VE_AVC_SRAM_PORT_DATA 0x2e4
+#define VE_VP8_PPS 0x214
+#define VE_VP8_PPS_PIC_TYPE_P_FRAME BIT(31)
+#define VE_VP8_PPS_LAST_SHARPNESS_LEVEL(v) SHIFT_AND_MASK_BITS(v, 30, 28)
+#define VE_VP8_PPS_LAST_PIC_TYPE_P_FRAME BIT(27)
+#define VE_VP8_PPS_ALTREF_SIGN_BIAS BIT(26)
+#define VE_VP8_PPS_GOLDEN_SIGN_BIAS BIT(25)
+#define VE_VP8_PPS_RELOAD_ENTROPY_PROBS BIT(24)
+#define VE_VP8_PPS_REFRESH_ENTROPY_PROBS BIT(23)
+#define VE_VP8_PPS_MB_NO_COEFF_SKIP BIT(22)
+#define VE_VP8_PPS_TOKEN_PARTITION(v) SHIFT_AND_MASK_BITS(v, 21, 20)
+#define VE_VP8_PPS_MODE_REF_LF_DELTA_UPDATE BIT(19)
+#define VE_VP8_PPS_MODE_REF_LF_DELTA_ENABLE BIT(18)
+#define VE_VP8_PPS_LOOP_FILTER_LEVEL(v) SHIFT_AND_MASK_BITS(v, 17, 12)
+#define VE_VP8_PPS_LOOP_FILTER_SIMPLE BIT(11)
+#define VE_VP8_PPS_SHARPNESS_LEVEL(v) SHIFT_AND_MASK_BITS(v, 10, 8)
+#define VE_VP8_PPS_LAST_LOOP_FILTER_SIMPLE BIT(7)
+#define VE_VP8_PPS_SEGMENTATION_ENABLE BIT(6)
+#define VE_VP8_PPS_MB_SEGMENT_ABS_DELTA BIT(5)
+#define VE_VP8_PPS_UPDATE_MB_SEGMENTATION_MAP BIT(4)
+#define VE_VP8_PPS_FULL_PIXEL BIT(3)
+#define VE_VP8_PPS_BILINEAR_MC_FILTER BIT(2)
+#define VE_VP8_PPS_FILTER_TYPE_SIMPLE BIT(1)
+#define VE_VP8_PPS_LPF_DISABLE BIT(0)
+
+#define VE_VP8_QP_INDEX_DELTA 0x218
+#define VE_VP8_QP_INDEX_DELTA_UVAC(v) SHIFT_AND_MASK_BITS(v, 31, 27)
+#define VE_VP8_QP_INDEX_DELTA_UVDC(v) SHIFT_AND_MASK_BITS(v, 26, 22)
+#define VE_VP8_QP_INDEX_DELTA_Y2AC(v) SHIFT_AND_MASK_BITS(v, 21, 17)
+#define VE_VP8_QP_INDEX_DELTA_Y2DC(v) SHIFT_AND_MASK_BITS(v, 16, 12)
+#define VE_VP8_QP_INDEX_DELTA_Y1DC(v) SHIFT_AND_MASK_BITS(v, 11, 7)
+#define VE_VP8_QP_INDEX_DELTA_BASE_QINDEX(v) SHIFT_AND_MASK_BITS(v, 6, 0)
+
+#define VE_VP8_PART_SIZE_OFFSET 0x21c
+#define VE_VP8_ENTROPY_PROBS_ADDR 0x250
+#define VE_VP8_FIRST_DATA_PART_LEN 0x254
+
+#define VE_VP8_FSIZE 0x258
+#define VE_VP8_FSIZE_WIDTH(w) \
+ SHIFT_AND_MASK_BITS(DIV_ROUND_UP(w, 16), 15, 8)
+#define VE_VP8_FSIZE_HEIGHT(h) \
+ SHIFT_AND_MASK_BITS(DIV_ROUND_UP(h, 16), 7, 0)
+
+#define VE_VP8_PICSIZE 0x25c
+#define VE_VP8_PICSIZE_WIDTH(w) SHIFT_AND_MASK_BITS(w, 27, 16)
+#define VE_VP8_PICSIZE_HEIGHT(h) SHIFT_AND_MASK_BITS(h, 11, 0)
+
+#define VE_VP8_REC_LUMA 0x2ac
+#define VE_VP8_FWD_LUMA 0x2b0
+#define VE_VP8_BWD_LUMA 0x2b4
+#define VE_VP8_REC_CHROMA 0x2d0
+#define VE_VP8_FWD_CHROMA 0x2d4
+#define VE_VP8_BWD_CHROMA 0x2d8
+#define VE_VP8_ALT_LUMA 0x2e8
+#define VE_VP8_ALT_CHROMA 0x2ec
+
+#define VE_VP8_SEGMENT_FEAT_MB_LV0 0x2f0
+#define VE_VP8_SEGMENT_FEAT_MB_LV1 0x2f4
+
+#define VE_VP8_SEGMENT3(v) SHIFT_AND_MASK_BITS(v, 31, 24)
+#define VE_VP8_SEGMENT2(v) SHIFT_AND_MASK_BITS(v, 23, 16)
+#define VE_VP8_SEGMENT1(v) SHIFT_AND_MASK_BITS(v, 15, 8)
+#define VE_VP8_SEGMENT0(v) SHIFT_AND_MASK_BITS(v, 7, 0)
+
+#define VE_VP8_REF_LF_DELTA 0x2f8
+#define VE_VP8_MODE_LF_DELTA 0x2fc
+
+#define VE_VP8_LF_DELTA3(v) SHIFT_AND_MASK_BITS(v, 30, 24)
+#define VE_VP8_LF_DELTA2(v) SHIFT_AND_MASK_BITS(v, 22, 16)
+#define VE_VP8_LF_DELTA1(v) SHIFT_AND_MASK_BITS(v, 14, 8)
+#define VE_VP8_LF_DELTA0(v) SHIFT_AND_MASK_BITS(v, 6, 0)
+
#define VE_ISP_INPUT_SIZE 0xa00
#define VE_ISP_INPUT_STRIDE 0xa04
#define VE_ISP_CTRL 0xa08
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_video.c b/drivers/staging/media/sunxi/cedrus/cedrus_video.c
index a78d6b1a3b64..6801ffa77a6b 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus_video.c
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_video.c
@@ -48,6 +48,10 @@ static struct cedrus_format cedrus_formats[] = {
.directions = CEDRUS_DECODE_SRC,
.capabilities = CEDRUS_CAPABILITY_H265_DEC,
},
+ {
+ .pixelformat = V4L2_PIX_FMT_VP8_FRAME,
+ .directions = CEDRUS_DECODE_SRC,
+ },
{
.pixelformat = V4L2_PIX_FMT_SUNXI_TILED_NV12,
.directions = CEDRUS_DECODE_DST,
@@ -125,6 +129,7 @@ void cedrus_prepare_format(struct v4l2_pix_format *pix_fmt, int extended)
case V4L2_PIX_FMT_MPEG2_SLICE:
case V4L2_PIX_FMT_H264_SLICE:
case V4L2_PIX_FMT_HEVC_SLICE:
+ case V4L2_PIX_FMT_VP8_FRAME:
/* Zero bytes per line for encoded source. */
bytesperline = 0;
/* Choose some minimum size since this can't be 0 */
@@ -499,6 +504,10 @@ static int cedrus_start_streaming(struct vb2_queue *vq, unsigned int count)
ctx->current_codec = CEDRUS_CODEC_H265;
break;
+ case V4L2_PIX_FMT_VP8_FRAME:
+ ctx->current_codec = CEDRUS_CODEC_VP8;
+ break;
+
default:
return -EINVAL;
}
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_vp8.c b/drivers/staging/media/sunxi/cedrus/cedrus_vp8.c
new file mode 100644
index 000000000000..93beffd07c35
--- /dev/null
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_vp8.c
@@ -0,0 +1,699 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Cedrus VPU driver
+ *
+ * Copyright (c) 2019 Jernej Skrabec <jernej.skrabec@siol.net>
+ */
+
+#include <linux/delay.h>
+#include <linux/types.h>
+
+#include <media/videobuf2-dma-contig.h>
+
+#include "cedrus.h"
+#include "cedrus_hw.h"
+#include "cedrus_regs.h"
+
+#define CEDRUS_ENTROPY_PROBS_SIZE 0x2400
+#define VP8_PROB_HALF 128
+
+static const u8 prob_table_init[] = {
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xB0, 0xF6, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDF, 0xF1, 0xFC, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xF9, 0xFD, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xF4, 0xFC, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xEA, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xFF, 0xF6, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xEF, 0xFD, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFE, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xFF, 0xF8, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFB, 0xFF, 0xFE, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFD, 0xFE, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xFB, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xFF, 0xFE, 0xFD, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xFA, 0xFF, 0xFE, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD9, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xE1, 0xFC, 0xF1, 0xFD, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xEA, 0xFA, 0xF1, 0xFA, 0xFD, 0xFF, 0xFD, 0xFE,
+ 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xDF, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEE, 0xFD, 0xFE, 0xFE,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xFF, 0xF8, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF9, 0xFE, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFD, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xF7, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xFF, 0xFD, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFE, 0xFD, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xFA, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xBA, 0xFB, 0xFA, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEA, 0xFB, 0xF4, 0xFE,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xFB, 0xFB, 0xF3, 0xFD, 0xFE, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFD, 0xFE, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xEC, 0xFD, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xFB, 0xFD, 0xFD, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xFF, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFE, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xFA, 0xFE, 0xFC, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFE, 0xF9, 0xFD,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFD, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF6, 0xFD, 0xFD, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xFC, 0xFE, 0xFB, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFE, 0xFC, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xF8, 0xFE, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xFD, 0xFF, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xFF, 0xFB, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xF5, 0xFB, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0xFD, 0xFE, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFB, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFD, 0xFE, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFC, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xF9, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xFF, 0xFF, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xFA, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x91, 0x9C, 0xA3, 0x80,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6E, 0x6F, 0x96, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x78, 0x5A, 0x4F, 0x85, 0x57, 0x55, 0x50, 0x6F,
+ 0x97, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x93, 0x88, 0x12, 0x00, 0x6A, 0x91, 0x01, 0x00, 0xB3, 0x79, 0x01, 0x00,
+ 0xDF, 0x01, 0x22, 0x00, 0xD0, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x01, 0x01, 0x8F,
+ 0x0E, 0x12, 0x0E, 0x6B, 0x87, 0x40, 0x39, 0x44, 0x3C, 0x38, 0x80, 0x41,
+ 0x9F, 0x86, 0x80, 0x22, 0xEA, 0xBC, 0x80, 0x1C, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x84, 0x02, 0x04, 0x06, 0x80, 0x81, 0x82, 0x83, 0x80, 0x02, 0x04, 0x06,
+ 0x81, 0x82, 0x83, 0x84, 0x80, 0x02, 0x81, 0x04, 0x82, 0x83, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x08,
+ 0x04, 0x06, 0x80, 0x81, 0x82, 0x83, 0x0A, 0x0C, 0x84, 0x85, 0x86, 0x87,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x08, 0x04, 0x06, 0x80, 0x81,
+ 0x82, 0x83, 0x0A, 0x0C, 0x84, 0x85, 0x86, 0x87, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x83, 0x02, 0x82, 0x04, 0x80, 0x81, 0x00, 0x00, 0x80, 0x02, 0x81, 0x04,
+ 0x82, 0x06, 0x08, 0x0C, 0x83, 0x0A, 0x85, 0x86, 0x84, 0x0E, 0x87, 0x10,
+ 0x88, 0x89, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x8A, 0x02, 0x8B, 0x04, 0x8C, 0x8D, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x87, 0x02, 0x85, 0x04, 0x86, 0x06, 0x88, 0x89,
+};
+
+static const u8 vp8_mv_update_prob[2][19] = {
+ { 237, 246, 253, 253, 254, 254, 254, 254, 254,
+ 254, 254, 254, 254, 254, 250, 250, 252, 254, 254 },
+ { 231, 243, 245, 253, 254, 254, 254, 254, 254,
+ 254, 254, 254, 254, 254, 251, 251, 254, 254, 254 }
+};
+
+static uint8_t read_bits(struct cedrus_dev *dev, unsigned int bits_count,
+ unsigned int probability)
+{
+ cedrus_write(dev, VE_H264_TRIGGER_TYPE,
+ VE_H264_TRIGGER_TYPE_VP8_GET_BITS |
+ VE_H264_TRIGGER_TYPE_BIN_LENS(bits_count) |
+ VE_H264_TRIGGER_TYPE_PROBABILITY(probability));
+
+ while (cedrus_read(dev, VE_H264_STATUS) & VE_H264_STATUS_VLD_BUSY)
+ ;
+
+ return cedrus_read(dev, VE_H264_BASIC_BITS);
+}
+
+static void get_delta_q(struct cedrus_dev *dev)
+{
+ if (read_bits(dev, 1, VP8_PROB_HALF)) {
+ read_bits(dev, 4, VP8_PROB_HALF);
+ read_bits(dev, 1, VP8_PROB_HALF);
+ }
+}
+
+static void process_segmentation_info(struct cedrus_dev *dev)
+{
+ int update = read_bits(dev, 1, VP8_PROB_HALF);
+ int i;
+
+ if (read_bits(dev, 1, VP8_PROB_HALF)) {
+ read_bits(dev, 1, VP8_PROB_HALF);
+
+ for (i = 0; i < 4; i++)
+ if (read_bits(dev, 1, VP8_PROB_HALF)) {
+ read_bits(dev, 7, VP8_PROB_HALF);
+ read_bits(dev, 1, VP8_PROB_HALF);
+ }
+
+ for (i = 0; i < 4; i++)
+ if (read_bits(dev, 1, VP8_PROB_HALF)) {
+ read_bits(dev, 6, VP8_PROB_HALF);
+ read_bits(dev, 1, VP8_PROB_HALF);
+ }
+ }
+
+ if (update)
+ for (i = 0; i < 3; i++)
+ if (read_bits(dev, 1, VP8_PROB_HALF))
+ read_bits(dev, 8, VP8_PROB_HALF);
+}
+
+static void process_ref_lf_delta_info(struct cedrus_dev *dev)
+{
+ if (read_bits(dev, 1, VP8_PROB_HALF)) {
+ int i;
+
+ for (i = 0; i < 4; i++)
+ if (read_bits(dev, 1, VP8_PROB_HALF)) {
+ read_bits(dev, 6, VP8_PROB_HALF);
+ read_bits(dev, 1, VP8_PROB_HALF);
+ }
+
+ for (i = 0; i < 4; i++)
+ if (read_bits(dev, 1, VP8_PROB_HALF)) {
+ read_bits(dev, 6, VP8_PROB_HALF);
+ read_bits(dev, 1, VP8_PROB_HALF);
+ }
+ }
+}
+
+static void process_ref_frame_info(struct cedrus_dev *dev)
+{
+ u8 refresh_golden_frame = read_bits(dev, 1, VP8_PROB_HALF);
+ u8 refresh_alt_ref_frame = read_bits(dev, 1, VP8_PROB_HALF);
+
+ if (!refresh_golden_frame)
+ read_bits(dev, 2, VP8_PROB_HALF);
+
+ if (!refresh_alt_ref_frame)
+ read_bits(dev, 2, VP8_PROB_HALF);
+
+ read_bits(dev, 1, VP8_PROB_HALF);
+ read_bits(dev, 1, VP8_PROB_HALF);
+}
+
+static void cedrus_read_header(struct cedrus_dev *dev,
+ const struct v4l2_ctrl_vp8_frame_header *slice)
+{
+ int i, j;
+
+ if (VP8_FRAME_IS_KEY_FRAME(slice)) {
+ read_bits(dev, 1, VP8_PROB_HALF);
+ read_bits(dev, 1, VP8_PROB_HALF);
+ }
+
+ if (read_bits(dev, 1, VP8_PROB_HALF))
+ process_segmentation_info(dev);
+
+ read_bits(dev, 1, VP8_PROB_HALF);
+ read_bits(dev, 6, VP8_PROB_HALF);
+ read_bits(dev, 3, VP8_PROB_HALF);
+
+ if (read_bits(dev, 1, VP8_PROB_HALF))
+ process_ref_lf_delta_info(dev);
+
+ read_bits(dev, 2, VP8_PROB_HALF);
+ read_bits(dev, 7, VP8_PROB_HALF);
+
+ get_delta_q(dev);
+ get_delta_q(dev);
+ get_delta_q(dev);
+ get_delta_q(dev);
+ get_delta_q(dev);
+
+ if (!VP8_FRAME_IS_KEY_FRAME(slice))
+ process_ref_frame_info(dev);
+
+ read_bits(dev, 1, VP8_PROB_HALF);
+
+ if (!VP8_FRAME_IS_KEY_FRAME(slice))
+ read_bits(dev, 1, VP8_PROB_HALF);
+
+ cedrus_write(dev, VE_H264_TRIGGER_TYPE, VE_H264_TRIGGER_TYPE_VP8_UPDATE_COEF);
+ while (cedrus_read(dev, VE_H264_STATUS) & VE_H264_STATUS_VP8_UPPROB_BUSY)
+ ;
+
+ cedrus_write(dev, VE_H264_STATUS, VE_H264_CTRL_INT_MASK);
+
+ if (read_bits(dev, 1, VP8_PROB_HALF))
+ read_bits(dev, 8, VP8_PROB_HALF);
+
+ if (!VP8_FRAME_IS_KEY_FRAME(slice)) {
+ read_bits(dev, 8, VP8_PROB_HALF);
+ read_bits(dev, 8, VP8_PROB_HALF);
+ read_bits(dev, 8, VP8_PROB_HALF);
+
+ if (read_bits(dev, 1, VP8_PROB_HALF)) {
+ read_bits(dev, 8, VP8_PROB_HALF);
+ read_bits(dev, 8, VP8_PROB_HALF);
+ read_bits(dev, 8, VP8_PROB_HALF);
+ read_bits(dev, 8, VP8_PROB_HALF);
+ }
+
+ if (read_bits(dev, 1, VP8_PROB_HALF)) {
+ read_bits(dev, 8, VP8_PROB_HALF);
+ read_bits(dev, 8, VP8_PROB_HALF);
+ read_bits(dev, 8, VP8_PROB_HALF);
+ }
+
+ for (i = 0; i < 2; i++)
+ for (j = 0; j < 19; j++)
+ if (read_bits(dev, 1, vp8_mv_update_prob[i][j]))
+ read_bits(dev, 7, VP8_PROB_HALF);
+ }
+}
+
+static void cedrus_vp8_update_probs(const struct v4l2_ctrl_vp8_frame_header *slice,
+ u8 *prob_table)
+{
+ int i, j, k;
+
+ memcpy(&prob_table[0x1008], slice->entropy_header.y_mode_probs, 4);
+ memcpy(&prob_table[0x1010], slice->entropy_header.uv_mode_probs, 3);
+
+ memcpy(&prob_table[0x1018], slice->segment_header.segment_probs, 3);
+
+ prob_table[0x101c] = slice->prob_skip_false;
+ prob_table[0x101d] = slice->prob_intra;
+ prob_table[0x101e] = slice->prob_last;
+ prob_table[0x101f] = slice->prob_gf;
+
+ memcpy(&prob_table[0x1020], slice->entropy_header.mv_probs[0], 19);
+ memcpy(&prob_table[0x1040], slice->entropy_header.mv_probs[1], 19);
+
+ for (i = 0; i < 4; ++i)
+ for (j = 0; j < 8; ++j)
+ for (k = 0; k < 3; ++k)
+ memcpy(&prob_table[i * 512 + j * 64 + k * 16],
+ slice->entropy_header.coeff_probs[i][j][k], 11);
+}
+
+static enum cedrus_irq_status
+cedrus_vp8_irq_status(struct cedrus_ctx *ctx)
+{
+ struct cedrus_dev *dev = ctx->dev;
+ u32 reg = cedrus_read(dev, VE_H264_STATUS);
+
+ if (reg & (VE_H264_STATUS_DECODE_ERR_INT |
+ VE_H264_STATUS_VLD_DATA_REQ_INT))
+ return CEDRUS_IRQ_ERROR;
+
+ if (reg & VE_H264_CTRL_SLICE_DECODE_INT)
+ return CEDRUS_IRQ_OK;
+
+ return CEDRUS_IRQ_NONE;
+}
+
+static void cedrus_vp8_irq_clear(struct cedrus_ctx *ctx)
+{
+ struct cedrus_dev *dev = ctx->dev;
+
+ cedrus_write(dev, VE_H264_STATUS,
+ VE_H264_STATUS_INT_MASK);
+}
+
+static void cedrus_vp8_irq_disable(struct cedrus_ctx *ctx)
+{
+ struct cedrus_dev *dev = ctx->dev;
+ u32 reg = cedrus_read(dev, VE_H264_CTRL);
+
+ cedrus_write(dev, VE_H264_CTRL,
+ reg & ~VE_H264_CTRL_INT_MASK);
+}
+
+static void cedrus_vp8_setup(struct cedrus_ctx *ctx,
+ struct cedrus_run *run)
+{
+ const struct v4l2_ctrl_vp8_frame_header *slice = run->vp8.slice_params;
+ struct vb2_queue *cap_q = &ctx->fh.m2m_ctx->cap_q_ctx.q;
+ struct vb2_buffer *src_buf = &run->src->vb2_buf;
+ struct cedrus_dev *dev = ctx->dev;
+ dma_addr_t luma_addr, chroma_addr;
+ dma_addr_t src_buf_addr;
+ int header_size;
+ int qindex;
+ u32 reg;
+
+ cedrus_engine_enable(ctx, CEDRUS_CODEC_VP8);
+
+ cedrus_write(dev, VE_H264_CTRL, VE_H264_CTRL_VP8);
+
+ cedrus_vp8_update_probs(slice, ctx->codec.vp8.entropy_probs_buf);
+
+ reg = slice->first_part_size * 8;
+ cedrus_write(dev, VE_VP8_FIRST_DATA_PART_LEN, reg);
+
+ header_size = VP8_FRAME_IS_KEY_FRAME(slice) ? 10 : 3;
+
+ reg = slice->first_part_size + header_size;
+ cedrus_write(dev, VE_VP8_PART_SIZE_OFFSET, reg);
+
+ reg = vb2_plane_size(src_buf, 0) * 8;
+ cedrus_write(dev, VE_H264_VLD_LEN, reg);
+
+ /*
+ * FIXME: There is a problem if frame header is skipped (adding
+ * first_part_header_bits to offset). It seems that functions
+ * for parsing bitstreams change internal state of VPU in some
+ * way that can't be otherwise set. Maybe this can be bypassed
+ * by somehow fixing probability table buffer?
+ */
+ reg = header_size * 8;
+ cedrus_write(dev, VE_H264_VLD_OFFSET, reg);
+
+ src_buf_addr = vb2_dma_contig_plane_dma_addr(src_buf, 0);
+ cedrus_write(dev, VE_H264_VLD_END,
+ src_buf_addr + vb2_get_plane_payload(src_buf, 0));
+ cedrus_write(dev, VE_H264_VLD_ADDR,
+ VE_H264_VLD_ADDR_VAL(src_buf_addr) |
+ VE_H264_VLD_ADDR_FIRST | VE_H264_VLD_ADDR_VALID |
+ VE_H264_VLD_ADDR_LAST);
+
+ cedrus_write(dev, VE_H264_TRIGGER_TYPE,
+ VE_H264_TRIGGER_TYPE_INIT_SWDEC);
+
+ cedrus_write(dev, VE_VP8_ENTROPY_PROBS_ADDR,
+ ctx->codec.vp8.entropy_probs_buf_dma);
+
+ reg = 0;
+ switch (slice->version) {
+ case 1:
+ reg |= VE_VP8_PPS_FILTER_TYPE_SIMPLE;
+ reg |= VE_VP8_PPS_BILINEAR_MC_FILTER;
+ break;
+ case 2:
+ reg |= VE_VP8_PPS_LPF_DISABLE;
+ reg |= VE_VP8_PPS_BILINEAR_MC_FILTER;
+ break;
+ case 3:
+ reg |= VE_VP8_PPS_LPF_DISABLE;
+ reg |= VE_VP8_PPS_FULL_PIXEL;
+ break;
+ }
+ if (slice->segment_header.flags & V4L2_VP8_SEGMENT_HEADER_FLAG_UPDATE_MAP)
+ reg |= VE_VP8_PPS_UPDATE_MB_SEGMENTATION_MAP;
+ if (!(slice->segment_header.flags & V4L2_VP8_SEGMENT_HEADER_FLAG_DELTA_VALUE_MODE))
+ reg |= VE_VP8_PPS_MB_SEGMENT_ABS_DELTA;
+ if (slice->segment_header.flags & V4L2_VP8_SEGMENT_HEADER_FLAG_ENABLED)
+ reg |= VE_VP8_PPS_SEGMENTATION_ENABLE;
+ if (ctx->codec.vp8.last_filter_type)
+ reg |= VE_VP8_PPS_LAST_LOOP_FILTER_SIMPLE;
+ reg |= VE_VP8_PPS_SHARPNESS_LEVEL(slice->lf_header.sharpness_level);
+ if (slice->lf_header.flags & V4L2_VP8_LF_FILTER_TYPE_SIMPLE)
+ reg |= VE_VP8_PPS_LOOP_FILTER_SIMPLE;
+ reg |= VE_VP8_PPS_LOOP_FILTER_LEVEL(slice->lf_header.level);
+ if (slice->lf_header.flags & V4L2_VP8_LF_HEADER_ADJ_ENABLE)
+ reg |= VE_VP8_PPS_MODE_REF_LF_DELTA_ENABLE;
+ if (slice->lf_header.flags & V4L2_VP8_LF_HEADER_DELTA_UPDATE)
+ reg |= VE_VP8_PPS_MODE_REF_LF_DELTA_UPDATE;
+ reg |= VE_VP8_PPS_TOKEN_PARTITION(ilog2(slice->num_dct_parts));
+ if (slice->flags & V4L2_VP8_FRAME_HEADER_FLAG_MB_NO_SKIP_COEFF)
+ reg |= VE_VP8_PPS_MB_NO_COEFF_SKIP;
+ reg |= VE_VP8_PPS_RELOAD_ENTROPY_PROBS;
+ if (slice->flags & V4L2_VP8_FRAME_HEADER_FLAG_SIGN_BIAS_GOLDEN)
+ reg |= VE_VP8_PPS_GOLDEN_SIGN_BIAS;
+ if (slice->flags & V4L2_VP8_FRAME_HEADER_FLAG_SIGN_BIAS_ALT)
+ reg |= VE_VP8_PPS_ALTREF_SIGN_BIAS;
+ if (ctx->codec.vp8.last_frame_p_type)
+ reg |= VE_VP8_PPS_LAST_PIC_TYPE_P_FRAME;
+ reg |= VE_VP8_PPS_LAST_SHARPNESS_LEVEL(ctx->codec.vp8.last_sharpness_level);
+ if (!(slice->flags & V4L2_VP8_FRAME_HEADER_FLAG_KEY_FRAME))
+ reg |= VE_VP8_PPS_PIC_TYPE_P_FRAME;
+ cedrus_write(dev, VE_VP8_PPS, reg);
+
+ cedrus_read_header(dev, slice);
+
+ /* reset registers changed by HW */
+ cedrus_write(dev, VE_H264_CUR_MB_NUM, 0);
+ cedrus_write(dev, VE_H264_MB_ADDR, 0);
+ cedrus_write(dev, VE_H264_ERROR_CASE, 0);
+
+ reg = 0;
+ reg |= VE_VP8_QP_INDEX_DELTA_UVAC(slice->quant_header.uv_ac_delta);
+ reg |= VE_VP8_QP_INDEX_DELTA_UVDC(slice->quant_header.uv_dc_delta);
+ reg |= VE_VP8_QP_INDEX_DELTA_Y2AC(slice->quant_header.y2_ac_delta);
+ reg |= VE_VP8_QP_INDEX_DELTA_Y2DC(slice->quant_header.y2_dc_delta);
+ reg |= VE_VP8_QP_INDEX_DELTA_Y1DC(slice->quant_header.y_dc_delta);
+ reg |= VE_VP8_QP_INDEX_DELTA_BASE_QINDEX(slice->quant_header.y_ac_qi);
+ cedrus_write(dev, VE_VP8_QP_INDEX_DELTA, reg);
+
+ reg = 0;
+ reg |= VE_VP8_FSIZE_WIDTH(slice->width);
+ reg |= VE_VP8_FSIZE_HEIGHT(slice->height);
+ cedrus_write(dev, VE_VP8_FSIZE, reg);
+
+ reg = 0;
+ reg |= VE_VP8_PICSIZE_WIDTH(slice->width);
+ reg |= VE_VP8_PICSIZE_HEIGHT(slice->height);
+ cedrus_write(dev, VE_VP8_PICSIZE, reg);
+
+ reg = 0;
+ reg |= VE_VP8_SEGMENT3(slice->segment_header.quant_update[3]);
+ reg |= VE_VP8_SEGMENT2(slice->segment_header.quant_update[2]);
+ reg |= VE_VP8_SEGMENT1(slice->segment_header.quant_update[1]);
+ reg |= VE_VP8_SEGMENT0(slice->segment_header.quant_update[0]);
+ cedrus_write(dev, VE_VP8_SEGMENT_FEAT_MB_LV0, reg);
+
+ reg = 0;
+ reg |= VE_VP8_SEGMENT3(slice->segment_header.lf_update[3]);
+ reg |= VE_VP8_SEGMENT2(slice->segment_header.lf_update[2]);
+ reg |= VE_VP8_SEGMENT1(slice->segment_header.lf_update[1]);
+ reg |= VE_VP8_SEGMENT0(slice->segment_header.lf_update[0]);
+ cedrus_write(dev, VE_VP8_SEGMENT_FEAT_MB_LV1, reg);
+
+ reg = 0;
+ reg |= VE_VP8_LF_DELTA3(slice->lf_header.ref_frm_delta[3]);
+ reg |= VE_VP8_LF_DELTA2(slice->lf_header.ref_frm_delta[2]);
+ reg |= VE_VP8_LF_DELTA1(slice->lf_header.ref_frm_delta[1]);
+ reg |= VE_VP8_LF_DELTA0(slice->lf_header.ref_frm_delta[0]);
+ cedrus_write(dev, VE_VP8_REF_LF_DELTA, reg);
+
+ reg = 0;
+ reg |= VE_VP8_LF_DELTA3(slice->lf_header.mb_mode_delta[3]);
+ reg |= VE_VP8_LF_DELTA2(slice->lf_header.mb_mode_delta[2]);
+ reg |= VE_VP8_LF_DELTA1(slice->lf_header.mb_mode_delta[1]);
+ reg |= VE_VP8_LF_DELTA0(slice->lf_header.mb_mode_delta[0]);
+ cedrus_write(dev, VE_VP8_MODE_LF_DELTA, reg);
+
+ luma_addr = cedrus_dst_buf_addr(ctx, run->dst->vb2_buf.index, 0);
+ chroma_addr = cedrus_dst_buf_addr(ctx, run->dst->vb2_buf.index, 1);
+ cedrus_write(dev, VE_VP8_REC_LUMA, luma_addr);
+ cedrus_write(dev, VE_VP8_REC_CHROMA, chroma_addr);
+
+ qindex = vb2_find_timestamp(cap_q, slice->last_frame_ts, 0);
+ if (qindex >= 0) {
+ luma_addr = cedrus_dst_buf_addr(ctx, qindex, 0);
+ chroma_addr = cedrus_dst_buf_addr(ctx, qindex, 1);
+ cedrus_write(dev, VE_VP8_FWD_LUMA, luma_addr);
+ cedrus_write(dev, VE_VP8_FWD_CHROMA, chroma_addr);
+ } else {
+ cedrus_write(dev, VE_VP8_FWD_LUMA, 0);
+ cedrus_write(dev, VE_VP8_FWD_CHROMA, 0);
+ }
+
+ qindex = vb2_find_timestamp(cap_q, slice->golden_frame_ts, 0);
+ if (qindex >= 0) {
+ luma_addr = cedrus_dst_buf_addr(ctx, qindex, 0);
+ chroma_addr = cedrus_dst_buf_addr(ctx, qindex, 1);
+ cedrus_write(dev, VE_VP8_BWD_LUMA, luma_addr);
+ cedrus_write(dev, VE_VP8_BWD_CHROMA, chroma_addr);
+ } else {
+ cedrus_write(dev, VE_VP8_BWD_LUMA, 0);
+ cedrus_write(dev, VE_VP8_BWD_CHROMA, 0);
+ }
+
+ qindex = vb2_find_timestamp(cap_q, slice->alt_frame_ts, 0);
+ if (qindex >= 0) {
+ luma_addr = cedrus_dst_buf_addr(ctx, qindex, 0);
+ chroma_addr = cedrus_dst_buf_addr(ctx, qindex, 1);
+ cedrus_write(dev, VE_VP8_ALT_LUMA, luma_addr);
+ cedrus_write(dev, VE_VP8_ALT_CHROMA, chroma_addr);
+ } else {
+ cedrus_write(dev, VE_VP8_ALT_LUMA, 0);
+ cedrus_write(dev, VE_VP8_ALT_CHROMA, 0);
+ }
+
+ cedrus_write(dev, VE_H264_CTRL, VE_H264_CTRL_VP8 |
+ VE_H264_CTRL_DECODE_ERR_INT |
+ VE_H264_CTRL_SLICE_DECODE_INT);
+
+ if (slice->lf_header.level) {
+ ctx->codec.vp8.last_filter_type =
+ !!(slice->lf_header.flags & V4L2_VP8_LF_FILTER_TYPE_SIMPLE);
+ ctx->codec.vp8.last_frame_p_type =
+ !VP8_FRAME_IS_KEY_FRAME(slice);
+ ctx->codec.vp8.last_sharpness_level =
+ slice->lf_header.sharpness_level;
+ }
+}
+
+static int cedrus_vp8_start(struct cedrus_ctx *ctx)
+{
+ struct cedrus_dev *dev = ctx->dev;
+
+ ctx->codec.vp8.entropy_probs_buf =
+ dma_alloc_coherent(dev->dev, CEDRUS_ENTROPY_PROBS_SIZE,
+ &ctx->codec.vp8.entropy_probs_buf_dma,
+ GFP_KERNEL);
+ if (!ctx->codec.vp8.entropy_probs_buf)
+ return -ENOMEM;
+
+ memcpy(&ctx->codec.vp8.entropy_probs_buf[2048],
+ prob_table_init, sizeof(prob_table_init));
+
+ return 0;
+}
+
+static void cedrus_vp8_stop(struct cedrus_ctx *ctx)
+{
+ struct cedrus_dev *dev = ctx->dev;
+
+ cedrus_engine_disable(dev);
+
+ dma_free_coherent(dev->dev, CEDRUS_ENTROPY_PROBS_SIZE,
+ ctx->codec.vp8.entropy_probs_buf,
+ ctx->codec.vp8.entropy_probs_buf_dma);
+}
+
+static void cedrus_vp8_trigger(struct cedrus_ctx *ctx)
+{
+ struct cedrus_dev *dev = ctx->dev;
+
+ cedrus_write(dev, VE_H264_TRIGGER_TYPE,
+ VE_H264_TRIGGER_TYPE_VP8_SLICE_DECODE);
+}
+
+struct cedrus_dec_ops cedrus_dec_ops_vp8 = {
+ .irq_clear = cedrus_vp8_irq_clear,
+ .irq_disable = cedrus_vp8_irq_disable,
+ .irq_status = cedrus_vp8_irq_status,
+ .setup = cedrus_vp8_setup,
+ .start = cedrus_vp8_start,
+ .stop = cedrus_vp8_stop,
+ .trigger = cedrus_vp8_trigger,
+};
--
2.26.2
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* Re: clock_gettime64 vdso bug on 32-bit arm, rpi-4
From: Arnd Bergmann @ 2020-05-20 20:52 UTC (permalink / raw)
To: Rich Felker
Cc: Mark Rutland, nd, Szabolcs Nagy, Will Deacon,
Russell King - ARM Linux, Linux Kernel Mailing List, Stephen Boyd,
Florian Fainelli, Adhemerval Zanella, Marc Zyngier,
Thomas Gleixner, Vincenzo Frascino, Jack Schmidt, Linux ARM
In-Reply-To: <20200520170932.GO1079@brightrain.aerifal.cx>
On Wed, May 20, 2020 at 7:09 PM Rich Felker <dalias@libc.org> wrote:
>
> On Wed, May 20, 2020 at 12:08:10PM -0400, Rich Felker wrote:
> > On Wed, May 20, 2020 at 04:41:29PM +0100, Szabolcs Nagy wrote:
> > > The 05/19/2020 22:31, Arnd Bergmann wrote:
> > > > On Tue, May 19, 2020 at 10:24 PM Adhemerval Zanella
> > > > <adhemerval.zanella@linaro.org> wrote:
> > > > > On 19/05/2020 16:54, Arnd Bergmann wrote:
> > > note: i could not reproduce it in qemu-system with these configs:
> > >
> > > qemu-system-aarch64 + arm64 kernel + compat vdso
> > > qemu-system-aarch64 + kvm accel (on cortex-a72) + 32bit arm kernel
> > > qemu-system-arm + cpu max + 32bit arm kernel
> > >
> > > so i think it's something specific to that user's setup
> > > (maybe rpi hw bug or gcc miscompiled the vdso or something
> > > with that particular linux, i built my own linux 5.6 because
> > > i did not know the exact kernel version where the bug was seen)
> > >
> > > i don't have access to rpi (or other cortex-a53 where i
> > > can install my own kernel) so this is as far as i got.
> >
> > If we have a binary of the kernel that's known to be failing on the
> > hardware, it would be useful to dump its vdso and examine the
> > disassembly to see if it was miscompiled.
>
> OK, OP posted it and I think we've solved this. See
> https://github.com/richfelker/musl-cross-make/issues/96#issuecomment-631604410
Thanks a lot everyone for figuring this out.
> And my analysis:
>
> <@dalias> see what i just found on the tracker
> <@dalias> patch_vdso/vdso_nullpatch_one in arch/arm/kernel/vdso.c patches out the time32 functions in this case
> <@dalias> but not the time64 one
> <@dalias> this looks like a real kernel bug that's not hw-specific except breaking on all hardware where the patching-out is needed
> <@dalias> we could possibly work around it by refusing to use the time64 vdso unless the time32 one is also present
> <@dalias> yep
> <@dalias> so i think we've solved this. the kernel thought it wasnt using vdso anymore because it patched it out
> <@dalias> but it forgot to patch out the time64 one
> <@dalias> so it stopped updating the data needed for vdso to work
As you mentioned in the issue tracker, the patching was meant as
an optimization and missing it for clock_gettime64 was a mistake but
should by itself not have caused incorrect data to be returned.
I would assume that there is another bug that leads to clock_gettime64
not entering the syscall fallback path as it should but instead returning
bogus data.
Here are some more things I found:
- From reading the linux-5.6 code that was tested, I see that a condition
that leads to patching out the clock_gettime() vdso should also lead to
clock_gettime64() falling back to the the syscall after
__arch_get_hw_counter() returns an error, but for some reason that
does not happen. Presumably the presence of the patching meant that
this code path was never much exercised.
A missing 45939ce292b4 ("ARM: 8957/1: VDSO: Match ARMv8 timer in
cntvct_functional()") would explain the problem, if it happened on
linux-5.6-rc7 or earlier. The fix was merged in the final v5.6 though.
- The patching may actually be counterproductive because it means that
clock_gettime(CLOCK_*COARSE, ...) has to go through the system call
when it could just return the time of the last timer tick regardless of the
clocksource.
- We may get bitten by errata handling on 32-bit kernels running on 64-bit
hardware that has errata workaround in arch/arm64 for compat mode
but not in native arm kernels. ARM64_ERRATUM_1418040,
ARM64_ERRATUM_858921 or SUN50I_ERRATUM_UNKNOWN1
are examples of workaround that are not used on 32-bit kernels running
on 64-bit hardware.
Arnd
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH v6 09/11] PCI: layerscape: Add EP mode support for ls1088a and ls2088a
From: Rob Herring @ 2020-05-20 20:50 UTC (permalink / raw)
To: Xiaowei Bao
Cc: devicetree, andrew.murray, lorenzo.pieralisi, jingoohan1,
linux-pci, Zhiqiang.Hou, linux-kernel, kishon, Minghuan.Lian,
robh+dt, mingkai.hu, gustavo.pimentel, bhelgaas, shawnguo,
roy.zang, linuxppc-dev, leoyang.li, linux-arm-kernel, amurray
In-Reply-To: <20200314033038.24844-10-xiaowei.bao@nxp.com>
On Sat, 14 Mar 2020 11:30:36 +0800, Xiaowei Bao wrote:
> Add PCIe EP mode support for ls1088a and ls2088a, there are some
> difference between LS1 and LS2 platform, so refactor the code of
> the EP driver.
>
> Signed-off-by: Xiaowei Bao <xiaowei.bao@nxp.com>
> ---
> v2:
> - This is a new patch for supporting the ls1088a and ls2088a platform.
> v3:
> - Adjust the some struct assignment order in probe function.
> v4:
> - No change.
> v5:
> - No change.
> v6:
> - No change.
>
> drivers/pci/controller/dwc/pci-layerscape-ep.c | 72 +++++++++++++++++++-------
> 1 file changed, 53 insertions(+), 19 deletions(-)
>
Reviewed-by: Rob Herring <robh@kernel.org>
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH v6 07/11] PCI: layerscape: Modify the way of getting capability with different PEX
From: Rob Herring @ 2020-05-20 20:45 UTC (permalink / raw)
To: Xiaowei Bao
Cc: devicetree, andrew.murray, lorenzo.pieralisi, roy.zang,
gustavo.pimentel, Zhiqiang.Hou, linux-kernel, kishon,
Minghuan.Lian, jingoohan1, robh+dt, mingkai.hu, linux-pci,
bhelgaas, shawnguo, leoyang.li, linuxppc-dev, linux-arm-kernel,
amurray
In-Reply-To: <20200314033038.24844-8-xiaowei.bao@nxp.com>
On Sat, 14 Mar 2020 11:30:34 +0800, Xiaowei Bao wrote:
> The different PCIe controller in one board may be have different
> capability of MSI or MSIX, so change the way of getting the MSI
> capability, make it more flexible.
>
> Signed-off-by: Xiaowei Bao <xiaowei.bao@nxp.com>
> ---
> v2:
> - Remove the repeated assignment code.
> v3:
> - Use ep_func msi_cap and msix_cap to decide the msi_capable and
> msix_capable of pci_epc_features struct.
> v4:
> - No change.
> v5:
> - No change.
> v6:
> - No change.
>
> drivers/pci/controller/dwc/pci-layerscape-ep.c | 31 +++++++++++++++++++-------
> 1 file changed, 23 insertions(+), 8 deletions(-)
>
Reviewed-by: Rob Herring <robh@kernel.org>
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH v6 04/11] PCI: designware-ep: Modify MSI and MSIX CAP way of finding
From: Rob Herring @ 2020-05-20 20:45 UTC (permalink / raw)
To: Xiaowei Bao
Cc: roy.zang, lorenzo.pieralisi, devicetree, jingoohan1, Zhiqiang.Hou,
linuxppc-dev, linux-pci, linux-kernel, leoyang.li, Minghuan.Lian,
linux-arm-kernel, gustavo.pimentel, bhelgaas, andrew.murray,
kishon, shawnguo, mingkai.hu, amurray
In-Reply-To: <20200314033038.24844-5-xiaowei.bao@nxp.com>
On Sat, Mar 14, 2020 at 11:30:31AM +0800, Xiaowei Bao wrote:
> Each PF of EP device should have it's own MSI or MSIX capabitily
s/it's/its/
> struct, so create a dw_pcie_ep_func struct and remove the msi_cap
> and msix_cap to this struct from dw_pcie_ep, and manage the PFs
> with a list.
>
> Signed-off-by: Xiaowei Bao <xiaowei.bao@nxp.com>
> ---
> v3:
> - This is a new patch, to fix the issue of MSI and MSIX CAP way of
> finding.
> v4:
> - Correct some word of commit message.
> v5:
> - No change.
> v6:
> - Fix up the compile error.
>
> drivers/pci/controller/dwc/pcie-designware-ep.c | 135 +++++++++++++++++++++---
> drivers/pci/controller/dwc/pcie-designware.h | 18 +++-
> 2 files changed, 134 insertions(+), 19 deletions(-)
>
> diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c
> index 933bb89..fb915f2 100644
> --- a/drivers/pci/controller/dwc/pcie-designware-ep.c
> +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c
> @@ -19,6 +19,19 @@ void dw_pcie_ep_linkup(struct dw_pcie_ep *ep)
> pci_epc_linkup(epc);
> }
>
> +struct dw_pcie_ep_func *
> +dw_pcie_ep_get_func_from_ep(struct dw_pcie_ep *ep, u8 func_no)
> +{
> + struct dw_pcie_ep_func *ep_func;
> +
> + list_for_each_entry(ep_func, &ep->func_list, list) {
> + if (ep_func->func_no == func_no)
> + return ep_func;
> + }
> +
> + return NULL;
> +}
> +
> static unsigned int dw_pcie_ep_func_select(struct dw_pcie_ep *ep, u8 func_no)
> {
> unsigned int func_offset = 0;
> @@ -59,6 +72,47 @@ void dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar)
> __dw_pcie_ep_reset_bar(pci, func_no, bar, 0);
> }
>
> +static u8 __dw_pcie_ep_find_next_cap(struct dw_pcie_ep *ep, u8 func_no,
> + u8 cap_ptr, u8 cap)
> +{
> + struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
> + unsigned int func_offset = 0;
> + u8 cap_id, next_cap_ptr;
> + u16 reg;
> +
> + if (!cap_ptr)
> + return 0;
> +
> + func_offset = dw_pcie_ep_func_select(ep, func_no);
> +
> + reg = dw_pcie_readw_dbi(pci, func_offset + cap_ptr);
> + cap_id = (reg & 0x00ff);
> +
> + if (cap_id > PCI_CAP_ID_MAX)
> + return 0;
> +
> + if (cap_id == cap)
> + return cap_ptr;
> +
> + next_cap_ptr = (reg & 0xff00) >> 8;
> + return __dw_pcie_ep_find_next_cap(ep, func_no, next_cap_ptr, cap);
> +}
> +
> +static u8 dw_pcie_ep_find_capability(struct dw_pcie_ep *ep, u8 func_no, u8 cap)
> +{
> + struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
> + unsigned int func_offset = 0;
> + u8 next_cap_ptr;
> + u16 reg;
> +
> + func_offset = dw_pcie_ep_func_select(ep, func_no);
> +
> + reg = dw_pcie_readw_dbi(pci, func_offset + PCI_CAPABILITY_LIST);
> + next_cap_ptr = (reg & 0x00ff);
> +
> + return __dw_pcie_ep_find_next_cap(ep, func_no, next_cap_ptr, cap);
> +}
> +
> static int dw_pcie_ep_write_header(struct pci_epc *epc, u8 func_no,
> struct pci_epf_header *hdr)
> {
> @@ -246,13 +300,18 @@ static int dw_pcie_ep_get_msi(struct pci_epc *epc, u8 func_no)
> struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
> u32 val, reg;
> unsigned int func_offset = 0;
> + struct dw_pcie_ep_func *ep_func;
>
> - if (!ep->msi_cap)
> + ep_func = dw_pcie_ep_get_func_from_ep(ep, func_no);
> + if (!ep_func)
> + return -EINVAL;
> +
> + if (!ep_func->msi_cap)
> return -EINVAL;
if (!ep_func || !ep_func->msi_cap)
return -EINVAL;
>
> func_offset = dw_pcie_ep_func_select(ep, func_no);
>
> - reg = ep->msi_cap + func_offset + PCI_MSI_FLAGS;
> + reg = ep_func->msi_cap + func_offset + PCI_MSI_FLAGS;
> val = dw_pcie_readw_dbi(pci, reg);
> if (!(val & PCI_MSI_FLAGS_ENABLE))
> return -EINVAL;
> @@ -268,13 +327,18 @@ static int dw_pcie_ep_set_msi(struct pci_epc *epc, u8 func_no, u8 interrupts)
> struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
> u32 val, reg;
> unsigned int func_offset = 0;
> + struct dw_pcie_ep_func *ep_func;
> +
> + ep_func = dw_pcie_ep_get_func_from_ep(ep, func_no);
> + if (!ep_func)
> + return -EINVAL;
>
> - if (!ep->msi_cap)
> + if (!ep_func->msi_cap)
> return -EINVAL;
Same here.
>
> func_offset = dw_pcie_ep_func_select(ep, func_no);
>
> - reg = ep->msi_cap + func_offset + PCI_MSI_FLAGS;
> + reg = ep_func->msi_cap + func_offset + PCI_MSI_FLAGS;
> val = dw_pcie_readw_dbi(pci, reg);
> val &= ~PCI_MSI_FLAGS_QMASK;
> val |= (interrupts << 1) & PCI_MSI_FLAGS_QMASK;
> @@ -291,13 +355,18 @@ static int dw_pcie_ep_get_msix(struct pci_epc *epc, u8 func_no)
> struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
> u32 val, reg;
> unsigned int func_offset = 0;
> + struct dw_pcie_ep_func *ep_func;
> +
> + ep_func = dw_pcie_ep_get_func_from_ep(ep, func_no);
> + if (!ep_func)
> + return -EINVAL;
>
> - if (!ep->msix_cap)
> + if (!ep_func->msix_cap)
> return -EINVAL;
Same here for msix.
>
> func_offset = dw_pcie_ep_func_select(ep, func_no);
>
> - reg = ep->msix_cap + func_offset + PCI_MSIX_FLAGS;
> + reg = ep_func->msix_cap + func_offset + PCI_MSIX_FLAGS;
> val = dw_pcie_readw_dbi(pci, reg);
> if (!(val & PCI_MSIX_FLAGS_ENABLE))
> return -EINVAL;
> @@ -313,13 +382,18 @@ static int dw_pcie_ep_set_msix(struct pci_epc *epc, u8 func_no, u16 interrupts)
> struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
> u32 val, reg;
> unsigned int func_offset = 0;
> + struct dw_pcie_ep_func *ep_func;
>
> - if (!ep->msix_cap)
> + ep_func = dw_pcie_ep_get_func_from_ep(ep, func_no);
> + if (!ep_func)
> + return -EINVAL;
> +
> + if (!ep_func->msix_cap)
> return -EINVAL;
And here.
>
> func_offset = dw_pcie_ep_func_select(ep, func_no);
>
> - reg = ep->msix_cap + func_offset + PCI_MSIX_FLAGS;
> + reg = ep_func->msix_cap + func_offset + PCI_MSIX_FLAGS;
> val = dw_pcie_readw_dbi(pci, reg);
> val &= ~PCI_MSIX_FLAGS_QSIZE;
> val |= interrupts;
> @@ -404,6 +478,7 @@ int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no,
> u8 interrupt_num)
> {
> struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
> + struct dw_pcie_ep_func *ep_func;
> struct pci_epc *epc = ep->epc;
> unsigned int aligned_offset;
> unsigned int func_offset = 0;
> @@ -413,25 +488,29 @@ int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no,
> bool has_upper;
> int ret;
>
> - if (!ep->msi_cap)
> + ep_func = dw_pcie_ep_get_func_from_ep(ep, func_no);
> + if (!ep_func)
> + return -EINVAL;
> +
> + if (!ep_func->msi_cap)
> return -EINVAL;
And here.
>
> func_offset = dw_pcie_ep_func_select(ep, func_no);
>
> /* Raise MSI per the PCI Local Bus Specification Revision 3.0, 6.8.1. */
> - reg = ep->msi_cap + func_offset + PCI_MSI_FLAGS;
> + reg = ep_func->msi_cap + func_offset + PCI_MSI_FLAGS;
> msg_ctrl = dw_pcie_readw_dbi(pci, reg);
> has_upper = !!(msg_ctrl & PCI_MSI_FLAGS_64BIT);
> - reg = ep->msi_cap + func_offset + PCI_MSI_ADDRESS_LO;
> + reg = ep_func->msi_cap + func_offset + PCI_MSI_ADDRESS_LO;
> msg_addr_lower = dw_pcie_readl_dbi(pci, reg);
> if (has_upper) {
> - reg = ep->msi_cap + func_offset + PCI_MSI_ADDRESS_HI;
> + reg = ep_func->msi_cap + func_offset + PCI_MSI_ADDRESS_HI;
> msg_addr_upper = dw_pcie_readl_dbi(pci, reg);
> - reg = ep->msi_cap + func_offset + PCI_MSI_DATA_64;
> + reg = ep_func->msi_cap + func_offset + PCI_MSI_DATA_64;
> msg_data = dw_pcie_readw_dbi(pci, reg);
> } else {
> msg_addr_upper = 0;
> - reg = ep->msi_cap + func_offset + PCI_MSI_DATA_32;
> + reg = ep_func->msi_cap + func_offset + PCI_MSI_DATA_32;
> msg_data = dw_pcie_readw_dbi(pci, reg);
> }
> aligned_offset = msg_addr_lower & (epc->mem->page_size - 1);
> @@ -467,6 +546,7 @@ int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no,
> u16 interrupt_num)
> {
> struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
> + struct dw_pcie_ep_func *ep_func;
> struct pci_epc *epc = ep->epc;
> u16 tbl_offset, bir;
> unsigned int func_offset = 0;
> @@ -477,9 +557,16 @@ int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no,
> void __iomem *msix_tbl;
> int ret;
>
> + ep_func = dw_pcie_ep_get_func_from_ep(ep, func_no);
> + if (!ep_func)
> + return -EINVAL;
> +
> + if (!ep_func->msix_cap)
> + return -EINVAL;
And here.
> +
> func_offset = dw_pcie_ep_func_select(ep, func_no);
>
> - reg = ep->msix_cap + func_offset + PCI_MSIX_TABLE;
> + reg = ep_func->msix_cap + func_offset + PCI_MSIX_TABLE;
> tbl_offset = dw_pcie_readl_dbi(pci, reg);
> bir = (tbl_offset & PCI_MSIX_TABLE_BIR);
> tbl_offset &= PCI_MSIX_TABLE_OFFSET;
> @@ -558,6 +645,7 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep)
> int i;
> int ret;
> u32 reg;
> + u8 func_no;
> void *addr;
> u8 hdr_type;
> unsigned int nbars;
> @@ -566,6 +654,9 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep)
> struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
> struct device *dev = pci->dev;
> struct device_node *np = dev->of_node;
> + struct dw_pcie_ep_func *ep_func;
> +
> + INIT_LIST_HEAD(&ep->func_list);
>
> if (!pci->dbi_base || !pci->dbi_base2) {
> dev_err(dev, "dbi_base/dbi_base2 is not populated\n");
> @@ -632,9 +723,19 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep)
> if (ret < 0)
> epc->max_functions = 1;
>
> - ep->msi_cap = dw_pcie_find_capability(pci, PCI_CAP_ID_MSI);
> + for (func_no = 0; func_no < epc->max_functions; func_no++) {
> + ep_func = devm_kzalloc(dev, sizeof(*ep_func), GFP_KERNEL);
Why do you need a list if you allocate all the functions at once? You
could just do an array. Or do the allocations as needed and keep the
list. I assume all functions aren't always used.
> + if (!ep_func)
> + return -ENOMEM;
>
> - ep->msix_cap = dw_pcie_find_capability(pci, PCI_CAP_ID_MSIX);
> + ep_func->func_no = func_no;
> + ep_func->msi_cap = dw_pcie_ep_find_capability(ep, func_no,
> + PCI_CAP_ID_MSI);
> + ep_func->msix_cap = dw_pcie_ep_find_capability(ep, func_no,
> + PCI_CAP_ID_MSIX);
> +
> + list_add_tail(&ep_func->list, &ep->func_list);
> + }
>
> if (ep->ops->ep_init)
> ep->ops->ep_init(ep);
> diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
> index cb32afa..dd9b7b4 100644
> --- a/drivers/pci/controller/dwc/pcie-designware.h
> +++ b/drivers/pci/controller/dwc/pcie-designware.h
> @@ -230,8 +230,16 @@ struct dw_pcie_ep_ops {
> unsigned int (*func_conf_select)(struct dw_pcie_ep *ep, u8 func_no);
> };
>
> +struct dw_pcie_ep_func {
> + struct list_head list;
> + u8 func_no;
> + u8 msi_cap; /* MSI capability offset */
> + u8 msix_cap; /* MSI-X capability offset */
> +};
> +
> struct dw_pcie_ep {
> struct pci_epc *epc;
> + struct list_head func_list;
> const struct dw_pcie_ep_ops *ops;
> phys_addr_t phys_base;
> size_t addr_size;
> @@ -244,8 +252,6 @@ struct dw_pcie_ep {
> u32 num_ob_windows;
> void __iomem *msi_mem;
> phys_addr_t msi_mem_phys;
> - u8 msi_cap; /* MSI capability offset */
> - u8 msix_cap; /* MSI-X capability offset */
> };
>
> struct dw_pcie_ops {
> @@ -437,6 +443,8 @@ int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no,
> int dw_pcie_ep_raise_msix_irq_doorbell(struct dw_pcie_ep *ep, u8 func_no,
> u16 interrupt_num);
> void dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar);
> +struct dw_pcie_ep_func *
> +dw_pcie_ep_get_func_from_ep(struct dw_pcie_ep *ep, u8 func_no);
> #else
> static inline void dw_pcie_ep_linkup(struct dw_pcie_ep *ep)
> {
> @@ -478,5 +486,11 @@ static inline int dw_pcie_ep_raise_msix_irq_doorbell(struct dw_pcie_ep *ep,
> static inline void dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar)
> {
> }
> +
> +static inline struct dw_pcie_ep_func *
> +dw_pcie_ep_get_func_from_ep(struct dw_pcie_ep *ep, u8 func_no)
> +{
> + return NULL;
> +}
> #endif
> #endif /* _PCIE_DESIGNWARE_H */
> --
> 2.9.5
>
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH v6 01/11] PCI: designware-ep: Add multiple PFs support for DWC
From: Rob Herring @ 2020-05-20 20:32 UTC (permalink / raw)
To: Xiaowei Bao
Cc: roy.zang, lorenzo.pieralisi, devicetree, jingoohan1, Zhiqiang.Hou,
linuxppc-dev, linux-pci, linux-kernel, leoyang.li, Minghuan.Lian,
robh+dt, linux-arm-kernel, gustavo.pimentel, bhelgaas,
andrew.murray, kishon, shawnguo, mingkai.hu, amurray
In-Reply-To: <20200314033038.24844-2-xiaowei.bao@nxp.com>
On Sat, 14 Mar 2020 11:30:28 +0800, Xiaowei Bao wrote:
> Add multiple PFs support for DWC, due to different PF have different
> config space, we use func_conf_select callback function to access
> the different PF's config space, the different chip company need to
> implement this callback function when use the DWC IP core and intend
> to support multiple PFs feature.
>
> Signed-off-by: Xiaowei Bao <xiaowei.bao@nxp.com>
> Acked-by: Gustavo Pimentel <gustavo.pimentel@synopsys.com>
> ---
> v2:
> - Remove duplicate redundant code.
> - Reimplement the PF config space access way.
> v3:
> - Integrate duplicate code for func_select.
> - Move PCIE_ATU_FUNC_NUM(pf) (pf << 20) to ((pf) << 20).
> - Add the comments for func_conf_select function.
> v4:
> - Correct the commit message.
> v5:
> - No change.
> v6:
> - No change.
>
> drivers/pci/controller/dwc/pcie-designware-ep.c | 123 ++++++++++++++++--------
> drivers/pci/controller/dwc/pcie-designware.c | 59 ++++++++----
> drivers/pci/controller/dwc/pcie-designware.h | 18 +++-
> 3 files changed, 142 insertions(+), 58 deletions(-)
>
Reviewed-by: Rob Herring <robh@kernel.org>
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH v7 11/11] media: platform: Add jpeg dec/enc feature
From: Tomasz Figa @ 2020-05-20 19:40 UTC (permalink / raw)
To: Xia Jiang
Cc: devicetree, srv_heupstream, Rick Chang, linux-kernel,
Mauro Carvalho Chehab, Rob Herring, Matthias Brugger,
Hans Verkuil, linux-mediatek, Marek Szyprowski, linux-arm-kernel,
linux-media
In-Reply-To: <1589020095.24163.150.camel@mhfsdcap03>
Hi Xia,
On Sat, May 09, 2020 at 06:28:15PM +0800, Xia Jiang wrote:
> On Fri, 2020-05-01 at 17:37 +0000, Tomasz Figa wrote:
> > Hi Xia,
> >
> > On Thu, Apr 16, 2020 at 12:03:15PM +0800, Xia Jiang wrote:
> > > On Fri, 2020-03-06 at 20:23 +0900, Tomasz Figa wrote:
> > > > Hi Xia,
> > > >
> > > > On Tue, Mar 03, 2020 at 08:34:46PM +0800, Xia Jiang wrote:
> > > > > Add mtk jpeg encode v4l2 driver based on jpeg decode, because that jpeg
> > > > > decode and encode have great similarities with function operation.
> > > >
> > > > Thank you for the patch. Please see my comments inline.
> > >
> > > Dear Tomasz,
> > >
> > > Thank you for your reply. I have followed your advice and submited v8
> > > version patch.
> > >
> > > Please check my reply below.
> Dear Tomasz,
> I have some confuse about your advice, please check my reply below.
Sorry for the late reply again. Please see my reply inline.
> > [snip]
> > > >
> > > > >
> > > > > - switch (s->target) {
> > > > > - case V4L2_SEL_TGT_COMPOSE:
> > > > > - s->r.left = 0;
> > > > > - s->r.top = 0;
> > > > > - ctx->out_q.w = s->r.width;
> > > > > - ctx->out_q.h = s->r.height;
> > > > > - break;
> > > > > - default:
> > > > > - return -EINVAL;
> > > > > + switch (s->target) {
> > > > > + case V4L2_SEL_TGT_CROP:
> > > > > + s->r.left = 0;
> > > > > + s->r.top = 0;
> > > > > + ctx->out_q.w = s->r.width;
> > > > > + ctx->out_q.h = s->r.height;
> > > >
> > > > What happens if the userspace provides a value bigger than current format?
> > > we need get the min value of userspace value and current value,changed
> > > it like this:
> > > ctx->out_q.w = min(s->r.width, ctx->out_q.w);
> > > ctx->out_q.h = min(s->r.height,ctx->out_q.h);
> >
> > Since ctx->out_q is modified by this function, wouldn't that cause
> > problems if S_SELECTION was called two times, first with a smaller
> > rectangle and then with a bigger one? We should store the active crop
> > and format separately and use the latter for min().
> Add a member variable(struct v4l2_rect) in out_q structure for storing
> the active crop, like this:
> s->r.width = min(s->r.width, ctx->out_q.w);
> s->r.height = min(s->r.height,ctx->out_q.h);
> ctx->out_q.rect.width = s->r.width;
> ctx->out_q.rect.height = s->r.height;
> Is that ok?
Yes. I'd call it crop_rect and it can be simplified further into:
ct->out_q.crop_rect = s->r;
> >
> > [snip]
> > > > >
> > > > > while ((vb = mtk_jpeg_buf_remove(ctx, q->type)))
> > > > > v4l2_m2m_buf_done(vb, VB2_BUF_STATE_ERROR);
> > > > > @@ -772,6 +1011,45 @@ static int mtk_jpeg_set_dec_dst(struct mtk_jpeg_ctx *ctx,
> > > > > return 0;
> > > > > }
> > > > >
> > > > > +static void mtk_jpeg_set_enc_dst(struct mtk_jpeg_ctx *ctx, void __iomem *base,
> > > > > + struct vb2_buffer *dst_buf,
> > > > > + struct mtk_jpeg_enc_bs *bs)
> > > > > +{
> > > > > + bs->dma_addr = vb2_dma_contig_plane_dma_addr(dst_buf, 0);
> > > > > + bs->dma_addr_offset = ctx->enable_exif ? MTK_JPEG_DEFAULT_EXIF_SIZE : 0;
> > > >
> > > > Could you explain what is the meaning of the dma_addr_offset and where the
> > > > default EXIF size comes from? Also, how is the encoder output affected by
> > > > the enable_exif flag?
> > > If enabled the exif mode, the real output will be filled at the locaiton
> > > of dst_addr+ dma_addr_offset(exif size).The dma_addr_offset will be
> > > filled by the application.
> > > The default exif size is setted as constant value 64k according to the
> > > spec.(Exif metadata are restricted in size to 64kB in JPEG images
> > > because according to the specification this information must be
> > > contained within a signed JPEG APP1 segment)
> >
> > Okay, thanks. Then it sounds like MTK_JPEG_MAX_EXIF_SIZE could be a more
> > appropriate name.
> >
> > [snip]
> > > > > +}
> > > > > +
> > > > > static void mtk_jpeg_device_run(void *priv)
> > > > > {
> > > > > struct mtk_jpeg_ctx *ctx = priv;
> > > > > @@ -782,6 +1060,8 @@ static void mtk_jpeg_device_run(void *priv)
> > > > > struct mtk_jpeg_src_buf *jpeg_src_buf;
> > > > > struct mtk_jpeg_bs bs;
> > > > > struct mtk_jpeg_fb fb;
> > > > > + struct mtk_jpeg_enc_bs enc_bs;
> > > > > + struct mtk_jpeg_enc_fb enc_fb;
> > > > > int i;
> > > > >
> > > > > src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
> > > > > @@ -792,30 +1072,47 @@ static void mtk_jpeg_device_run(void *priv)
> > > > > for (i = 0; i < dst_buf->vb2_buf.num_planes; i++)
> > > > > vb2_set_plane_payload(&dst_buf->vb2_buf, i, 0);
> > > > > buf_state = VB2_BUF_STATE_DONE;
> > > >
> > > > About existing code, but we may want to explain this.
> > > > What is this last frame handling above for?
> > > if the user gives us a empty buffer(means it is the last frame),the
> > > driver will not encode and done the buffer to the user.
> > >
> >
> > An empty buffer is not a valid way of signaling a last frame in V4L2. In
> > general, I'm not sure there is such a thing in JPEG, because all frames
> > are separate from each other and we always expect 1 input buffer and 1
> > output buffer for one frame. We might want to remove the special
> > handling in a follow up patch.
> How does application to end jpeg operation in motion jpeg if we remove
> this? I tryed to end with the condition that the input number equals
> output number in UT, and is ok.
That's correct. The operation ends when the number of CAPTURE buffers
dequeued is the same as the number of OUTPUT buffers queued.
> >
> > > > > - goto dec_end;
> > > > > + goto device_run_end;
> > > > > }
> > > > >
> > > > > - if (mtk_jpeg_check_resolution_change(ctx, &jpeg_src_buf->dec_param)) {
> > > > > - mtk_jpeg_queue_src_chg_event(ctx);
> > > > > - ctx->state = MTK_JPEG_SOURCE_CHANGE;
> > > > > - v4l2_m2m_job_finish(jpeg->m2m_dev, ctx->fh.m2m_ctx);
> > > > > - return;
> > > > > - }
> > > > > + if (jpeg->mode == MTK_JPEG_ENC) {
> > > > > + spin_lock_irqsave(&jpeg->hw_lock, flags);
> > > > > + mtk_jpeg_enc_reset(jpeg->reg_base);
> > > >
> > > > Why do we need to reset every frame?
> > > We do this operation is to ensure that all registers are cleared.
> > > It's safer from the hardware point of view.
> >
> > Wouldn't this only waste power? If we reset the hardware after powering
> > up, the only registers that could change would be changed by the driver
> > itself. The driver should program all registers properly when starting
> > next frame anyway, so such a reset shouldn't be necessary.
> I confirmed with hardware designer again that we need to reset every
> frame. If we do not do like this, unexpected mistakes may occur.
Okay, thanks for double checking. Please add a comment to the code that it
is a hardware requirement.
> >
> > > >
> > > > > +
> > > > > + mtk_jpeg_set_enc_dst(ctx, jpeg->reg_base, &dst_buf->vb2_buf,
> > > > > + &enc_bs);
> > > > > + mtk_jpeg_set_enc_src(ctx, jpeg->reg_base, &src_buf->vb2_buf,
> > > > > + &enc_fb);
> > > > > + mtk_jpeg_enc_set_ctrl_cfg(jpeg->reg_base, ctx->enable_exif,
> > > > > + ctx->enc_quality,
> > > > > + ctx->restart_interval);
> > > > > +
> > > > > + mtk_jpeg_enc_start(jpeg->reg_base);
> > > > > + } else {
> > > > > + if (mtk_jpeg_check_resolution_change
> > > > > + (ctx, &jpeg_src_buf->dec_param)) {
> > > > > + mtk_jpeg_queue_src_chg_event(ctx);
> > > > > + ctx->state = MTK_JPEG_SOURCE_CHANGE;
> > > > > + v4l2_m2m_job_finish(jpeg->m2m_dev, ctx->fh.m2m_ctx);
> > > >
> > > > This is a bit strange. Resolution change should be signaled when the
> > > > hardware attempted to decode a frame and detected a different resolution
> > > > than current. It shouldn't be necessary for the userspace to queue a pair
> > > > of buffers to signal it, as with the current code.
> > > If the the resolution is bigger than current, the current buffer will
> > > not be enough for the changed resolution.Shouldn't it tell the userspace
> > > to queue new buffer and stream on again?
> >
> > The V4L2 decode flow is as follows:
> > - application configures and starts only the OUTPUT queue,
> > - application queues an OUTPUT buffer with a frame worth of bitstream,
> > - decoder parses the bitstream headers, detects CAPTURE format and
> > signals the source change event,
> > - application reads CAPTURE format and configures and starts the
> > CAPTURE queue,
> > - application queues a CAPTURE buffer,
> > - decoder decodes the image to the queued buffer.
> >
> > In case of subsequent (dynamic) resolution change:
> > - application queues an OUTPUT buffer and a CAPTURE buffer,
> > - decoder parses the bitstream, notices resolution change, updates
> > CAPTURE format and signals the source change event, refusing to
> > continue the decoding until the application acknowledges it,
> > - application either reallocates its CAPTURE buffers or confirms that
> > the existing buffers are fine and acknowledges resolution change,
> > - decoding continues.
> >
> > For more details, please check the interface specification:
> > https://www.kernel.org/doc/html/latest/media/uapi/v4l/dev-decoder.html
> >
> I tryed to move this operation from device_run() to
> mtk_jpeg_dec_buf_queue(),but have a problem in motion jpeg.For example,I
> queued three buffers continuously,the third buffer has resolution
> change(bigger than the second buffer),but the capture buffer used in
> device run didn't changed.
> How do we handle this case?
Sorry, I think I misread the driver code. It looks like there is a code
that parses the JPEG header from the source buffer called from
mtk_jpeg_dec_buf_queue() and that is the moment the driver detects the new
resolution. Then it only signals the event once all the previously queued
frames have been decoded, i.e. when the first new resolution frame gets to
device_run(). I think the current code should be fine then. Sorry for
confusion again!
> > [snip]
> > > > > - ret = video_register_device(jpeg->dec_vdev, VFL_TYPE_GRABBER, 3);
> > > > > + ret = video_register_device(jpeg->vfd_jpeg, VFL_TYPE_GRABBER, -1);
> > > >
> > > > FYI the type changed to VFL_TYPE_VIDEO recently.
> > > I changed VFL_TYPE_GRABBER to VFL_TYPE_VIDEO,but builded fail.
> >
> > What kernel version are you building with?
> I build it with the latest kernel 5.7,but builed fail again.
That's strange. There is no VFL_TYPE_GRABBER in 5.7 anymore:
https://elixir.bootlin.com/linux/v5.7-rc6/source/include/media/v4l2-dev.h#L24
Best regards,
Tomasz
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ 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