From 01bd5ba2b8db17a023966278f6023ad27afdffd5 Mon Sep 17 00:00:00 2001 From: Yvonne Chen Date: Tue, 26 Sep 2017 17:29:59 +0800 Subject: [PATCH] media_modules: add sec firmload for 4.9[3/3] PD# 150992 add sec firmload for 4.9 under optee Change-Id: Id1f5cbcfc293746869bea9542109a9ef7ed628e5 Signed-off-by: Yvonne Chen --- .../common/firmware/firmware_drv.c | 13 +++++-- .../frame_provider/decoder/avs/avs.c | 5 ++- .../frame_provider/decoder/h264/vh264.c | 6 ++-- .../frame_provider/decoder/h264/vh264_mvc.c | 3 +- .../decoder/h264_multi/vmh264.c | 8 ++--- .../frame_provider/decoder/h265/vh265.c | 11 ++++-- .../frame_provider/decoder/mjpeg/vmjpeg.c | 5 ++- .../frame_provider/decoder/mpeg12/vmpeg12.c | 4 ++- .../frame_provider/decoder/mpeg4/vmpeg4.c | 4 ++- .../frame_provider/decoder/real/vreal.c | 6 ++-- .../frame_provider/decoder/utils/amvdec.c | 27 +++++++++++++-- .../frame_provider/decoder/utils/vdec.c | 32 +----------------- .../frame_provider/decoder/utils/vdec.h | 1 - .../frame_provider/decoder/vc1/vvc1.c | 5 ++- .../frame_provider/decoder/vp9/vvp9.c | 5 +-- firmware/video/video_ucode.bin | Bin 424448 -> 424704 bytes 16 files changed, 80 insertions(+), 55 deletions(-) diff --git a/drivers/amlogic/media_modules/common/firmware/firmware_drv.c b/drivers/amlogic/media_modules/common/firmware/firmware_drv.c index 35dc29be6840..486c0aca055b 100644 --- a/drivers/amlogic/media_modules/common/firmware/firmware_drv.c +++ b/drivers/amlogic/media_modules/common/firmware/firmware_drv.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -67,7 +68,15 @@ int get_firmware_data(enum firmware_type_e type, char *buf) int data_len, ret = -1; struct firmware_mgr_s *mgr = g_mgr; struct firmware_info_s *info; - + if (tee_enabled()) { + pr_info ("tee load firmware type= %d\n",(u32)type); + ret = tee_load_video_fw((u32)type); + if (ret == 0) + ret = 1; + else + ret = -1; + return ret; + } if (list_empty(&mgr->head)) { pr_info("the info list is empty.\n"); return 0; @@ -143,7 +152,7 @@ static int request_firmware_from_sys(const char *file_name, goto release; } - memcpy(buf, (char *)firmware->data, firmware->size); + memcpy(buf, (char *)firmware->data+256, firmware->size-256); pr_info("load firmware size : %zd, Name : %s.\n", firmware->size, file_name); diff --git a/drivers/amlogic/media_modules/frame_provider/decoder/avs/avs.c b/drivers/amlogic/media_modules/frame_provider/decoder/avs/avs.c index da964cc68116..68bb5d8fb4be 100644 --- a/drivers/amlogic/media_modules/frame_provider/decoder/avs/avs.c +++ b/drivers/amlogic/media_modules/frame_provider/decoder/avs/avs.c @@ -1460,12 +1460,15 @@ static s32 vavs_init(void) size = get_firmware_data(VIDEO_DEC_AVS, buf); if (size < 0) { + amvdec_disable(); pr_err("get firmware fail."); vfree(buf); return -1; } - if (amvdec_loadmc_ex(VFORMAT_AVS, NULL, buf) < 0) { + if (size == 1) + pr_info ("tee load ok"); + else if (amvdec_loadmc_ex(VFORMAT_AVS, NULL, buf) < 0) { amvdec_disable(); vfree(buf); return -EBUSY; diff --git a/drivers/amlogic/media_modules/frame_provider/decoder/h264/vh264.c b/drivers/amlogic/media_modules/frame_provider/decoder/h264/vh264.c index ff31b464c49f..574bc0c67bb7 100644 --- a/drivers/amlogic/media_modules/frame_provider/decoder/h264/vh264.c +++ b/drivers/amlogic/media_modules/frame_provider/decoder/h264/vh264.c @@ -45,7 +45,7 @@ #include "../../../stream_input/parser/streambuf.h" #include #include - +#include #include #include "../utils/decoder_mmu_box.h" #include "../utils/decoder_bmmu_box.h" @@ -2348,7 +2348,7 @@ static void vh264_prot_init(void) WRITE_VREG(AV_SCRATCH_0, 0); WRITE_VREG(AV_SCRATCH_1, buf_offset); - if (!is_secload_get()) + if (!tee_enabled()) WRITE_VREG(AV_SCRATCH_G, mc_dma_handle); WRITE_VREG(AV_SCRATCH_7, 0); WRITE_VREG(AV_SCRATCH_8, 0); @@ -2565,7 +2565,7 @@ static s32 vh264_init(void) query_video_status(0, &trickmode_fffb); amvdec_enable(); - if (!firmwareloaded && is_secload_get()) { + if (!firmwareloaded && tee_enabled()) { if (tee_load_video_fw((u32)VIDEO_DEC_H264) != 0) { amvdec_disable(); return -1; diff --git a/drivers/amlogic/media_modules/frame_provider/decoder/h264/vh264_mvc.c b/drivers/amlogic/media_modules/frame_provider/decoder/h264/vh264_mvc.c index 9d2b85773a50..30fbad8ef3df 100644 --- a/drivers/amlogic/media_modules/frame_provider/decoder/h264/vh264_mvc.c +++ b/drivers/amlogic/media_modules/frame_provider/decoder/h264/vh264_mvc.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -1404,7 +1405,7 @@ static s32 vh264mvc_init(void) amvdec_enable(); - if (is_secload_get()) { + if (tee_enabled()) { if (tee_load_video_fw((u32)VIDEO_DEC_H264_MVC) != 0) { amvdec_disable(); return -1; diff --git a/drivers/amlogic/media_modules/frame_provider/decoder/h264_multi/vmh264.c b/drivers/amlogic/media_modules/frame_provider/decoder/h264_multi/vmh264.c index 3b7676e301ab..9a32496ba8f6 100644 --- a/drivers/amlogic/media_modules/frame_provider/decoder/h264_multi/vmh264.c +++ b/drivers/amlogic/media_modules/frame_provider/decoder/h264_multi/vmh264.c @@ -42,6 +42,7 @@ #include #include "../utils/vdec_input.h" +#include #include #include "../utils/vdec.h" @@ -4342,7 +4343,7 @@ static int vh264_hw_ctx_restore(struct vdec_h264_hw_s *hw) WRITE_VREG(FRAME_COUNTER_REG, hw->decode_pic_count); WRITE_VREG(AV_SCRATCH_8, hw->buf_offset); - if (!is_secload_get()) + if (!tee_enabled()) WRITE_VREG(AV_SCRATCH_G, hw->mc_dma_handle); /* hw->error_recovery_mode = (error_recovery_mode != 0) ? @@ -4495,7 +4496,7 @@ static s32 vh264_init(struct vdec_h264_hw_s *hw) return -ENOMEM; } } - if (is_secload_get() && !firmwareloaded) { + if (tee_enabled() && !firmwareloaded) { pr_info("VMH264 start load sec firmware ...\n"); if (tee_load_video_fw((u32)VIDEO_DEC_H264_MULTI) != 0) { @@ -5094,8 +5095,7 @@ static void run(struct vdec_s *vdec, size); start_process_time(hw); - - if (is_secload_get()) { + if (tee_enabled()) { if (tee_load_video_fw((u32)VIDEO_DEC_H264_MULTI) != 0) { amvdec_enable_flag = false; diff --git a/drivers/amlogic/media_modules/frame_provider/decoder/h265/vh265.c b/drivers/amlogic/media_modules/frame_provider/decoder/h265/vh265.c index 39cbd5de788e..35519e2c50d6 100644 --- a/drivers/amlogic/media_modules/frame_provider/decoder/h265/vh265.c +++ b/drivers/amlogic/media_modules/frame_provider/decoder/h265/vh265.c @@ -8613,7 +8613,9 @@ static s32 vh265_init(struct hevc_state_s *hevc) #endif amhevc_enable(); - if (amhevc_loadmc_ex(VFORMAT_HEVC, NULL, fw->data) < 0) { + if (size == 1) + pr_info ("tee load ok"); + else if (amhevc_loadmc_ex(VFORMAT_HEVC, NULL, fw->data) < 0) { amhevc_disable(); vfree(fw); return -EBUSY; @@ -9423,7 +9425,12 @@ static void run(struct vdec_s *vdec, } } - if (amhevc_vdec_loadmc_ex(vdec, NULL, hevc->fw->data) < 0) { + if (hevc->mmu_enable &&(get_cpu_type() >= MESON_CPU_MAJOR_ID_GXL)) + r = amhevc_vdec_loadmc_ex(vdec, "vh265_mc_mmu", hevc->fw->data); + else + r = amhevc_vdec_loadmc_ex(vdec, "vh265_mc", hevc->fw->data); + + if (r < 0) { amhevc_disable(); hevc_print(hevc, 0, "%s: Error amvdec_loadmc fail\n", diff --git a/drivers/amlogic/media_modules/frame_provider/decoder/mjpeg/vmjpeg.c b/drivers/amlogic/media_modules/frame_provider/decoder/mjpeg/vmjpeg.c index d8e28aa98f6d..1e129369fde2 100644 --- a/drivers/amlogic/media_modules/frame_provider/decoder/mjpeg/vmjpeg.c +++ b/drivers/amlogic/media_modules/frame_provider/decoder/mjpeg/vmjpeg.c @@ -727,12 +727,15 @@ static s32 vmjpeg_init(void) size = get_firmware_data(VIDEO_DEC_MJPEG, buf); if (size < 0) { + amvdec_disable(); pr_err("get firmware fail."); vfree(buf); return -1; } - if (amvdec_loadmc_ex(VFORMAT_MJPEG, NULL, buf) < 0) { + if (size == 1) + pr_info ("tee load ok"); + else if (amvdec_loadmc_ex(VFORMAT_MJPEG, NULL, buf) < 0) { amvdec_disable(); vfree(buf); return -EBUSY; diff --git a/drivers/amlogic/media_modules/frame_provider/decoder/mpeg12/vmpeg12.c b/drivers/amlogic/media_modules/frame_provider/decoder/mpeg12/vmpeg12.c index 41c37be0f92a..1546940ffbba 100644 --- a/drivers/amlogic/media_modules/frame_provider/decoder/mpeg12/vmpeg12.c +++ b/drivers/amlogic/media_modules/frame_provider/decoder/mpeg12/vmpeg12.c @@ -1082,7 +1082,9 @@ static s32 vmpeg12_init(void) return -1; } - if (amvdec_loadmc_ex(VFORMAT_MPEG12, NULL, buf) < 0) { + if (size == 1) + pr_info ("tee load ok"); + else if (amvdec_loadmc_ex(VFORMAT_MPEG12, NULL, buf) < 0) { amvdec_disable(); vfree(buf); return -EBUSY; diff --git a/drivers/amlogic/media_modules/frame_provider/decoder/mpeg4/vmpeg4.c b/drivers/amlogic/media_modules/frame_provider/decoder/mpeg4/vmpeg4.c index 094fae3ebcc9..6cdbf7f3c87f 100644 --- a/drivers/amlogic/media_modules/frame_provider/decoder/mpeg4/vmpeg4.c +++ b/drivers/amlogic/media_modules/frame_provider/decoder/mpeg4/vmpeg4.c @@ -1040,7 +1040,9 @@ static s32 vmpeg4_init(void) return -1; } - if (amvdec_loadmc_ex(VFORMAT_MPEG4, NULL, buf) < 0) { + if (size == 1) + pr_info ("tee load ok"); + else if (amvdec_loadmc_ex(VFORMAT_MPEG4, NULL, buf) < 0) { amvdec_disable(); vfree(buf); return -EBUSY; diff --git a/drivers/amlogic/media_modules/frame_provider/decoder/real/vreal.c b/drivers/amlogic/media_modules/frame_provider/decoder/real/vreal.c index 7af39aca0a6e..7d408eec7b26 100644 --- a/drivers/amlogic/media_modules/frame_provider/decoder/real/vreal.c +++ b/drivers/amlogic/media_modules/frame_provider/decoder/real/vreal.c @@ -822,12 +822,14 @@ s32 vreal_init(struct vdec_s *vdec) pr_info("unsurpported real format\n"); if (size < 0) { + amvdec_disable(); pr_err("get firmware fail."); vfree(buf); return -1; } - - if (amvdec_loadmc_ex(VFORMAT_REAL, NULL, buf) < 0) { + if (size == 1) + pr_info ("tee load ok"); + else if (amvdec_loadmc_ex(VFORMAT_REAL, NULL, buf) < 0) { amvdec_disable(); vfree(buf); return -EBUSY; diff --git a/drivers/amlogic/media_modules/frame_provider/decoder/utils/amvdec.c b/drivers/amlogic/media_modules/frame_provider/decoder/utils/amvdec.c index 52e81ad2fc44..e8fbee65b1c4 100644 --- a/drivers/amlogic/media_modules/frame_provider/decoder/utils/amvdec.c +++ b/drivers/amlogic/media_modules/frame_provider/decoder/utils/amvdec.c @@ -421,6 +421,26 @@ s32 optee_load_fw(enum vformat_e type, const char *name) else if (!strcmp(name, "h263_mc")) ret = tee_load_video_fw((u32)VIDEO_DEC_FORMAT_H263); break; + default: + if (!strcmp(name, "vh265_mc")) + ret = tee_load_video_fw((u32)VIDEO_DEC_HEVC); + else if (!strcmp(name, "vh265_mc_mmu")) + ret = tee_load_video_fw((u32)VIDEO_DEC_HEVC_MMU); + else if (!strcmp(name, "vmpeg4_mc_311")) + ret = tee_load_video_fw((u32)VIDEO_DEC_MPEG4_3); + else if (!strcmp(name, "vmpeg4_mc_4")) + ret = tee_load_video_fw((u32)VIDEO_DEC_MPEG4_4); + else if (!strcmp(name, "vmpeg4_mc_5")) + ret = tee_load_video_fw((u32)VIDEO_DEC_MPEG4_5); + else if (!strcmp(name, "h263_mc")) + ret = tee_load_video_fw((u32)VIDEO_DEC_FORMAT_H263); + else if (!strcmp(name, "vreal_mc_8")) + ret = tee_load_video_fw((u32)VIDEO_DEC_REAL_V8); + else if (!strcmp(name, "vreal_mc_9")) + ret = tee_load_video_fw((u32)VIDEO_DEC_REAL_V9); + else + pr_info("unknow dec format\n"); + break; } return ret; } @@ -428,7 +448,7 @@ EXPORT_SYMBOL(optee_load_fw); s32 amvdec_loadmc_ex(enum vformat_e type, const char *name, char *def) { - if (is_secload_get()) + if (tee_enabled()) return optee_load_fw(type, name); else return am_loadmc_ex(type, name, def, &amvdec_loadmc); @@ -617,7 +637,7 @@ static s32 amhevc_loadmc(const u32 *p) s32 amhevc_loadmc_ex(enum vformat_e type, const char *name, char *def) { if (has_hevc_vdec()) - if (is_secload_get()) + if (tee_enabled()) return optee_load_fw(type, name); else return am_loadmc_ex(type, name, def, &amhevc_loadmc); @@ -629,6 +649,9 @@ EXPORT_SYMBOL(amhevc_loadmc_ex); s32 amhevc_vdec_loadmc_ex(struct vdec_s *vdec, const char *name, char *def) { if (has_hevc_vdec()) + if (tee_enabled()) + return optee_load_fw(FIRMWARE_MAX, name); + else return am_vdec_loadmc_ex(vdec, name, def, &amhevc_loadmc); else return 0; diff --git a/drivers/amlogic/media_modules/frame_provider/decoder/utils/vdec.c b/drivers/amlogic/media_modules/frame_provider/decoder/utils/vdec.c index 47fe09e99082..a58f2ceea573 100644 --- a/drivers/amlogic/media_modules/frame_provider/decoder/utils/vdec.c +++ b/drivers/amlogic/media_modules/frame_provider/decoder/utils/vdec.c @@ -65,7 +65,6 @@ #include #include #include "secprot.h" -#include static DEFINE_MUTEX(vdec_mutex); @@ -78,7 +77,7 @@ static int keep_vdec_mem; static unsigned int debug_trace_num = 16 * 20; static int step_mode; static unsigned int clk_config; -static int is_secload; + static int hevc_max_reset_count; #define MAX_INSTANCE_MUN 9 @@ -3062,34 +3061,7 @@ static ssize_t dump_decoder_state_show(struct class *class, return pbuf - buf; } -int is_secload_get(void) -{ - return is_secload; -} -EXPORT_SYMBOL(is_secload_get); -static ssize_t is_secload_show(struct class *cla, - struct class_attribute *attr, - char *buf) -{ - return sprintf(buf, "%d\n", is_secload ? 1 : 0); -} - -static ssize_t is_secload_store(struct class *cla, - struct class_attribute *attr, - const char *buf, size_t count) -{ - size_t r; - int value; - - r = sscanf(buf, "%d", &value); - - if (r != 1) - return -EINVAL; - - is_secload = value & tee_enabled(); - return count; -} static struct class_attribute vdec_class_attrs[] = { __ATTR_RO(amrisc_regs), @@ -3106,8 +3078,6 @@ static struct class_attribute vdec_class_attrs[] = { __ATTR_RO(dump_vdec_blocks), __ATTR_RO(dump_vdec_chunks), __ATTR_RO(dump_decoder_state), - __ATTR(is_secload, S_IRUGO | S_IWUSR | S_IWGRP, is_secload_show, - is_secload_store), __ATTR_NULL }; diff --git a/drivers/amlogic/media_modules/frame_provider/decoder/utils/vdec.h b/drivers/amlogic/media_modules/frame_provider/decoder/utils/vdec.h index 7c86d0e0ae54..98c5f43aa2c2 100644 --- a/drivers/amlogic/media_modules/frame_provider/decoder/utils/vdec.h +++ b/drivers/amlogic/media_modules/frame_provider/decoder/utils/vdec.h @@ -351,5 +351,4 @@ int vdec_get_debug_flags(void); unsigned char is_mult_inc(unsigned int); -int is_secload_get(void); #endif /* VDEC_H */ diff --git a/drivers/amlogic/media_modules/frame_provider/decoder/vc1/vvc1.c b/drivers/amlogic/media_modules/frame_provider/decoder/vc1/vvc1.c index 8efcf771fb62..6828cc576a07 100644 --- a/drivers/amlogic/media_modules/frame_provider/decoder/vc1/vvc1.c +++ b/drivers/amlogic/media_modules/frame_provider/decoder/vc1/vvc1.c @@ -1038,12 +1038,15 @@ static s32 vvc1_init(void) size = get_firmware_data(VIDEO_DEC_VC1, buf); if (size < 0) { + amvdec_disable(); pr_err("get firmware fail."); vfree(buf); return -1; } - if (amvdec_loadmc_ex(VFORMAT_VC1, NULL, buf) < 0) { + if (size == 1) + pr_info ("tee load ok"); + else if (amvdec_loadmc_ex(VFORMAT_VC1, NULL, buf) < 0) { amvdec_disable(); vfree(buf); return -EBUSY; diff --git a/drivers/amlogic/media_modules/frame_provider/decoder/vp9/vvp9.c b/drivers/amlogic/media_modules/frame_provider/decoder/vp9/vvp9.c index 53634654433a..ae07e1fc7316 100644 --- a/drivers/amlogic/media_modules/frame_provider/decoder/vp9/vvp9.c +++ b/drivers/amlogic/media_modules/frame_provider/decoder/vp9/vvp9.c @@ -6649,8 +6649,9 @@ static s32 vvp9_init(struct VP9Decoder_s *pbi) #endif amhevc_enable(); - - if (amhevc_loadmc_ex(VFORMAT_VP9, NULL, fw->data) < 0) { + if (size == 1) + pr_info ("tee load ok\n"); + else if (amhevc_loadmc_ex(VFORMAT_VP9, NULL, fw->data) < 0) { amhevc_disable(); vfree(fw); return -EBUSY; diff --git a/firmware/video/video_ucode.bin b/firmware/video/video_ucode.bin index 276f0ade7d3f0ab19d7ec67d47037c9581426c18..08a3f302b4cb573c1a6bf1eb4250d926ef0ef7ca 100644 GIT binary patch delta 3454 zcmb_feNa?Y6uN>Up~dB(F@! z{AT`vzvu7io^U8T)lu@dXKM83`Xi^_$j!dZ7TW#N#xD1@Q||qna)+kQQpv4LzdJH3 zZ}#XVm#=m%{Ijv^%BL5tnRizOL-AiYW@I)O4K2*MI@L8OJ(TrC^ud;_(jx;W9`3kz zhVW|4wrk3_fi1Cr-5FOY=l*u~=-A2r%_-@-2IYy~hT`!bBt-46 zys$29v?=I|S|0UK`)Bd;$>viF97O|8Upv+H$HH5d>?D>e`(AtN&1FA~I*u=H-jwpx zknxhI_`bnE*Ji~0l{~Y1u`Mh1=$T_x1BQ;gKi!)PiX~8+SKnQEOuX1EapPOdgd?F)Z>yU%Z{Q$|k z!M|$H>{C1FrG9Qe?C1}~8?^Dje$*yh<8z?dYu&5YN5;w4!30@xjhs!Ml<|aOrJP%4FIG?} zPG+S=VN6SBwq#*jWTD+^0ia01V?+hWiiM2lmJjUJEo;%aQRgqVP&z>tTq`3nRz_gG zM50VeKw$$Vl#wI(3W*hEC=%OAmu`h=B59zlTVb`#w#g`iAcW`B2OD7QWN=#6@B;#o z0+|fqvpNs@GFw7yF~_Zth&7BWfds{(<tGyw_!S!%OsneP zXrY$2)xk-^33{mxrWSBQpNXK*?VR)_uMMP$N|uSCEDmDf*3RY{4$YO@c|eHOaMBzJ zrTu8r9P>pS>nv4t$7|#=zE2C7eJyGMOSpxutA~yl{FQ!>I5x^)i1=w+J#00xcS`Br ztuUT$+zzh_fWEZ@K4ZrnrHYR);shvU=RZ&*m-CIRjyf9P5D~velN;bP5$~sK8lc01 zx0EV}>8y+D16lMF1}nE!lFB5(vjkBog=UHQuB1v3PpD z5teuzdTrR*Jf1=h&0*Vz7^$ztw!j9WQ!+lUrJC2Img06!p=l3FXj2oMEs`Tt4#I;D zzyw8z<6&^CtwZSyu{M1U@1^I1(2>T*6)ASU|Nn9ZBAjz*+D?tLS>3b~ilPH=&-I4U9edst+eR_ z=#L?{>3i95!`?|qaUZ9T8nL)ns*mxbmm=~CCU!Uu(sq*m^T!O#)|%(8`` zvgX&rbt)XNTBd624$<=}yidWGd0kX65%78So)6&&A(<`GVeR~!FB(ClMGJ_;C+XP!#=T!%w;PIr$i}N1K7tOD2PYUP#84UNDkJXLe<|!UvQ1v0-5*1bK6{le@51J46QGV*RPBL8xA1v^=kzn2haGpM=JqI(5>mH2;eZu!zcn7Ih zn;0A=ie#92Vjp~578fm0lRt$kET}A#7vqb$YVbIGKzP)3AX{>gr(~BmM;eo!Bkef+ zwAFtO%YGS{UA`P?EGCj`2eFN*CN@9cx!n%TeqN@ogZgPP8Ld)t+{FXbo*AvU#e4Dr qrS&xI%g1{!FBPZpx~^H3BB++1;PgIxrzG|I30W5TKd?=f3jYBngmn4< delta 3069 zcmb_eZEO@p7=CB=W@m426QRM<9=JJ=ND;-f2b9_G-xDfDwJTg5WYfbjJ8F} z#83Qob>Dh;8*b=pd?D zmJHjG78&05v+%Lv)8DJT2QC!^Th^x%2OirzKLMq6b(oX!-=0lRqX)}ryBVFK-v>Z^z z#Mo(MK*EK=&>+&RGQxsj8mhQ5po;N=LO@XgEU>=gbN7(h`2a%hlW=~tNR2_ERE6uc z9^NfK{^L1zlONqfrfwPfc0djKn8j?G9(17x}jN*%jjIsc#-vb-1Pj7_LBR*f#mBlNh^* zoy1h=;~ibZOoI#FJ(YO0P*AawU+N-pZ0)h%?Iux#1n>KZti^DSn>{2w%sRIiLt#M| zW-uC(2|9ji6J+7{@kKpk5r$LzgC1gHXyYe(NKqDh-+P{(zZPP;S0J`eHj^xf==PdQ z96@{oQZjjAFL^S?dc0MdA+xBK&Sw}h3OBkL%52=M#0ov^w82i^+e;Qqwf=Nki>a1m zX>_w?s)*kE4M#n85#`bSWYf$EUiHK9sx(X*XGsIoeWRN*}@4 z6iq(St^}f;K2eiP#4`?&b*A->w^%I$TYn2=e4&I1f z_M&h)MP62`f4|zkbd+E@HaYf{Pl&0+Sk?%NoCBwfPPt?msgUCSqlB=7=MIqBCe$H! z4ie}443hg~M_G65_XbE5FJeXYE`9b_a+>Avz!Gm0EBD=%(=8VJK+bTz^lwo5sobl{ zDsNkK;E;Qs2&_oZ*qXZ}L23 TYd?}DDfl`_eCu|E)T+M#sHfj~