From 1418c7d85efb873033c3c7a93c9ecb32138a88ff Mon Sep 17 00:00:00 2001 From: "shihong.zheng" Date: Tue, 16 Jun 2020 21:54:30 +0800 Subject: [PATCH] media_modules: sc2 media modules bringup. [1/1] PD#SWPL-26369 Problem: sc2 media modules bringup. Solution: support sc2 decoder changes. ucode change id: Ieb122b1 ucode commit id: ff35011e Verify: ptm/pxp Change-Id: Ibda54d1710ef61841ae2a75c10912e796434dac2 Signed-off-by: shihong.zheng --- drivers/common/chips/chips.c | 1 + drivers/common/chips/decoder_cpu_ver_info.c | 7 ++ drivers/common/chips/decoder_cpu_ver_info.h | 3 + drivers/common/firmware/firmware_type.c | 1 + drivers/common/media_clock/clk/clkg12.c | 16 ++- .../common/media_clock/switch/amports_gate.c | 3 + .../decoder/mpeg4/vmpeg4_multi.c | 5 +- drivers/frame_provider/decoder/utils/vdec.c | 101 +++++++++++++++--- drivers/frame_provider/decoder/utils/vdec.h | 2 + drivers/frame_provider/decoder/vav1/vav1.c | 33 ++++-- drivers/stream_input/amports/amstream.c | 50 ++++++++- .../stream_input/amports/stream_buffer_base.c | 33 +++++- .../stream_input/amports/stream_buffer_base.h | 8 +- .../amports/stream_buffer_interface.c | 30 +++--- drivers/stream_input/amports/streambuf.c | 19 ++-- drivers/stream_input/amports/streambuf.h | 27 +++++ firmware/video_ucode.bin | Bin 1404416 -> 1488640 bytes 17 files changed, 277 insertions(+), 62 deletions(-) mode change 100755 => 100644 firmware/video_ucode.bin diff --git a/drivers/common/chips/chips.c b/drivers/common/chips/chips.c index 9cabb1d..d692ca8 100644 --- a/drivers/common/chips/chips.c +++ b/drivers/common/chips/chips.c @@ -77,6 +77,7 @@ static const struct type_name cpu_type_name[] = { {AM_MESON_CPU_MAJOR_ID_SM1, "sm1"}, {AM_MESON_CPU_MAJOR_ID_TL1, "tl1"}, {AM_MESON_CPU_MAJOR_ID_TM2, "tm2"}, + {AM_MESON_CPU_MAJOR_ID_SC2, "sc2"}, {0, NULL}, }; diff --git a/drivers/common/chips/decoder_cpu_ver_info.c b/drivers/common/chips/decoder_cpu_ver_info.c index 894bd74..d74728c 100644 --- a/drivers/common/chips/decoder_cpu_ver_info.c +++ b/drivers/common/chips/decoder_cpu_ver_info.c @@ -61,6 +61,9 @@ static enum AM_MESON_CPU_MAJOR_ID cpu_ver_info[AM_MESON_CPU_MAJOR_ID_MAX - MAJOR AM_MESON_CPU_MAJOR_ID_RES_0x2d, AM_MESON_CPU_MAJOR_ID_TL1, AM_MESON_CPU_MAJOR_ID_TM2, + AM_MESON_CPU_MAJOR_ID_RES_0x30, + AM_MESON_CPU_MAJOR_ID_RES_0x31, + AM_MESON_CPU_MAJOR_ID_SC2, }; static const struct of_device_id cpu_ver_of_match[] = { @@ -107,6 +110,10 @@ static const struct of_device_id cpu_ver_of_match[] = { .compatible = "amlogic, cpu-major-id-tm2", .data = &cpu_ver_info[AM_MESON_CPU_MAJOR_ID_TM2 - MAJOR_ID_START], }, + { + .compatible = "amlogic, cpu-major-id-sc2", + .data = &cpu_ver_info[AM_MESON_CPU_MAJOR_ID_SC2 - MAJOR_ID_START], + }, {}, }; diff --git a/drivers/common/chips/decoder_cpu_ver_info.h b/drivers/common/chips/decoder_cpu_ver_info.h index 83e8274..cd97477 100644 --- a/drivers/common/chips/decoder_cpu_ver_info.h +++ b/drivers/common/chips/decoder_cpu_ver_info.h @@ -48,6 +48,9 @@ enum AM_MESON_CPU_MAJOR_ID AM_MESON_CPU_MAJOR_ID_RES_0x2d, AM_MESON_CPU_MAJOR_ID_TL1 = 0x2e, AM_MESON_CPU_MAJOR_ID_TM2 = 0x2f, + AM_MESON_CPU_MAJOR_ID_RES_0x30, + AM_MESON_CPU_MAJOR_ID_RES_0x31, + AM_MESON_CPU_MAJOR_ID_SC2 = 0x32, AM_MESON_CPU_MAJOR_ID_MAX, }; diff --git a/drivers/common/firmware/firmware_type.c b/drivers/common/firmware/firmware_type.c index ac35859..c232020 100644 --- a/drivers/common/firmware/firmware_type.c +++ b/drivers/common/firmware/firmware_type.c @@ -75,6 +75,7 @@ static const struct cpu_type_s cpu_type[] = { {AM_MESON_CPU_MAJOR_ID_SM1, "sm1"}, {AM_MESON_CPU_MAJOR_ID_TL1, "tl1"}, {AM_MESON_CPU_MAJOR_ID_TM2, "tm2"}, + {AM_MESON_CPU_MAJOR_ID_SC2, "sc2"}, }; const char *get_fw_format_name(unsigned int format) diff --git a/drivers/common/media_clock/clk/clkg12.c b/drivers/common/media_clock/clk/clkg12.c index 22d71a6..237ddc1 100644 --- a/drivers/common/media_clock/clk/clkg12.c +++ b/drivers/common/media_clock/clk/clkg12.c @@ -414,18 +414,24 @@ static struct clk_set_setting clks_for_formats[] = { void set_clock_gate(struct gate_switch_node *nodes, int num) { struct gate_switch_node *node = NULL; + char *hevc_mux_str = NULL; + + if (get_cpu_major_id() < AM_MESON_CPU_MAJOR_ID_SC2) + hevc_mux_str = "clk_hevc_mux"; + else + hevc_mux_str = "clk_hevcf_mux"; do { node = &nodes[num - 1]; - if (IS_ERR_OR_NULL(node)) + if (IS_ERR_OR_NULL(node) || (IS_ERR_OR_NULL(node->clk))) pr_info("get mux clk err.\n"); if (!strcmp(node->name, "clk_vdec_mux")) gclk.vdec_mux_node = node; else if (!strcmp(node->name, "clk_hcodec_mux")) gclk.hcodec_mux_node = node; - else if (!strcmp(node->name, "clk_hevc_mux")) - gclk.hevc_mux_node = node; + else if (!strcmp(node->name, hevc_mux_str)) + gclk.hevc_mux_node = node; else if (!strcmp(node->name, "clk_hevcb_mux")) gclk.hevc_back_mux_node = node; } while(--num); @@ -785,7 +791,8 @@ static int hevc_back_clock_set(int clk) clk = hevcb_frq; } - if (get_cpu_major_id() >= MESON_CPU_MAJOR_ID_TXLX) { + if ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_TXLX) && + (get_cpu_major_id() < AM_MESON_CPU_MAJOR_ID_SC2)) { if ((READ_EFUSE_REG(EFUSE_LIC1) >> 28 & 0x1) && clk > 333) { pr_info("The hevcb clock limit to 333MHz.\n"); clk = 333; @@ -1022,6 +1029,7 @@ static int vdec_clock_get(enum vdec_type_e core) AM_MESON_CPU_MAJOR_ID_SM1,\ AM_MESON_CPU_MAJOR_ID_TL1,\ AM_MESON_CPU_MAJOR_ID_TM2,\ + AM_MESON_CPU_MAJOR_ID_SC2,\ 0} #include "clk.h" diff --git a/drivers/common/media_clock/switch/amports_gate.c b/drivers/common/media_clock/switch/amports_gate.c index beaea53..9d5f7b4 100644 --- a/drivers/common/media_clock/switch/amports_gate.c +++ b/drivers/common/media_clock/switch/amports_gate.c @@ -64,6 +64,9 @@ struct gate_switch_node gates[] = { { .name = "asyncfifo", }, + { + .name = "clk_hevcf_mux", + }, }; /* diff --git a/drivers/frame_provider/decoder/mpeg4/vmpeg4_multi.c b/drivers/frame_provider/decoder/mpeg4/vmpeg4_multi.c index 9cf5629..0bb416c 100644 --- a/drivers/frame_provider/decoder/mpeg4/vmpeg4_multi.c +++ b/drivers/frame_provider/decoder/mpeg4/vmpeg4_multi.c @@ -47,6 +47,7 @@ #include "../utils/firmware.h" #include "../utils/vdec_v4l2_buffer_ops.h" #include "../utils/config_parser.h" +#include "../../../common/chips/decoder_cpu_ver_info.h" #include #define DRIVER_NAME "ammvdec_mpeg4" @@ -871,8 +872,8 @@ static void vmpeg4_prepare_input(struct vdec_mpeg4_hw_s *hw) /* reset VLD fifo for all vdec */ WRITE_VREG(DOS_SW_RESET0, (1<<5) | (1<<4) | (1<<3)); WRITE_VREG(DOS_SW_RESET0, 0); - - dummy = READ_RESET_REG(RESET0_REGISTER); + if (get_cpu_major_id() < AM_MESON_CPU_MAJOR_ID_SC2) + dummy = READ_RESET_REG(RESET0_REGISTER); WRITE_VREG(POWER_CTL_VLD, 1 << 4); /* diff --git a/drivers/frame_provider/decoder/utils/vdec.c b/drivers/frame_provider/decoder/utils/vdec.c index 327242d..f75d735 100644 --- a/drivers/frame_provider/decoder/utils/vdec.c +++ b/drivers/frame_provider/decoder/utils/vdec.c @@ -78,6 +78,9 @@ #include #endif +#include +#include + static DEFINE_MUTEX(vdec_mutex); #define MC_SIZE (4096 * 4) @@ -135,7 +138,7 @@ static int enable_mvdec_info = 1; int decode_underflow = 0; -int enable_stream_mode_multi_dec; +static int enable_stream_mode_multi_dec; #define CANVAS_MAX_SIZE (AMVDEC_CANVAS_MAX1 - AMVDEC_CANVAS_START_INDEX + 1 + AMVDEC_CANVAS_MAX2 + 1) @@ -279,6 +282,15 @@ void VDEC_PRINT_FUN_LINENO(const char *fun, int line) } EXPORT_SYMBOL(VDEC_PRINT_FUN_LINENO); +bool is_support_no_parser(void) +{ + if ((enable_stream_mode_multi_dec) || + (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SC2)) + return true; + return false; +} +EXPORT_SYMBOL(is_support_no_parser); + unsigned char is_mult_inc(unsigned int type) { unsigned char ret = 0; @@ -657,7 +669,8 @@ static void vdec_disable_DMC(struct vdec_s *vdec) codec_dmcbus_read(DMC_REQ_CTRL) & ~mask); spin_unlock_irqrestore(&vdec_spin_lock, flags); - if (is_cpu_tm2_revb()) { + if (is_cpu_tm2_revb() || + (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SC2)) { while (!(codec_dmcbus_read(TM2_REVB_DMC_CHAN_STS) & mask)) ; @@ -1308,7 +1321,7 @@ static void vdec_sync_input_write(struct vdec_s *vdec) return; if (vdec->input.target == VDEC_INPUT_TARGET_VLD) { - if (enable_stream_mode_multi_dec) { + if (is_support_no_parser()) { if (!vdec->master) { WRITE_VREG(VLD_MEM_VIFIFO_WP, STBUF_READ(&vdec->vbuf, get_wp)); @@ -1321,7 +1334,7 @@ static void vdec_sync_input_write(struct vdec_s *vdec) STBUF_READ(&vdec->vbuf, get_wp)); } } else if (vdec->input.target == VDEC_INPUT_TARGET_HEVC) { - if (enable_stream_mode_multi_dec) { + if (is_support_no_parser()) { if (!vdec->master) { WRITE_VREG(HEVC_STREAM_WR_PTR, STBUF_READ(&vdec->vbuf, get_wp)); @@ -1359,8 +1372,8 @@ int vdec_prepare_input(struct vdec_s *vdec, struct vframe_chunk_s **p) /* reset VLD fifo for all vdec */ WRITE_VREG(DOS_SW_RESET0, (1<<5) | (1<<4) | (1<<3)); WRITE_VREG(DOS_SW_RESET0, 0); - - dummy = READ_RESET_REG(RESET0_REGISTER); + if (get_cpu_major_id() < AM_MESON_CPU_MAJOR_ID_SC2) + dummy = READ_RESET_REG(RESET0_REGISTER); WRITE_VREG(POWER_CTL_VLD, 1 << 4); } else if (input->target == VDEC_INPUT_TARGET_HEVC) { #if 0 @@ -1823,7 +1836,8 @@ void hevc_wait_ddr(void) codec_dmcbus_read(DMC_REQ_CTRL) & ~mask); spin_unlock_irqrestore(&vdec_spin_lock, flags); - if (is_cpu_tm2_revb()) { + if (is_cpu_tm2_revb() || + (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SC2)) { while (!(codec_dmcbus_read(TM2_REVB_DMC_CHAN_STS) & mask)) ; @@ -2199,7 +2213,7 @@ s32 vdec_init(struct vdec_s *vdec, int is_4k) *todo: VFM patch control should be configurable, * for now all stream based input uses default VFM path. */ - if (!enable_stream_mode_multi_dec) { + if (!is_support_no_parser()) { if (vdec_stream_based(vdec) && !vdec_dual(vdec)) { if (vdec_core->vfm_vdec == NULL) { pr_debug("vdec_init set vfm decoder %p\n", vdec); @@ -2236,7 +2250,7 @@ s32 vdec_init(struct vdec_s *vdec, int is_4k) /* todo */ if (!vdec_dual(vdec)) { p->use_vfm_path = - enable_stream_mode_multi_dec ? + (is_support_no_parser()) ? vdec_single(vdec) : vdec_stream_based(vdec); } @@ -2313,7 +2327,7 @@ s32 vdec_init(struct vdec_s *vdec, int is_4k) /* create IONVIDEO instance and connect decoder's * vf_provider interface to it */ - if (!enable_stream_mode_multi_dec) { + if (!is_support_no_parser()) { if (p->type != VDEC_TYPE_FRAME_BLOCK) { r = -ENODEV; pr_err("vdec: Incorrect decoder type\n"); @@ -3468,6 +3482,7 @@ void vdec_power_reset(void) } EXPORT_SYMBOL(vdec_power_reset); + void vdec_poweron(enum vdec_type_e core) { void *decomp_addr = NULL; @@ -3488,6 +3503,34 @@ void vdec_poweron(enum vdec_type_e core) return; } + if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SC2) { + if (core == VDEC_1) + pwr_ctrl_psci_smc(PDID_DOS_VDEC, PWR_ON); + else if (core == VDEC_HEVC) { + pwr_ctrl_psci_smc(PDID_DOS_HEVC, PWR_ON); + + /* wait 10uS */ + udelay(10); + /* hevc soft reset */ + WRITE_VREG(DOS_SW_RESET3, 0xffffffff); + WRITE_VREG(DOS_SW_RESET3, 0); + /* enable hevc clock */ + amports_switch_gate("clk_hevcf_mux", 1); + if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A) + amports_switch_gate("clk_hevcb_mux", 1); + hevc_clock_hi_enable(); + hevc_back_clock_hi_enable(); + /* power up hevc memories */ + WRITE_VREG(DOS_MEM_PD_HEVC, 0); + /* remove hevc isolation */ + } else if (core == VDEC_HCODEC) + pwr_ctrl_psci_smc(PDID_DOS_HCODEC, PWR_ON); + + mutex_unlock(&vdec_mutex); + + return; + } + if (vdec_on(core)) { mutex_unlock(&vdec_mutex); return; @@ -3752,6 +3795,24 @@ void vdec_poweroff(enum vdec_type_e core) return; } + if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SC2) { + if (core == VDEC_1) + pwr_ctrl_psci_smc(PDID_DOS_VDEC, PWR_OFF); + else if (core == VDEC_HEVC) { + pwr_ctrl_psci_smc(PDID_DOS_HEVC, PWR_OFF); + + /* disable hevc clock */ + hevc_clock_off(); + if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A) + hevc_back_clock_off(); + } + else if (core == VDEC_HCODEC) + pwr_ctrl_psci_smc(PDID_DOS_HCODEC, PWR_OFF); + + mutex_unlock(&vdec_mutex); + return; + } + is_power_ctrl_ver2 = ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) && (get_cpu_major_id() != AM_MESON_CPU_MAJOR_ID_TL1)) ? true : false; @@ -4061,7 +4122,8 @@ void vdec_reset_core(struct vdec_s *vdec) codec_dmcbus_read(DMC_REQ_CTRL) & ~mask); spin_unlock_irqrestore(&vdec_spin_lock, flags); - if (is_cpu_tm2_revb()) { + if (is_cpu_tm2_revb() || + (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SC2)) { while (!(codec_dmcbus_read(TM2_REVB_DMC_CHAN_STS) & mask)) ; @@ -4150,7 +4212,8 @@ void hevc_reset_core(struct vdec_s *vdec) codec_dmcbus_read(DMC_REQ_CTRL) & ~mask); spin_unlock_irqrestore(&vdec_spin_lock, flags); - if (is_cpu_tm2_revb()) { + if (is_cpu_tm2_revb() || + (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SC2)) { while (!(codec_dmcbus_read(TM2_REVB_DMC_CHAN_STS) & mask)) ; @@ -4178,10 +4241,18 @@ void hevc_reset_core(struct vdec_s *vdec) * 19:sao * 24:hevc_afifo */ - WRITE_VREG(DOS_SW_RESET3, + if ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SC2) && + (vdec->format == VFORMAT_AVS2)) { + WRITE_VREG(DOS_SW_RESET3, (1<<3)|(1<<4)|(1<<8)|(1<<11)| - (1<<12)|(1<<13)|(1<<14)|(1<<15)| - (1<<17)|(1<<18)|(1<<19)|(1<<24)); + (1<<12)|(1<<14)|(1<<15)| + (1<<17)|(1<<18)|(1<<19)); + } else { + WRITE_VREG(DOS_SW_RESET3, + (1<<3)|(1<<4)|(1<<8)|(1<<11)| + (1<<12)|(1<<13)|(1<<14)|(1<<15)| + (1<<17)|(1<<18)|(1<<19)|(1<<24)); + } WRITE_VREG(DOS_SW_RESET3, 0); diff --git a/drivers/frame_provider/decoder/utils/vdec.h b/drivers/frame_provider/decoder/utils/vdec.h index 0a526d0..54c5903 100644 --- a/drivers/frame_provider/decoder/utils/vdec.h +++ b/drivers/frame_provider/decoder/utils/vdec.h @@ -468,4 +468,6 @@ int vdec_get_frame_num(struct vdec_s *vdec); int show_stream_buffer_status(char *buf, int (*callback) (struct stream_buf_s *, char *)); +bool is_support_no_parser(void); + #endif /* VDEC_H */ diff --git a/drivers/frame_provider/decoder/vav1/vav1.c b/drivers/frame_provider/decoder/vav1/vav1.c index cba2890..f8b03a3 100644 --- a/drivers/frame_provider/decoder/vav1/vav1.c +++ b/drivers/frame_provider/decoder/vav1/vav1.c @@ -3635,11 +3635,11 @@ struct loopfilter { //LpfSuperblockInfo neighbor_sb_lpf_info; //#endif // LOOP_FILTER_BITMASK }; - +#ifdef DBG_LPF_DBLK_LVL static int32_t myclamp(int32_t value, int32_t low, int32_t high) { return value < low ? low : (value > high ? high : value); } - +#endif /*static int8_t extend_sign_7bits(uint8_t value) { return (((value>>6) & 0x1)<<7) | (value&0x7f); }*/ @@ -3710,10 +3710,13 @@ void av1_loop_filter_frame_init(AV1Decoder* pbi, struct segmentation_lf *seg, struct loopfilter *lf, int32_t pic_width) { BuffInfo_t* buf_spec = pbi->work_space_buf; - int32_t i,dir; + int32_t i; +#ifdef DBG_LPF_DBLK_LVL + int32_t dir; int32_t filt_lvl[MAX_MB_PLANE], filt_lvl_r[MAX_MB_PLANE]; int32_t plane; int32_t seg_id; +#endif // n_shift is the multiplier for lf_deltas // the multiplier is 1 for when filter_lvl is between 0 and 31; // 2 when filter_lvl is between 32 and 63 @@ -3730,7 +3733,7 @@ void av1_loop_filter_frame_init(AV1Decoder* pbi, struct segmentation_lf *seg, | (lfi->lfthr[i*2].mblim & 0xff); WRITE_VREG(HEVC_DBLK_CFG9, thr); } - +#ifdef DBG_LPF_DBLK_LVL filt_lvl[0] = lf->filter_level[0]; filt_lvl[1] = lf->filter_level_u; filt_lvl[2] = lf->filter_level_v; @@ -3854,6 +3857,8 @@ void av1_loop_filter_frame_init(AV1Decoder* pbi, struct segmentation_lf *seg, level = 0; WRITE_VREG(HEVC_DBLK_CFGA, level); } +#endif // DBG_LPF_DBLK_LVL + #ifdef DBG_LPF_DBLK_FORCED_OFF if (lf->lf_pic_cnt == 2) { printk("LF_PRINT: pic_cnt(%d) dblk forced off !!!\n", lf->lf_pic_cnt); @@ -3896,6 +3901,9 @@ void av1_loop_filter_frame_init(AV1Decoder* pbi, struct segmentation_lf *seg, { uint32_t cdef_data32 = (READ_VREG(HEVC_DBLK_CDEF1) & 0xffffff00); cdef_data32 |= 17; // TODO ERROR :: cdef temp dma address left offset +#ifdef DBG_LPF_CDEF_NO_PIPELINE + cdef_data32 |= (1<<17); // cdef test no pipeline for very small picture +#endif WRITE_VREG(HEVC_DBLK_CDEF1, cdef_data32); } // Picture count @@ -5943,10 +5951,14 @@ static void config_film_grain_reg(struct AV1HW_s *hw, int film_grain_params_ref_ void config_next_ref_info_hw(struct AV1HW_s *hw) { - int j; - AV1_COMMON *const cm = &hw->pbi->common; - av1_set_next_ref_frame_map(hw->pbi); - WRITE_VREG(HEVC_PARSER_MEM_WR_ADDR, 0x1000); + int j; + AV1_COMMON *const cm = &hw->pbi->common; + + av1_set_next_ref_frame_map(hw->pbi); + if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SC2) + WRITE_VREG(HEVC_PARSER_MEM_WR_ADDR, 0x11a0); + else + WRITE_VREG(HEVC_PARSER_MEM_WR_ADDR, 0x1000); for (j = 0; j < 12; j++) { unsigned int info = av1_get_next_used_ref_info(cm, j); @@ -6593,7 +6605,10 @@ int av1_continue_decoding(struct AV1HW_s *hw, int obu_type) cm->cur_frame->segment_feature[i] = (0x80000000 | (i << 22)); } } - WRITE_VREG(HEVC_PARSER_MEM_WR_ADDR, 0x1010 + (cur_pic_config->index)); + if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SC2) + WRITE_VREG(HEVC_PARSER_MEM_WR_ADDR, 0x11b0 + (cur_pic_config->index)); + else + WRITE_VREG(HEVC_PARSER_MEM_WR_ADDR, 0x1010 + (cur_pic_config->index)); if (hw->aom_param.p.segmentation_enabled & 1) // segmentation_enabled WRITE_VREG(HEVC_PARSER_MEM_RW_DATA, READ_VREG(AV1_REF_SEG_INFO)); else diff --git a/drivers/stream_input/amports/amstream.c b/drivers/stream_input/amports/amstream.c index fbf6517..75a72a5 100644 --- a/drivers/stream_input/amports/amstream.c +++ b/drivers/stream_input/amports/amstream.c @@ -123,8 +123,6 @@ static int def_vstreambuf_sizeM = (DEFAULT_VIDEO_BUFFER_SIZE >> 20); static int slow_input; -extern int enable_stream_mode_multi_dec; - /* #define DATA_DEBUG */ static int use_bufferlevelx10000 = 10000; static int reset_canuse_buferlevel(int level); @@ -907,7 +905,8 @@ static int amstream_port_init(struct port_priv_s *priv) mutex_lock(&amstream_mutex); - if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A) { + if ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A) && + (get_cpu_major_id() < AM_MESON_CPU_MAJOR_ID_SC2)) { r = check_efuse_chip(port->vformat); if (r) { pr_info("No support video format %d.\n", port->vformat); @@ -960,7 +959,7 @@ static int amstream_port_init(struct port_priv_s *priv) get_esparser_stbuf_ops(); /* def used stbuf with parser if the feature disable. */ - if (!enable_stream_mode_multi_dec) + if (!is_support_no_parser()) ops = get_esparser_stbuf_ops(); } @@ -1614,7 +1613,7 @@ static int amstream_open(struct inode *inode, struct file *file) } } - if (!enable_stream_mode_multi_dec) { + if (!is_support_no_parser()) { if ((port->flag & PORT_FLAG_IN_USE) && ((port->type & PORT_TYPE_FRAME) == 0)) { mutex_unlock(&amstream_mutex); @@ -1717,6 +1716,7 @@ static int amstream_open(struct inode *inode, struct file *file) } } } + return 0; } @@ -3432,6 +3432,46 @@ static long amstream_do_ioctl_old(struct port_priv_s *priv, */ break; } + case AMSTREAM_IOC_INIT_EX_STBUF: { + struct stream_buffer_metainfo parm; + struct stream_buf_s *vbuf = &priv->vdec->vbuf; + + if (copy_from_user(&parm, (void __user *)arg, + sizeof(struct stream_buffer_metainfo))) { + return -EFAULT; + } + stream_buffer_set_ext_buf(vbuf, parm.stbuf_start, + parm.stbuf_size, parm.stbuf_flag); + break; + } + case AMSTREAM_IOC_WR_STBUF_META: { + struct stream_buffer_metainfo meta; + struct stream_buf_s *vbuf = &priv->vdec->vbuf; + + if (copy_from_user(&meta, (void __user *)arg, + sizeof(struct stream_buffer_metainfo))) { + return -EFAULT; + } + if (!vbuf->ext_buf_addr) + return -ENODEV; + + stream_buffer_meta_write(vbuf, &meta); + break; + } + case AMSTREAM_IOC_GET_STBUF_STATUS: { + struct stream_buffer_status st; + struct stream_buf_s *pbuf = &priv->vdec->vbuf; + + st.stbuf_start = pbuf->ext_buf_addr; + st.stbuf_size = pbuf->buf_size; + st.stbuf_rp = pbuf->ops->get_rp(pbuf); + st.stbuf_wp = pbuf->ops->get_wp(pbuf); + if (copy_to_user((void __user *)arg, &st, + sizeof(struct stream_buffer_status))) { + return -EFAULT; + } + break; + } default: r = -ENOIOCTLCMD; break; diff --git a/drivers/stream_input/amports/stream_buffer_base.c b/drivers/stream_input/amports/stream_buffer_base.c index e6dc5f1..d436441 100644 --- a/drivers/stream_input/amports/stream_buffer_base.c +++ b/drivers/stream_input/amports/stream_buffer_base.c @@ -88,8 +88,10 @@ int stream_buffer_base_init(struct stream_buf_s *stbuf, width = vdec->sys_info->width; height = vdec->sys_info->height; - memcpy(stbuf, get_def_parms(format), - sizeof(*stbuf)); + if (!stbuf->ext_buf_addr) { + memcpy(stbuf, get_def_parms(format), + sizeof(*stbuf)); + } stbuf->id = vdec->id; stbuf->is_hevc = ((format == VFORMAT_HEVC) || @@ -110,13 +112,38 @@ EXPORT_SYMBOL(stream_buffer_base_init); void stream_buffer_set_ext_buf(struct stream_buf_s *stbuf, ulong addr, - u32 size) + u32 size, + u32 flag) { stbuf->ext_buf_addr = addr; stbuf->buf_size = size; + stbuf->is_secure = ((flag & STBUF_META_FLAG_SECURE) != 0); + + /* + pr_debug("%s, addr %lx, size 0x%x, secure %d\n", __func__, + stbuf->ext_buf_addr, stbuf->buf_size, stbuf->is_secure); + */ } EXPORT_SYMBOL(stream_buffer_set_ext_buf); +void stream_buffer_meta_write(struct stream_buf_s *stbuf, + struct stream_buffer_metainfo *meta) +{ + u32 wp; + + if (meta->stbuf_pktaddr + meta->stbuf_pktsize < stbuf->buf_start + stbuf->buf_size) + wp = meta->stbuf_pktaddr + meta->stbuf_pktsize; + else + wp = meta->stbuf_pktaddr + meta->stbuf_pktsize - stbuf->buf_size; + + stbuf->ops->set_wp(stbuf, wp); + /* + pr_debug("%s, update wp 0x%x + sz 0x%x --> 0x%x\n", + __func__, meta->stbuf_pktaddr, meta->stbuf_pktsize, wp); + */ +} +EXPORT_SYMBOL(stream_buffer_meta_write); + ssize_t stream_buffer_write_ex(struct file *file, struct stream_buf_s *stbuf, const char __user *buf, diff --git a/drivers/stream_input/amports/stream_buffer_base.h b/drivers/stream_input/amports/stream_buffer_base.h index e7a107f..3360e64 100644 --- a/drivers/stream_input/amports/stream_buffer_base.h +++ b/drivers/stream_input/amports/stream_buffer_base.h @@ -44,8 +44,9 @@ int stream_buffer_base_init(struct stream_buf_s *stbuf, struct parser_args *pars); void stream_buffer_set_ext_buf(struct stream_buf_s *stbuf, - ulong addr, - u32 size); + ulong addr, + u32 size, + u32 flag); int stream_buffer_write(struct file *file, struct stream_buf_s *stbuf, @@ -58,5 +59,8 @@ ssize_t stream_buffer_write_ex(struct file *file, size_t count, int flags); +void stream_buffer_meta_write(struct stream_buf_s *stbuf, + struct stream_buffer_metainfo *meta); + #endif /* STREAM_BUFFER_INTERFACE_H */ diff --git a/drivers/stream_input/amports/stream_buffer_interface.c b/drivers/stream_input/amports/stream_buffer_interface.c index 71e83d0..e8981ed 100644 --- a/drivers/stream_input/amports/stream_buffer_interface.c +++ b/drivers/stream_input/amports/stream_buffer_interface.c @@ -31,6 +31,7 @@ #include #include #include "../../frame_provider/decoder/utils/vdec.h" +#include "../../common/chips/decoder_cpu_ver_info.h" #include "stream_buffer_base.h" #include "amports_priv.h" #include "thread_rw.h" @@ -88,6 +89,8 @@ static int stream_buffer_init(struct stream_buf_s *stbuf, struct vdec_s *vdec) if (stbuf->ext_buf_addr) { addr = stbuf->ext_buf_addr; size = stbuf->buf_size; + is_secure = stbuf->is_secure; + pages = (size >> PAGE_SHIFT); } else { flags |= CODEC_MM_FLAGS_FOR_VDECODER; if (vdec->port_flag & PORT_FLAG_DRM) { @@ -103,12 +106,11 @@ static int stream_buffer_init(struct stream_buf_s *stbuf, struct vdec_s *vdec) ret = -ENOMEM; goto err; } - - ret = vdec_set_input_buffer(vdec, addr, size); - if (ret) { - pr_err("[%d]: set input buffer err.\n", stbuf->id); - goto err; - } + } + ret = vdec_set_input_buffer(vdec, addr, size); + if (ret) { + pr_err("[%d]: set input buffer err.\n", stbuf->id); + goto err; } atomic_set(&stbuf->payload, 0); @@ -123,16 +125,18 @@ static int stream_buffer_init(struct stream_buf_s *stbuf, struct vdec_s *vdec) stbuf->buf_page_num = pages; stbuf->canusebuf_size = size; - /* init pts server. */ - ret = pts_start(type_to_pts(stbuf->type)); - if (ret < 0) { - pr_err("[%d]: pts server failed\n", stbuf->id); - //goto err;//fixme + if (get_cpu_major_id() < AM_MESON_CPU_MAJOR_ID_SC2) { + /* init pts server. parser register w/r inside */ + ret = pts_start(type_to_pts(stbuf->type)); + if (ret < 0) { + pr_err("[%d]: pts server failed\n", stbuf->id); + //goto err;//fixme + } } - /* init thread write. */ if (!(vdec_get_debug_flags() & 1) && - !codec_mm_video_tvp_enabled()) { + !codec_mm_video_tvp_enabled() && + (!stbuf->ext_buf_addr)) { int block_size = PAGE_SIZE << 4; int buf_num = (2 * SZ_1M) / (PAGE_SIZE << 4); diff --git a/drivers/stream_input/amports/streambuf.c b/drivers/stream_input/amports/streambuf.c index 20aa640..8243f56 100644 --- a/drivers/stream_input/amports/streambuf.c +++ b/drivers/stream_input/amports/streambuf.c @@ -265,10 +265,11 @@ u32 stbuf_space(struct stream_buf_s *buf) size = size - 6 * 1024; } - if ((buf->type == BUF_TYPE_VIDEO) - || (has_hevc_vdec() && buf->type == BUF_TYPE_HEVC)) - size -= READ_PARSER_REG(PARSER_VIDEO_HOLE); - + if (!buf->no_parser) { + if ((buf->type == BUF_TYPE_VIDEO) + || (has_hevc_vdec() && buf->type == BUF_TYPE_HEVC)) + size -= READ_PARSER_REG(PARSER_VIDEO_HOLE); + } return size > 0 ? size : 0; } @@ -432,11 +433,11 @@ void stbuf_release(struct stream_buf_s *buf) int r; buf->first_tstamp = INVALID_PTS; - - r = stbuf_init(buf, NULL);/* reinit buffer */ - if (r < 0) - pr_err("stbuf_release %d, stbuf_init failed\n", __LINE__); - + if (!buf->ext_buf_addr) { + r = stbuf_init(buf, NULL);/* reinit buffer */ + if (r < 0) + pr_err("stbuf_release %d, stbuf_init failed\n", __LINE__); + } if (buf->flag & BUF_FLAG_ALLOC && buf->buf_start) { codec_mm_free_for_dma(MEM_NAME, buf->buf_start); buf->flag &= ~BUF_FLAG_ALLOC; diff --git a/drivers/stream_input/amports/streambuf.h b/drivers/stream_input/amports/streambuf.h index eb6ff8c..1c14a59 100644 --- a/drivers/stream_input/amports/streambuf.h +++ b/drivers/stream_input/amports/streambuf.h @@ -37,6 +37,10 @@ #define FETCHBUF_SIZE (64*1024) #define USER_DATA_SIZE (8*1024) +/* stream_buffer_metainfo stbuf_flag */ +#define STBUF_META_FLAG_SECURE (1 << 0) +#define STBUF_META_FLAG_XXX1 (1 << 1) + struct vdec_s; struct stream_buf_s; @@ -138,6 +142,29 @@ struct drm_info { u32 extpad[7]; } /*drminfo_t */; +struct stream_buffer_metainfo { + union { + u32 stbuf_start; + u32 stbuf_pktaddr; //stbuf_pktaddr + stbuf_pktsize = wp + }; + union { + u32 stbuf_size; + u32 stbuf_pktsize; + }; + u32 stbuf_flag; + u32 stbuf_private; + u32 reserved[16]; +}; + +struct stream_buffer_status { + u32 stbuf_wp; + u32 stbuf_rp; + u32 stbuf_start; + u32 stbuf_size; + u32 reserved[16]; +}; + + #define TYPE_DRMINFO_V2 0x100 #define TYPE_DRMINFO 0x80 #define TYPE_PATTERN 0x40 diff --git a/firmware/video_ucode.bin b/firmware/video_ucode.bin old mode 100755 new mode 100644 index fb22598e1b78d1c3c0601b021ed914e1dacf3b10..ca48cd667d392fc59f6d67e4a29af3d25d73150c GIT binary patch delta 30874 zcmeI5d3Y2>{{O4HXS%v)CYekU5)vQ~j&LNzkccRWq(YPpAOYkO5R#yrLO@Z#i&R`i z4#gvDYS)8P!9|osblQ_GRCYlTMa2VMyzdnkR8-F2r@DH`Oh}9)@a6Xhc^;mcp6=!ZyB)|X$?qx`4q(}vyI_N6@|@Bi?< zo#Qv}a`(Qk`CFbVdVZg>a`aFBZw{|()p|wV#8pq~kE|)%kh}Jdb?>|sxWD$cq8Fdt zJGrX&vg&INojdUG)NX5^h`H?TDXqWyVOsC2vY2sD?{_omPOFj?&FmmU{ONIq6K?N-~j7d{>?i^=`>+NUiX}C-Lm_RAJ;86cU(7A_cwFWQY&^!Ee6(abFS0R=% z#CvIUC1{`lny3b7g0O1nX1zPqo1<7poOf7sIiJJ^Nbr*2{n2*42J&yB>p=$y>v~}w zU@7F^rCF3+|0L$$wHXP1nRxp0|0a>t?u~I1F$+A1M9UC&Ce zvR={O$_h?Bt;G=Yz~lOf&jU>~1k3|rqXFiDVTzcD*XdDC#0|_q(dPUQy^~T~9Orq` z6F21a^uGYifLh$Ig_bfeF3OreS@VD>!UDSp#iz3fed3`1na}%&p1y|Q{)2^q0Z%Oos|vB_R};2$0!?II}Q~FM<`L&{YmI`mngTWQH`{dkmoQZSJ~iEqnzPR zLdKUs#+GNO@_(PRc-Y+FDv1(tq90ogKWc~$)*m|9m}ooL$t!^6Dp#Ncfzw%nMCEYd z24&G{9Oa7-6+Z5ca*&_AHrU`YjsoEH^DBxgIQ_dPYWw-yuulE`-J_ZS8Ys`%zb$~k z4d;o51d!TYv0b%oiVp;x_H5`uy=%tB*ZSb`08!;ypOIdqBhMUr8zBxUL43R-wymWD z{LR#)@{ZMd-=Yd{dH-tN+*Ix@&#%_Y^R1T$`WMG&RI6fT=lRB1PmS^aMX`@9agH_W zjvZI#pQmYb&0JRYj&Y4uewqKTBWruQ;feH}*i-&Q+UR|FSL_UR=4H&+-`|p@y%XD3 zY*cKDZ_O%}DJ%7_u78j@dv%0nUY3hk*1NIYPFEWa@ORaMp*9?4c5U5Hwjnt<$8JNe zN46p3yJA~1p5Z%}wJG(tirKCB3?Fip@MRvJ$NH7}+bQ2#m8JeZN>ZEFvVq$a%LZwFqJ@I`F4b@?d&dx~<6)$3A!s-kgI_F^a;)%n+K;~0OH zvWoQ@>u;xih?w`=*v{;>vHqv5%gg*lin5KZD)%2%o@1*j{9mR$R%K_&AC;*N18QEt zXXNT}K`hxggriWL0M7iY%L@1LJ{oBIjo+}P5 z^N^$R#Op-Gp3Tyx_|sU{Sus8~Xo`P+D)~X~y)#xZvfo5HQjo6$)Fj`__M8=y#^SE< zf33X64qV|cQ(m)1P4%xD1ghu_3WgqCRxzs^3v4!$S=v$cSog1~aIf@!G`U|w_z^BK z1n%jg<(=aGPa2!URIRJF8aZDe|MuYc zk=t@i_77E~D&53#HEo3QKekZQW-4DMTiQGBeoTN@srKdZ7geeN_d`@36vPI-Zi zeaGlx-KlFgU=_u&*jVio6}`sx#cKUjt9LQ8aTwTu4=Bmtty=LZK36>DBYUZLh~wFbfU+IrPx5LJw9ml+mtUohObDk zhBhvN-eRJ49$x}-#lmPI?D>{jYr~v$vtDu&QrSl>wUz<8xyomBfFZh37Mxfytu#$h z5DTPf6BWv?P1D-J)≺86=0(G^UaVSZ!;qR|ff;;@i@U>V1ne%A)U;@x)=6>ExyZ+Idia{LO=oL0DtXiz-d&rnD0j1eoulRB z6}Ncjr*mv2_R!*>Q3kqvCNzmXi}|hGLT$SWp%o)|R6TLtXyX3f*w_fFn$Q$Kaz{yA z4Um2lC4l)Uj4+OAiWw(CQ;as}s}n?2<5TyEM>U$rxv^Sb^@W=RA2QOoDi}U8J4(vuzXYe%x65C0^+F zKgUP;aC_25`H!a|=VExCw_Jy#%{lsKr<_K5`GW~L!2{81btj?9N87=goP;PFJNgT6 zbb8B6Ai-G)r+j*8EdSuO2`*x}W=2~BC!y|(feM0~qHXl(tG=;5x9X+%90*UCmidnB z#KSaAOf%(;bo^DbUFE^6U8lVL8_Pd9+ohCSO3!GaCi-S*tOTphcb5m<(T43$LjT(k z5R+c7#8W=@8|#3vQjNsXCmf+`qW3jcf>qwcoZ8`D@a$Zfc;ex)CJNE$6m)gs zn4(imIE_|-m6#LEKMkD^S{}Gsah-Cmp3&IE<8sXiEHudQA;5VjA(Y|$L$sj zGTU!L`a}>(cn{bIx*KY#`dG{NV_T*g7gc!p-BK{7w@A%bNYYeg8xQHpxqqJHJ0ir( z+UsoLZ9eP@Nxb9<`JIr6L*MZZ*R#ySdb)=+SAC0xK6)b?epsKSq7H2PVZDpW-R!_& z{T!92vDh(YvQo+V9nsUOh)4Bphr>hXp>Da&r#MA=9f}l^mNnH^Dvq7(?0asRhr>Ri z!f!PA{!J+FuZnMwDE9;qBR9c*B&&)ST<`c zv183qIa@&Sn|~`cx4=K6y`oQyfs?yb-&gRx*k_>2J><`_?)c3hWPxUt&N^>1k`-zd zZ8KIYvE(z*>paLcu@h9qr`GmzbA-YMyk-m(N36p4DJq@BcCW@OKmx3O7!LtCuGS@yDlx6a6U@14GxU`6^Bjsz zPIdEcq;fWGEgr3+^=$5BGXn~^cP*Z+qSYXOn>_<$rThhjdQOM7AuRBY(b2<86(5Gn z=iOK@A5K-NE|l8dZkTS+LbeN56H$PFy&sOOM{EbVcPqRH&n@J*q@z}>u^-6O#{8OWc(u^(s z)L6>gJ$%VV=zJ`vRZMf1lY&#M^FK4NsnUG5J00&+Q8x3ugvY9=6Pp5Q3TigTw>3a< z={VvkO(ZVTTDQX{lzsdX&QwuL7P}dbZjHuy=s{Tl7ik0!03|ps5xKmy+=C8O`Pg&c z8+Vyr`BUy;d)ng`ipj=~G(c~4vB&K6QFdgcu}JxhRsI{FrF_Gdh-4qz{%_ndtVqYgjbTpO4Zoxg2Ic(NGXw;Fi4FglfH7JoCR3mWlRDi zJn0gG@w-wIJ2k1T%&TPQ((EBiX3XU_NpqAUW z08(PH#XlLDZ14heCA)OLaU~nS(1e~=#~`}G1vUm8G@7%+i%sZk@9Dk;&;$7;EIS`3vkrHdnQ)H5cfe%B+2lLSFIBpV zJ#)xt5!V~?PosK?7|N~TI@p3c&GzaVH+!uBw^Hf(Y)=8sP*FZhIv-bhcy}mv2PkfL zR(Y3sR)_E1cHa~;3)!pNpTk1}TS4t7*=*07xZRlj^3W~KWmOYs0#Vhpb6r*QcXVGT z4MrwJ6-4ByWL$>1npErLZKymLL8h3KGvx8cxLmWuo$j3v@ix+dEjeQ3D{a}_yUqNn zo$}0{6pB4i)#!P*&jUH3_Si09KV3E%dQyHbVi^c>*cJ?Jjdf{PQl~g056w)Rkf{Ot}0x7kmE#++8J4 zvtIARu)T+kdLNfUFMQ8!W|@!OV2>4a7K_!*vW^em;B&b(!-N@mD_ZU`#f_$y>>B7i z7&KyLUUh@d+BCskc#ie@1b4I4;0Rz0*EJVb^{gFXwqYcooL%o|@8Dp4a4DuU{(aT|sb`E32*o<+nyiX#weze&xk1uq%;(-RZ;@RW5f@DjsFiC64 z6>y)t)P(y_mV*^O2P-r!llNLDOsO%l#l*(DDtan`%dakgP?A8L$)$}W(YKy6GYQyQTJ9!?2a z%I}1Pf#26G*w>gcr|y zwqZ;lrIDDx9ZV3oATWVjY-~0z?zRC+oeUE;q%nQ>kHVa&T{z zPGx&?@Sl{0ENwfUX(r3sq19}Ag^>$GLK$apb0%DkpqH!IW4Sm#WjdS*;FnfHF$4rd zxAh4 z*x(v7QT+z)p85Ek^inuESOg5Hj`^u@^B(|J;%sk$ZBojz#~VGG^@a1bgu`0Gy}uun z3qI4nEW1El;zMlXc%x&W2+kBnR*0}Q1-PC1u#Hw}O1>bgj>>rgtfrf1!#RMfXdYX9 zK0d3%o;t2V-#5%vG)r(*+p*-wNU);YC5rHlb$yfWY#6N2TXkT?+aC{Bv>mH_3+F3s z*pgm2|NJ*2!HPg97GTBGBf*M5uN2=4u;On@u%hp>{db#bE%>Vq0~FcjW&;axn!3Tw zrWfKQ^${DKrm!6~W^=_Ocehd_*?0CA;v5_>GZ#gr2wg z=p2|j0gqBuRLin2#Mdih*qRG*=2>eUKFZR4TcJiGz^KRpqXG#=^zY$dv@<1`Z2%bU z%ouiSZMG2tqxJWxtdRu2nQt4dwcCK-;M+hH_Mdz6#bd%Xiyx^Nm^#_F=1ldHGWtKw^ zp_2vQw66MDiBL`WK4%+L4`JRb2~$nbUd6^6a(N`)(C^_lj%tFwl&T3D7l}6{OX3ab zCokE-8=Y-ij_0fB7dE`RF)KhIhp%i|#9#TEf#Hu{4!Pnt;oIE*%IC4lkDTlyq{x{{2R*oE!ay-l+Eaed7 z$RUO!hkPB9LmqMDkTnj>yxtrSww@kf%r;b*t)<#g;HVwvG@^ENjZ{0jM4@)1IBG|8 zTkT+DMuOyp*rSlB$d)=5s%<`EX}6eXDW9`ak$lJI-ePu4`4#SRjcXmOVzlvdJoyrC zK|<>I0#YG$d=V*id?;_)e78*NBMh1*Z@v8ey4%DtspGvch9QCRkq853RVj6Bk!LKGl#FyvowoM4yDa6=SQ$7aDWy}O}JP;db&9QF%%fmA>Y{U_XV#Wth@V(3QLFJOj! z2Mm)d?m7Zugwi4)hKMu_V#w359R@MvDFHF_;`usR+z`d^$Jk@raFR#BkiZzeHUeYF zP=PW1JbWeW296;s1;=zz>9TN;=>w9WAepO7)Irt~Vy{*hd6H!Q>ERTv31%`v1;l~s$z*Dd!*2OKsNFe;dudcG!kT> z(*wt7^hZbT;rpcAqY}&(_Qtg^pG*Ui@dB#YY7hC;QG3J(TkYZROSOl*@2EZGO{wru>Gy2= z3Y>H-oI)eE&o795ShKfT0r_0+{80$88`t8P73Jc0335k^qC! zZGeH6+e?h%2BjDX=kQd?FEr_RejzSfjM4aE#O|mxZx?|<5zv8}9}Hp`TA8)g`k6JnUVZZfl!tlx()w{6CE zdQeN}r!Axy!&79)h9`!HY=C1vmK*~RA~&eyYA)?A{p{Qh-8X>G)UZ}NRpwf;${5e zdGr-|;`$&%$JX6uMa%|mh2sEVDBK|g$iS+BS1YH5K~vhb{u6QTXN870b1Y2%V7b~@*TKGTT%{Z4kH*+2K5p~FsNJ- z3?Bt0atMY4gB@v(w=iP;C~3g{?$*%MM$imu-$=Bj3jZRa!1onJyms&tqY$-S6YEoe*$MQ*kRE z43}rdvRyRGchU>>EU1oLB8GCFvgO zc!uE#7GhteUT)0s_2mzF`mR{X)*aSUs!CQ=drCktG;X4919p_qhdlhS2;dV}KefVy zmrdxxLF0qimj`UF{a&2zA^WARWI+-H_EB5gIx9?ew+iR)Rk`N;AsmZ%mN*CcRURws zJtBTKAL3_3lLdv?B`Z6kn^nm15QVJD1SBvaPc>v!7SX(hXiT_>LqRusuwkn*?bWDN zd7%kq2sxEk;EUl2W&JBg%NCHE2*3$rkwM2d;7xw@Y%Mv}K-GE)_>c@J^n5#Y;&s#R zsl@Zx)RlNMyM3N#gthEJyi5_&mu*x=QyLYvdQ{N|uy5&~=9s3dx89d=c(jksxXiC> zT<8*}WgmL-PD!YZ!k`x^-m#zCd4ydT+RQZ_cAgOzSM*)1yEfnK7<94L0)V)yW z<8?2dBuz*pP6qBsa~Zfpzly*ec#xizvKN0^%3dl>6+Y&3RFvGPk@@uktphtR1;+_D zvtfd-0>XPgfY#M>k5Q&%G%SqKRv}?5@V$|xr2cMU>@E{RFhYz%rqsnij<>DMM2*zN z%0G2nN?$oHrM-?z=@9(3VQFmREoKj87VEPGTuSf2L%4`bixege`gVjeCfulYA)K_n zGDgNYF)8pQiJ=^BXXaZ&%Gjn`O%fO$sf?kqGRB7>m?mU0|+jnN<+CnPaQ zg)~N=WMe@a>jr)#A&n78g*3*&k0hiq0;!P3_&;F3ki;Mr(imSSr7;9Cxvj8Gg+U3V zF;vf}gz6cU(3)e?*o?q(S!5`-?N)+-9mM&Lxs~V=JIohyR;wWF*l|934-^H|F=YFd zx~SytNOg=Zu;Y9lo+N9E(=d6An^(bwiSA%qmU^a=N;sQP#il`FgenH9P{;UGsg6M; z&o(XD>ew;UQb-&VaW@g?;|Jg@AmfBw#&oER^C8=|1aZEQZK-=(J^(TZ6Uq2Rks=vH z>+CQeDS=ZuA{hY_lMu;x35&hcELI*A8d-~zG#NEP5YLr8u2aFSI5GA zOCfcP!a@QBe~lT!f5XpYD{{6W{E|Z4te&x{;@IjNnl6Ha$sC94sLd`+~b8_#v>h2_6YU90JdCMYaw`H+dl4@5673#axVv`I_p$~CnXTaBSk}Q z@}q9{p<>pmps-0RxpYZ^m0a4Sz)JqEw3372NmK%TGh`))54I?Wwn(+g!f{$3(!pun*Ac6_Mi`ME za>OdO{*d0z!)v5i1_|rv5lhh=pEWn+GBR`x0P40Q zdWu;k-)o6}WP6V2Ez}!T_Rq78T3AwI%RFeJSdhNByU^f-V#DDrkOE4D&{KZ}83AcX zh(MtgWc0~t_*O+Fcd`8n9uYu(`>L^8B){%G8j+b{L*O)C}6^Gmi z$ANmo!JRBr9Kyzk#b#&@6dKeTIvaLFiXas#4xJ@c90aLQap*O$A5z42WD8#uXd*(y z;a5r#hln)Xs67L=!;RY0g;6_MnaZ-a;e7T$nUNRIC&-dR>1{EGk9SPlmqV7qw0)UW zb3h=3b@Iuqvsig%8-avno81U2&r~|Xacp;%J||vk`<#sbI4hCZ`ffN+;|Fy1+IIZB z$$P-nL1hv4s91bP^B^ZsZV;qG$)UNhTWm8W58nMiyI9xd;e}ZEO44?KW<%D=79lxU zo@SjiIt{I>YTL5C);2n^D`9y)49x}kV01#O;M8Fn4tfYGD9q@@AF?%^W^@@8$sD!aL1&?9~E$uKEsEo~is!$KtdIP9ZE#i|jT1 z?fcX@oKT@$*;Ri{KVl!B4@>$Hywm`}U&y8{My0SJk*d0mO0r=*XfV6gThq_8@Ub=h ze}s&~t5*_LY%K&yY`kZ!bM-hvl07ZnBi&5)PRZwx&Nr zp8L2p{m!sEwx(b8>TF;Q%v_qzCf1l!l zsC*BL{TnDRL1w$UHQ56E=HnNs@xM78;xAB7pduqn>4QJ@sq_=}#l?88N_VjdLvY&^ z`Vs6ee^j5}n(F>HZuh=c46l4a@TLy7dwcs=Y#|FIYzZOAB1=+$vME6nLH4jlK|)YO+(@CLA}WH8 zsS!sEi-8eA1npK-EJa6fK~ZF2K82_ZjyePfR0IXSTd!V|ZW73mCUVaA;W=8qe%0?* z)w@;q*Z*57S~Y@xer@U9C!hT}^{XAt)j7kT_`3gFudX?{?}I~66n)u$$IRY+Cp`CK z`h4oK@fkPb()G{ioex}{@yKu6W?tW`*UY199{=LtubbmW9^RLl-!paQp3jCH z3Hxi0Qy`p!|tI*U$ zlzG(m%kam>;AM}cD1(DR+i0cbq>1A?PV6{7yZzmIahT`$^lm5_U#?V3N_@(Z?m@gF_Me{+eccG5Py zzI%HHH^aiq*T%=b#^j!TaVtTHMlNo!#aUjxfgGs_tAkg_=8>QYid${T<9 zh;P_s5d+>OzTOACmdV{xspuA85`4!K`vmJy=aM@2v?UdcZ}F4_o5t0<@j`@ZG5)%{ zFu2iu;f$9Jv$;cV8W;PjUdPzi-u-*x3WFV7_1=9_>)3a4k>GdEdN+=ujhl1r2WRYa zt&SnDz1N4GBzWKt?{#RGT+u3acT+|5cD#8%XC)9uMPcsazE&%2WrQUm7`#Z0Mcka`zigi`aZ>}<* zp2Aw{ddFBJdmV#ce%jz0EL9e-wzZ;P6b}d;&DoFyN0!TVn+Jvqp>=G2y!t4nLs{~> zT5mSauQ&FPe%RCUQ(~uWv4{QeqoYZ@^U85<@{D49g|Zj?db*qZdA8>SM^3(k?eXi4 z6vU4D^-N3`v$TNT+D$XCX91#i@(>#u&}U)Nfo+4&MYVw58H)BvdH|!lSi&K1azmPg zJ=>r*Qf3=AxGt|Lo13KTrO1ap1#p|+I@@y+Z1(%D+)c2oN;IfyfvQb%vPrp-w-u4!Tp;nVX=nm500!W8`Ox z8|r0lv{3QP>&_jNv8oknBOi*xo_{A$hZB|CoedN_zk}_0PrHwmKcl|Q)-~3jH0h}}t6xWzl<|3yZ3ocYwT1ub_w-&|&VPG&0}Hw=e! zGt@;(W!-hMTjc9f`JK3)cBe1d)sLpS$t{XU74~N~y5R*q(LYnT! z+!ET9r_I5B@{;+K9O`g!YIi+~FnW$T@+vS`U`XEDJij`DW+)D4A*i`X2dAS{W zY_xr41NgSi#`Mu9V-(M_TkDS~9=55q{_d|Ix-^(w-GV*^ng8_H6Z1N5OdFE@(ikw58qCA6m#+`+%>l(t>4= z&_*hR6(7(7alFutj>(>|QF;0zR|B)M&Wbxh`+aQ8NNtc3&(@CA3gBhFkgq?83y-kk zgV2!5-`El;Eh)CS?4yHP3vZz|_f)qs$=!CsJ|lWNCnUG%HR9VQg*p+b@QP*|J6FMxqb9*ZeC_H`a#OroDbDN zgBEs=^JZcrkKJX=rp(Lkwj=i6K6=277TqN$wZ^i?YI$CgEUUT|>KLGK2Vvv->YFj4 zY|l0|kOEzH!GoM|7o5hy?*cncXatlGK*`zYetPfrbT+gpKxFqsmYk>dRR*!D?dr|WFKosD!b`nE?_fd4?Cj}J)J?7~ z&@bUGo!OpzwOi69@F?M-9iSypA}Aja*Gw6x--=Niwl>Wd4CNH)JM5T`WmP-WfcJSh z{Ez`}dm*}-&Q$23|21{zVA&d55i5iC&8 zzyO)oTi}{huD`h>_jg$4gC1Sp|B`%c3>zh_GA$|u~VJyd zGBpvt_~kG?J(CQS_qHU#QgyQ2O*5r~@zQEvq*)GD3g1aZZ5|Ffy=>OtMC$k;pW3fX1b-@Wcm`iaY@(?=!_J!RR{dZ>K~_7P zzFVE5+`;muf*+yrupFs3EA7~v5qdVJgV@>;dV$KXmfpApBP+Vv#>Vzl@AcCD@4 z)Z@{Km9nKHb!I{NHugwAwV{Rdu(ABl)m(hFo$c+XJ`Q7;I$BS65zQvYmkk`PH@5IB z8{6Aoy(Nxh!250k{?`Hw3{dZi<4xg%w&3hdZS0Nd+O<0J!&}Xw_6M`5BaSS0qeL4U zbcNaxp6nf~H^%57Ond!yOkZNpTD+~Zh*b_c`jg$W6^6?N0cI-%5|@aXPskxde}-X) zpg}`Qq5ic8^Do){8}&Ju?`D&y>1hr5UbtVl#y+nZwX2^z9QRRgWGzBs#aTKHOp+aJ z(=`3|hI~gvHQxfG+BZhE!Nt0c`PR_nV*SZJA!V~>QLMwCSl+g5vzEfhEf$S+X|J`2 z6{|X(o$41N^rsqBU)DiuYo(utu_|88ave7L^$BVkMwIP*SG(FxEhbgnZc>$I zP?ZJ!S7E;f^o|(0S%Rj5A5JyEs+9huM1$22@|qTzB=s@OK@+;rK}Ay5q*^HJ0DLb@ zS^E@8Sre)$OU!lAV4iu0K~&@l|P)J}BAdzSr{UHLA_)@oXu0$eIBr%Eqt0ofBNi~s(u`?|Tll4~sbiY0Va1BoRvMxedb;Rbj;uZb_<{M-z^%zH@7 z_wwsy%`o|JHtvwN8KVzaaW^2JG1UQCkPqDoW`KAQl!AOH8+}*~Xb{L&6_p+a_qa0zH=i_PFW2&?~W&-7C1KYa=oj9tWVqDYOPk0;K>SUdoauY4Af} zwjiI47`X)V_v49?0WI&JA3gMg07_K*9OOI-u(|92~J%W1p zSQwiK>Y;^_dJM8NsfUb$mcjq?ktX%L%;q1{;HTUWcvd9!TqCF_9lvU09}U%;VqU*+p2xL-1?`2zqn4^XUiy`R zFY#e~vC0p__`=zmlN!V57+cU!%=TYc9>9wQU@1&5S&FxJ9NBJ_kz&7<4H^wUD*1l4 zr@uPOP4-$PzU*OR2B>q~d?#EBdfCY~P1lC{&_~v2c-h7Zu24H+`W{=5(sARBpq4D2oNx>Wq1e%k>u6n&J zN8rRT<^1489V!jrM3h7(RT={)c0}UDAv3Bj7AnnSN;j6Apn^zqiPqS|1yq1YgItj! z4PRh_1AF0JEghp$w(}D0Y8SDY+`!sz(crg-PhdkEe8`}NPD-2!4O1jEkR#F1Ko6PF zFu5i)Z~zKJnweM=8U#>;p@HrK*8-RhF=dh!a9hYE%cV@RR00FJQOYELVaY#hH#<$82{eNV zS_gQM%0%rAx1a+-3mh~gp^|`BBw&Hw3GILqK`CH?vZj;7N;T791^Dvd$y&h2C&_Uq z|B$G_C$VhMK)kN%@ip|339R_2)|kBx-@)`3R+aASltv-wM}h(csV5Q?$S6}D83rv1 z%Olr8tAso<%m4*&;Ma?^OdlEqkBa1k0?7%%FemgkIiauQgkJCz!3jMLPKf{2{QVBU znRpdTzD)H)|FUk-(pw;W8Yp~jf|3`~!yFxDu^ z;06n+w6jtWK-kf#+8~uXrH>i-;0)u#NvjlBP4$DY12+nM_{qeF!xA5;;}kwjE7sEE z$Tkxnz7FHV*CsxEZsNoLnE3Fii4UKe`0&AL`0&1o5ARBRST3ZGJJ_PVYTI@jO@wGu zQ}zI9T;fYNnDU0~Q4=fXCI!Fs0#;;y-lb>Rx89V;$b&!?acX^w6ewDxF!NufJ`hZd zrj+`^f=T_irFOxjT+L!V2YGZxikv-NM~UHku1qg+!Do2G*faD zNw3LG$Sb(1NO4PSqCP3Lki&wTzOxDu)c_~-q7YjuK*DOk8pZiKVd7;|TB%Qm`nQIB z1m^i>GAh?hMzyUSrD%E>rHo`$${Dp6BN?Tdl@nw#Dqbd|oKeaPF8_w*L6%85z>1;3 zKT-BH(K8yNh*VS!;ia>3r_f!Fcp(QOV2VS85->$RkASIeuFvF(&v!_c;^R%}V0(2O zlPnc*eiVUH#5*#Yr04`eQk#`c5~S$h>Oe0*io6DPKyMKQBtVM1%ElZ90foK{trFk_ zr2$eQxG%1u+$umS2=@g@L1}>0OHz2@Ae0y+B}ze3FF+YdQb0>lB=x)yUhem%)DJz zwHMYRyU^A(X^OOxvJ1@+IMvmMc1P@8{rfVSWk=FK7=d&h#Z?@+nJ(9Fm1^ zHwdb!&G1qqkA&$uR=iuCzLCP2~M0-$bneIogZZWsJi>e?#t z32kLnZGFSMZ${G-^cTdJ&I$;RC0b+U38B5*p{!>a*}fv>Iia|uTb`{+Mm++-r&J)L z%UXK>Q}&b^7F;eAjwI??7D#N!T`@nxu9%ZD?4p&DNUoJcl7AK=$uo&0EmDO+PoCN; z13=P&JZKWhQ?(Gu#+pRJvm}wYXtE>{%Gxi3v;k>j0*S{2k`_X@2`IBnAQ3xZU`aRy zJFqcDT=Sc10TQ(N-j3bo8l z=gVC(=ux>#hJpeWCF9I8cFBZwobRe}gnuh=WSGL5u2Kg9uuNN}#$g}1)Py`l0gtEy zWZkg1)1Cb}MQ;_A5;FCj-K$l#$GN10(5;eFAmjR+s{3o(7y}uFs#MTVPu~**45mD< z>X^J_Y=eQz8PBVk7(vRug?=mZu2Z}D_|oXS4=prM{PwFyRuIIT?)r$tQ| ziQWbSB2Hp>AB+@nUN%LXVD(0rY-i|1dv&~mNe?OIw3AX!tJ?VkrH1*#NdEAqX9N(b z)>Ww44tk03_dshDQ?!8fR)bubEoTpz0WD zXgMIR7+MaLhL-cPq2;iTyQwQ!;W({??dz@z%}WX>eT~r1R`gJ3V=0$xgnPU5)NaCY zKp+Y2$X6FCa3KT_c4tr3={}`)TxUdS_DoOMnF7*0>^B4o zOpl4^T81Hv78h%2apV`S`?HSulf#UC`K=F4|pm-xX#G*~6K(SE@ z6lDm7M9Q6cw)UQAS6 zOjKMsK-Rbqc-OT=YnfvKIW&6KP(~9dp1JGPS9nG$odCk|6}nw zOrvPi8+JXEqik^6E>M@9Wc_*g3-RCA<=?ZbFHS= zUm*_Hd9p$5e;VKU?0+~_g3!G+{%|U|q`~NzPg6Q4!`{RTW4NMCgOXs&2C={FbLw@Q z1_~V8RphVtw+%~5va zhlkYnd^kh@pEvry&l>wmSV#Y1K{~zvaM;&3){@|t*4Uk|4&x}=xVaJd7Rv?d^=wN? zaLRc&nDzJdI<#wFoH$nQS4-^Crw+@tzU<%$OYE$1E`}>+fR_!c|MAwMy-X}|9hFf0 z2-{&b`0w+u!q(CEGnoJ0a!d_5?svx?@Gm|43YUY>{im&PFvI7&bAs=jha=_c==^Cj zJhba|<6PRe&cm6Nb#xmnM|FD_H!T19hg&w`a?5!zT*qL;o33Rof8Ui8JaHc0bRFXj zfh=mg4S}FSag*Sm&cnftb@aT3n^ieQ6z}PdT_mW(GIYD;(d!uX z8eaao%Q)rQANxs_zt{5h{@72suES#-{5WO$)poJ0F{T