From 06926c3c30da8d332819369db91d892c60468ca7 Mon Sep 17 00:00:00 2001 From: GuEe-GUI <2991707448@qq.com> Date: Mon, 24 Aug 2026 09:56:55 +0800 Subject: [PATCH] [bsp][spacemit/k1] first version Signed-off-by: GuEe-GUI <2991707448@qq.com> --- bsp/spacemit/dm/Kconfig | 31 + bsp/spacemit/dm/SConscript | 13 + bsp/spacemit/dm/adc/Kconfig | 6 + bsp/spacemit/dm/adc/SConscript | 14 + bsp/spacemit/dm/adc/adc-spacemit-pmic.c | 308 + bsp/spacemit/dm/audio/Kconfig | 29 + bsp/spacemit/dm/audio/SConscript | 15 + bsp/spacemit/dm/audio/codec/es8326.c | 528 + bsp/spacemit/dm/audio/codec/es8326.h | 95 + bsp/spacemit/dm/audio/spacemit-audio.h | 68 + bsp/spacemit/dm/audio/spacemit-snd-card.c | 1087 ++ bsp/spacemit/dm/audio/spacemit-snd-i2s.c | 376 + bsp/spacemit/dm/audio/spacemit-snd-i2s.h | 40 + bsp/spacemit/dm/audio/spacemit-snd-pcm-dma.c | 168 + bsp/spacemit/dm/audio/spacemit-snd-sspa.c | 969 ++ bsp/spacemit/dm/audio/spacemit-snd-sspa.h | 55 + bsp/spacemit/dm/clk/Kconfig | 9 + bsp/spacemit/dm/clk/SConscript | 15 + bsp/spacemit/dm/clk/ccu-spacemit-k1x.c | 1244 +++ bsp/spacemit/dm/clk/ccu.h | 52 + bsp/spacemit/dm/clk/ccu_ddn.c | 198 + bsp/spacemit/dm/clk/ccu_ddn.h | 103 + bsp/spacemit/dm/clk/ccu_ddr.c | 298 + bsp/spacemit/dm/clk/ccu_ddr.h | 52 + bsp/spacemit/dm/clk/ccu_dpll.c | 144 + bsp/spacemit/dm/clk/ccu_dpll.h | 86 + bsp/spacemit/dm/clk/ccu_mix.c | 712 ++ bsp/spacemit/dm/clk/ccu_mix.h | 422 + bsp/spacemit/dm/clk/ccu_pll.c | 321 + bsp/spacemit/dm/clk/ccu_pll.h | 90 + bsp/spacemit/dm/clock_time/Kconfig | 3 + bsp/spacemit/dm/clock_time/SConscript | 12 + bsp/spacemit/dm/clock_time/clock_time-k1x.c | 667 ++ bsp/spacemit/dm/dma/Kconfig | 8 + bsp/spacemit/dm/dma/SConscript | 13 + bsp/spacemit/dm/dma/dma-mmp-pdma.c | 994 ++ bsp/spacemit/dm/dvfs/SConscript | 16 + bsp/spacemit/dm/dvfs/cpufreq/Kconfig | 11 + bsp/spacemit/dm/dvfs/cpufreq/SConscript | 11 + .../dm/dvfs/cpufreq/dvfs-spacemit-cpufreq.c | 864 ++ bsp/spacemit/dm/ethernet/Kconfig | 14 + bsp/spacemit/dm/ethernet/SConscript | 13 + bsp/spacemit/dm/ethernet/eth-k1x-emac.c | 1928 ++++ bsp/spacemit/dm/firmware/SConscript | 12 + bsp/spacemit/dm/firmware/firmware-spacemit.c | 133 + bsp/spacemit/dm/graphic/SConscript | 13 + bsp/spacemit/dm/graphic/framebuffer/Kconfig | 14 + .../dm/graphic/framebuffer/SConscript | 11 + .../dm/graphic/framebuffer/display-spacemit.c | 93 + .../dm/graphic/framebuffer/display-spacemit.h | 69 + .../dm/graphic/framebuffer/fb-spacemit.c | 1135 ++ .../dm/graphic/framebuffer/hdmi-spacemit.c | 482 + bsp/spacemit/dm/graphic/logo/Kconfig | 5 + bsp/spacemit/dm/graphic/logo/Kconfig.path | 10 + .../dm/graphic/logo/logo-bianbu-clut224.ppm | 9333 +++++++++++++++++ .../dm/graphic/logo/logo-spacemit-clut224.ppm | 1227 +++ bsp/spacemit/dm/hwcrypto/Kconfig | 17 + bsp/spacemit/dm/hwcrypto/SConscript | 15 + bsp/spacemit/dm/hwcrypto/hw-crypto-spacemit.c | 1189 +++ bsp/spacemit/dm/hwcrypto/hw-rng-spacemit.c | 353 + bsp/spacemit/dm/i2c/Kconfig | 3 + bsp/spacemit/dm/i2c/SConscript | 13 + bsp/spacemit/dm/i2c/i2c-k1x.c | 1411 +++ .../dm/include/dt-bindings/clock/k1x.h | 242 + .../dm/include/dt-bindings/pinctrl/k1x.h | 211 + .../dm/include/dt-bindings/power/k1x_pmu.h | 20 + .../dm/include/dt-bindings/reset/k1x.h | 142 + bsp/spacemit/dm/include/firmware-spacemit.h | 50 + bsp/spacemit/dm/include/jpu.h | 101 + bsp/spacemit/dm/include/k1-cru.h | 232 + bsp/spacemit/dm/include/k1-tcm.h | 30 + bsp/spacemit/dm/include/k1x-rproc.h | 19 + bsp/spacemit/dm/include/mfd/pm853.h | 336 + bsp/spacemit/dm/include/mfd/spacemit-pmic.h | 483 + bsp/spacemit/dm/include/mfd/spm8821.h | 885 ++ bsp/spacemit/dm/include/mfd/sy8810l.h | 73 + bsp/spacemit/dm/include/spacemit.h | 124 + bsp/spacemit/dm/include/v2d.h | 358 + bsp/spacemit/dm/input/SConscript | 13 + bsp/spacemit/dm/input/misc/Kconfig | 5 + bsp/spacemit/dm/input/misc/SConscript | 13 + .../dm/input/misc/pwrkey-spacemit-pmic.c | 157 + bsp/spacemit/dm/mailbox/Kconfig | 3 + bsp/spacemit/dm/mailbox/SConscript | 12 + bsp/spacemit/dm/mailbox/mailbox-k1x.c | 270 + bsp/spacemit/dm/mfd/Kconfig | 7 + bsp/spacemit/dm/mfd/SConscript | 12 + bsp/spacemit/dm/mfd/spacemit-pmic.c | 763 ++ bsp/spacemit/dm/nvmem/Kconfig | 6 + bsp/spacemit/dm/nvmem/SConscript | 13 + bsp/spacemit/dm/nvmem/spacemit-efuse.c | 187 + bsp/spacemit/dm/pci/Kconfig | 10 + bsp/spacemit/dm/pci/SConscript | 15 + bsp/spacemit/dm/pci/pcie-k1x.c | 1366 +++ bsp/spacemit/dm/pin/Kconfig | 5 + bsp/spacemit/dm/pin/SConscript | 13 + bsp/spacemit/dm/pin/pin-k1x.c | 421 + bsp/spacemit/dm/pinctrl/Kconfig | 5 + bsp/spacemit/dm/pinctrl/SConscript | 13 + .../dm/pinctrl/spacemit-pmic-pinctrl.c | 364 + bsp/spacemit/dm/pmdomain/Kconfig | 6 + bsp/spacemit/dm/pmdomain/SConscript | 12 + bsp/spacemit/dm/pmdomain/pm-domain-k1x.c | 582 + bsp/spacemit/dm/power/SConscript | 11 + bsp/spacemit/dm/power/reset/Kconfig | 2 + bsp/spacemit/dm/power/reset/SConscript | 12 + bsp/spacemit/dm/power/reset/reboot-spacemit.c | 113 + bsp/spacemit/dm/pwm/Kconfig | 4 + bsp/spacemit/dm/pwm/SConscript | 14 + bsp/spacemit/dm/pwm/pwm-pxa.c | 331 + bsp/spacemit/dm/regulator/Kconfig | 5 + bsp/spacemit/dm/regulator/SConscript | 12 + .../dm/regulator/regulator-spacemit-pmic.c | 413 + bsp/spacemit/dm/reset/Kconfig | 4 + bsp/spacemit/dm/reset/SConscript | 13 + bsp/spacemit/dm/reset/reset-spacemit-k1x.c | 332 + bsp/spacemit/dm/rtc/Kconfig | 4 + bsp/spacemit/dm/rtc/SConscript | 13 + bsp/spacemit/dm/rtc/rtc-spacemit-pmic.c | 592 ++ bsp/spacemit/dm/sdio/Kconfig | 5 + bsp/spacemit/dm/sdio/SConscript | 12 + bsp/spacemit/dm/sdio/sdhci-k1x.c | 1577 +++ bsp/spacemit/dm/serial/8250-pxa_k1x.c | 362 + bsp/spacemit/dm/serial/Kconfig | 7 + bsp/spacemit/dm/serial/SConscript | 13 + bsp/spacemit/dm/soc/Kconfig | 33 + bsp/spacemit/dm/soc/SConscript | 33 + bsp/spacemit/dm/soc/jpu.c | 1760 ++++ bsp/spacemit/dm/soc/k1x-rproc.c | 1557 +++ bsp/spacemit/dm/soc/k1x-tcm.c | 122 + bsp/spacemit/dm/soc/sbi-ipi.c | 27 + bsp/spacemit/dm/soc/spacemit-socinfo.c | 148 + bsp/spacemit/dm/soc/v2d/SConscript | 9 + bsp/spacemit/dm/soc/v2d/v2d_drv.c | 740 ++ bsp/spacemit/dm/soc/v2d/v2d_hw.c | 1092 ++ bsp/spacemit/dm/soc/v2d/v2d_internal.h | 35 + bsp/spacemit/dm/soc/v2d/v2d_reg.h | 922 ++ bsp/spacemit/dm/spi/Kconfig | 18 + bsp/spacemit/dm/spi/SConscript | 16 + bsp/spacemit/dm/spi/spi-k1x-qspi.c | 1384 +++ bsp/spacemit/dm/spi/spi-k1x.c | 1142 ++ bsp/spacemit/dm/thermal/Kconfig | 3 + bsp/spacemit/dm/thermal/SConscript | 13 + bsp/spacemit/dm/thermal/thermal-k1x.c | 484 + bsp/spacemit/dm/watchdog/Kconfig | 3 + bsp/spacemit/dm/watchdog/SConscript | 13 + bsp/spacemit/dm/watchdog/watchdog-k1x.c | 470 + bsp/spacemit/k1/.config | 1927 ++++ bsp/spacemit/k1/.gitignore | 8 + bsp/spacemit/k1/Kconfig | 27 + bsp/spacemit/k1/README.md | 185 + bsp/spacemit/k1/README_en.md | 193 + bsp/spacemit/k1/SConscript | 16 + bsp/spacemit/k1/SConstruct | 29 + bsp/spacemit/k1/applications/SConscript | 9 + bsp/spacemit/k1/applications/audio.c | 133 + bsp/spacemit/k1/applications/jpu.c | 776 ++ bsp/spacemit/k1/applications/main.c | 18 + bsp/spacemit/k1/applications/v2d.c | 468 + bsp/spacemit/k1/coremark/LICENSE.md | 100 + bsp/spacemit/k1/coremark/README.md | 533 + bsp/spacemit/k1/coremark/SConscript | 15 + bsp/spacemit/k1/coremark/core_list_join.c | 495 + bsp/spacemit/k1/coremark/core_main.c | 369 + bsp/spacemit/k1/coremark/core_matrix.c | 308 + bsp/spacemit/k1/coremark/core_portme.c | 89 + bsp/spacemit/k1/coremark/core_portme.h | 207 + bsp/spacemit/k1/coremark/core_state.c | 277 + bsp/spacemit/k1/coremark/core_util.c | 210 + bsp/spacemit/k1/coremark/coremark.h | 179 + bsp/spacemit/k1/coremark/iteration.png | Bin 0 -> 53691 bytes bsp/spacemit/k1/drivers/README.md | 13 + bsp/spacemit/k1/drivers/SConscript | 11 + bsp/spacemit/k1/drivers/board.c | 30 + bsp/spacemit/k1/drivers/board.h | 16 + bsp/spacemit/k1/drivers/esos.elf | Bin 0 -> 1394124 bytes bsp/spacemit/k1/drivers/firmware.S | 18 + bsp/spacemit/k1/rtconfig.h | 752 ++ bsp/spacemit/k1/rtconfig.py | 57 + 179 files changed, 56562 insertions(+) create mode 100644 bsp/spacemit/dm/Kconfig create mode 100644 bsp/spacemit/dm/SConscript create mode 100644 bsp/spacemit/dm/adc/Kconfig create mode 100644 bsp/spacemit/dm/adc/SConscript create mode 100644 bsp/spacemit/dm/adc/adc-spacemit-pmic.c create mode 100644 bsp/spacemit/dm/audio/Kconfig create mode 100644 bsp/spacemit/dm/audio/SConscript create mode 100644 bsp/spacemit/dm/audio/codec/es8326.c create mode 100644 bsp/spacemit/dm/audio/codec/es8326.h create mode 100644 bsp/spacemit/dm/audio/spacemit-audio.h create mode 100644 bsp/spacemit/dm/audio/spacemit-snd-card.c create mode 100644 bsp/spacemit/dm/audio/spacemit-snd-i2s.c create mode 100644 bsp/spacemit/dm/audio/spacemit-snd-i2s.h create mode 100644 bsp/spacemit/dm/audio/spacemit-snd-pcm-dma.c create mode 100644 bsp/spacemit/dm/audio/spacemit-snd-sspa.c create mode 100644 bsp/spacemit/dm/audio/spacemit-snd-sspa.h create mode 100644 bsp/spacemit/dm/clk/Kconfig create mode 100644 bsp/spacemit/dm/clk/SConscript create mode 100644 bsp/spacemit/dm/clk/ccu-spacemit-k1x.c create mode 100644 bsp/spacemit/dm/clk/ccu.h create mode 100644 bsp/spacemit/dm/clk/ccu_ddn.c create mode 100644 bsp/spacemit/dm/clk/ccu_ddn.h create mode 100644 bsp/spacemit/dm/clk/ccu_ddr.c create mode 100644 bsp/spacemit/dm/clk/ccu_ddr.h create mode 100644 bsp/spacemit/dm/clk/ccu_dpll.c create mode 100644 bsp/spacemit/dm/clk/ccu_dpll.h create mode 100644 bsp/spacemit/dm/clk/ccu_mix.c create mode 100644 bsp/spacemit/dm/clk/ccu_mix.h create mode 100644 bsp/spacemit/dm/clk/ccu_pll.c create mode 100644 bsp/spacemit/dm/clk/ccu_pll.h create mode 100644 bsp/spacemit/dm/clock_time/Kconfig create mode 100644 bsp/spacemit/dm/clock_time/SConscript create mode 100644 bsp/spacemit/dm/clock_time/clock_time-k1x.c create mode 100644 bsp/spacemit/dm/dma/Kconfig create mode 100644 bsp/spacemit/dm/dma/SConscript create mode 100644 bsp/spacemit/dm/dma/dma-mmp-pdma.c create mode 100644 bsp/spacemit/dm/dvfs/SConscript create mode 100644 bsp/spacemit/dm/dvfs/cpufreq/Kconfig create mode 100644 bsp/spacemit/dm/dvfs/cpufreq/SConscript create mode 100644 bsp/spacemit/dm/dvfs/cpufreq/dvfs-spacemit-cpufreq.c create mode 100644 bsp/spacemit/dm/ethernet/Kconfig create mode 100644 bsp/spacemit/dm/ethernet/SConscript create mode 100644 bsp/spacemit/dm/ethernet/eth-k1x-emac.c create mode 100644 bsp/spacemit/dm/firmware/SConscript create mode 100644 bsp/spacemit/dm/firmware/firmware-spacemit.c create mode 100644 bsp/spacemit/dm/graphic/SConscript create mode 100644 bsp/spacemit/dm/graphic/framebuffer/Kconfig create mode 100644 bsp/spacemit/dm/graphic/framebuffer/SConscript create mode 100644 bsp/spacemit/dm/graphic/framebuffer/display-spacemit.c create mode 100644 bsp/spacemit/dm/graphic/framebuffer/display-spacemit.h create mode 100644 bsp/spacemit/dm/graphic/framebuffer/fb-spacemit.c create mode 100644 bsp/spacemit/dm/graphic/framebuffer/hdmi-spacemit.c create mode 100644 bsp/spacemit/dm/graphic/logo/Kconfig create mode 100644 bsp/spacemit/dm/graphic/logo/Kconfig.path create mode 100644 bsp/spacemit/dm/graphic/logo/logo-bianbu-clut224.ppm create mode 100644 bsp/spacemit/dm/graphic/logo/logo-spacemit-clut224.ppm create mode 100644 bsp/spacemit/dm/hwcrypto/Kconfig create mode 100644 bsp/spacemit/dm/hwcrypto/SConscript create mode 100644 bsp/spacemit/dm/hwcrypto/hw-crypto-spacemit.c create mode 100644 bsp/spacemit/dm/hwcrypto/hw-rng-spacemit.c create mode 100644 bsp/spacemit/dm/i2c/Kconfig create mode 100644 bsp/spacemit/dm/i2c/SConscript create mode 100644 bsp/spacemit/dm/i2c/i2c-k1x.c create mode 100644 bsp/spacemit/dm/include/dt-bindings/clock/k1x.h create mode 100644 bsp/spacemit/dm/include/dt-bindings/pinctrl/k1x.h create mode 100644 bsp/spacemit/dm/include/dt-bindings/power/k1x_pmu.h create mode 100644 bsp/spacemit/dm/include/dt-bindings/reset/k1x.h create mode 100644 bsp/spacemit/dm/include/firmware-spacemit.h create mode 100644 bsp/spacemit/dm/include/jpu.h create mode 100644 bsp/spacemit/dm/include/k1-cru.h create mode 100644 bsp/spacemit/dm/include/k1-tcm.h create mode 100644 bsp/spacemit/dm/include/k1x-rproc.h create mode 100644 bsp/spacemit/dm/include/mfd/pm853.h create mode 100644 bsp/spacemit/dm/include/mfd/spacemit-pmic.h create mode 100644 bsp/spacemit/dm/include/mfd/spm8821.h create mode 100644 bsp/spacemit/dm/include/mfd/sy8810l.h create mode 100644 bsp/spacemit/dm/include/spacemit.h create mode 100644 bsp/spacemit/dm/include/v2d.h create mode 100644 bsp/spacemit/dm/input/SConscript create mode 100644 bsp/spacemit/dm/input/misc/Kconfig create mode 100644 bsp/spacemit/dm/input/misc/SConscript create mode 100644 bsp/spacemit/dm/input/misc/pwrkey-spacemit-pmic.c create mode 100644 bsp/spacemit/dm/mailbox/Kconfig create mode 100644 bsp/spacemit/dm/mailbox/SConscript create mode 100644 bsp/spacemit/dm/mailbox/mailbox-k1x.c create mode 100644 bsp/spacemit/dm/mfd/Kconfig create mode 100644 bsp/spacemit/dm/mfd/SConscript create mode 100644 bsp/spacemit/dm/mfd/spacemit-pmic.c create mode 100644 bsp/spacemit/dm/nvmem/Kconfig create mode 100644 bsp/spacemit/dm/nvmem/SConscript create mode 100644 bsp/spacemit/dm/nvmem/spacemit-efuse.c create mode 100644 bsp/spacemit/dm/pci/Kconfig create mode 100644 bsp/spacemit/dm/pci/SConscript create mode 100644 bsp/spacemit/dm/pci/pcie-k1x.c create mode 100644 bsp/spacemit/dm/pin/Kconfig create mode 100644 bsp/spacemit/dm/pin/SConscript create mode 100644 bsp/spacemit/dm/pin/pin-k1x.c create mode 100644 bsp/spacemit/dm/pinctrl/Kconfig create mode 100644 bsp/spacemit/dm/pinctrl/SConscript create mode 100644 bsp/spacemit/dm/pinctrl/spacemit-pmic-pinctrl.c create mode 100644 bsp/spacemit/dm/pmdomain/Kconfig create mode 100644 bsp/spacemit/dm/pmdomain/SConscript create mode 100644 bsp/spacemit/dm/pmdomain/pm-domain-k1x.c create mode 100644 bsp/spacemit/dm/power/SConscript create mode 100644 bsp/spacemit/dm/power/reset/Kconfig create mode 100644 bsp/spacemit/dm/power/reset/SConscript create mode 100644 bsp/spacemit/dm/power/reset/reboot-spacemit.c create mode 100644 bsp/spacemit/dm/pwm/Kconfig create mode 100644 bsp/spacemit/dm/pwm/SConscript create mode 100644 bsp/spacemit/dm/pwm/pwm-pxa.c create mode 100644 bsp/spacemit/dm/regulator/Kconfig create mode 100644 bsp/spacemit/dm/regulator/SConscript create mode 100644 bsp/spacemit/dm/regulator/regulator-spacemit-pmic.c create mode 100644 bsp/spacemit/dm/reset/Kconfig create mode 100644 bsp/spacemit/dm/reset/SConscript create mode 100644 bsp/spacemit/dm/reset/reset-spacemit-k1x.c create mode 100644 bsp/spacemit/dm/rtc/Kconfig create mode 100644 bsp/spacemit/dm/rtc/SConscript create mode 100644 bsp/spacemit/dm/rtc/rtc-spacemit-pmic.c create mode 100644 bsp/spacemit/dm/sdio/Kconfig create mode 100644 bsp/spacemit/dm/sdio/SConscript create mode 100644 bsp/spacemit/dm/sdio/sdhci-k1x.c create mode 100644 bsp/spacemit/dm/serial/8250-pxa_k1x.c create mode 100644 bsp/spacemit/dm/serial/Kconfig create mode 100644 bsp/spacemit/dm/serial/SConscript create mode 100644 bsp/spacemit/dm/soc/Kconfig create mode 100644 bsp/spacemit/dm/soc/SConscript create mode 100644 bsp/spacemit/dm/soc/jpu.c create mode 100644 bsp/spacemit/dm/soc/k1x-rproc.c create mode 100644 bsp/spacemit/dm/soc/k1x-tcm.c create mode 100644 bsp/spacemit/dm/soc/sbi-ipi.c create mode 100644 bsp/spacemit/dm/soc/spacemit-socinfo.c create mode 100644 bsp/spacemit/dm/soc/v2d/SConscript create mode 100644 bsp/spacemit/dm/soc/v2d/v2d_drv.c create mode 100644 bsp/spacemit/dm/soc/v2d/v2d_hw.c create mode 100644 bsp/spacemit/dm/soc/v2d/v2d_internal.h create mode 100644 bsp/spacemit/dm/soc/v2d/v2d_reg.h create mode 100644 bsp/spacemit/dm/spi/Kconfig create mode 100644 bsp/spacemit/dm/spi/SConscript create mode 100644 bsp/spacemit/dm/spi/spi-k1x-qspi.c create mode 100644 bsp/spacemit/dm/spi/spi-k1x.c create mode 100644 bsp/spacemit/dm/thermal/Kconfig create mode 100644 bsp/spacemit/dm/thermal/SConscript create mode 100644 bsp/spacemit/dm/thermal/thermal-k1x.c create mode 100644 bsp/spacemit/dm/watchdog/Kconfig create mode 100644 bsp/spacemit/dm/watchdog/SConscript create mode 100644 bsp/spacemit/dm/watchdog/watchdog-k1x.c create mode 100644 bsp/spacemit/k1/.config create mode 100644 bsp/spacemit/k1/.gitignore create mode 100644 bsp/spacemit/k1/Kconfig create mode 100644 bsp/spacemit/k1/README.md create mode 100644 bsp/spacemit/k1/README_en.md create mode 100644 bsp/spacemit/k1/SConscript create mode 100644 bsp/spacemit/k1/SConstruct create mode 100644 bsp/spacemit/k1/applications/SConscript create mode 100644 bsp/spacemit/k1/applications/audio.c create mode 100644 bsp/spacemit/k1/applications/jpu.c create mode 100644 bsp/spacemit/k1/applications/main.c create mode 100644 bsp/spacemit/k1/applications/v2d.c create mode 100644 bsp/spacemit/k1/coremark/LICENSE.md create mode 100644 bsp/spacemit/k1/coremark/README.md create mode 100644 bsp/spacemit/k1/coremark/SConscript create mode 100644 bsp/spacemit/k1/coremark/core_list_join.c create mode 100644 bsp/spacemit/k1/coremark/core_main.c create mode 100644 bsp/spacemit/k1/coremark/core_matrix.c create mode 100644 bsp/spacemit/k1/coremark/core_portme.c create mode 100644 bsp/spacemit/k1/coremark/core_portme.h create mode 100644 bsp/spacemit/k1/coremark/core_state.c create mode 100644 bsp/spacemit/k1/coremark/core_util.c create mode 100644 bsp/spacemit/k1/coremark/coremark.h create mode 100644 bsp/spacemit/k1/coremark/iteration.png create mode 100644 bsp/spacemit/k1/drivers/README.md create mode 100644 bsp/spacemit/k1/drivers/SConscript create mode 100644 bsp/spacemit/k1/drivers/board.c create mode 100644 bsp/spacemit/k1/drivers/board.h create mode 100644 bsp/spacemit/k1/drivers/esos.elf create mode 100644 bsp/spacemit/k1/drivers/firmware.S create mode 100644 bsp/spacemit/k1/rtconfig.h create mode 100644 bsp/spacemit/k1/rtconfig.py diff --git a/bsp/spacemit/dm/Kconfig b/bsp/spacemit/dm/Kconfig new file mode 100644 index 000000000000..0fdd2b6ae726 --- /dev/null +++ b/bsp/spacemit/dm/Kconfig @@ -0,0 +1,31 @@ +SOC_DM_ADC_DIR = $(SOC_DM_DIR)/adc +SOC_DM_AUDIO_DIR = $(SOC_DM_DIR)/audio +SOC_DM_CLK_DIR = $(SOC_DM_DIR)/clk +SOC_DM_DMA_DIR = $(SOC_DM_DIR)/dma +SOC_DM_DVFS_CPUFREQ_DIR = $(SOC_DM_DIR)/dvfs/cpufreq +SOC_DM_ETHERNET_DIR = $(SOC_DM_DIR)/ethernet +SOC_DM_GRAPHIC_FB_DIR = $(SOC_DM_DIR)/graphic/framebuffer +SOC_DM_GRAPHIC_LOGO_DIR = $(SOC_DM_DIR)/graphic/logo +SOC_DM_HWCRYPTO_DIR = $(SOC_DM_DIR)/hwcrypto +SOC_DM_CLOCK_TIME_DIR = $(SOC_DM_DIR)/clock_time +SOC_DM_I2C_DIR = $(SOC_DM_DIR)/i2c +SOC_DM_INPUT_MISC_DIR = $(SOC_DM_DIR)/input/misc +SOC_DM_MBOX_DIR = $(SOC_DM_DIR)/mailbox +SOC_DM_MFD_DIR = $(SOC_DM_DIR)/mfd +SOC_DM_NVMEM_DIR = $(SOC_DM_DIR)/nvmem +SOC_DM_PCI_DIR = $(SOC_DM_DIR)/pci +SOC_DM_PIC_DIR = $(RTT_DIR)/libcpu/risc-v/common/pic +SOC_DM_PIN_DIR = $(SOC_DM_DIR)/pin +SOC_DM_PINCTRL_DIR = $(SOC_DM_DIR)/pinctrl +SOC_DM_PMDOMAIN_DIR = $(SOC_DM_DIR)/pmdomain +SOC_DM_POWER_RESET_DIR = $(SOC_DM_DIR)/power/reset +SOC_DM_PWM_DIR = $(SOC_DM_DIR)/pwm +SOC_DM_REGULATOR_DIR = $(SOC_DM_DIR)/regulator +SOC_DM_RESET_DIR = $(SOC_DM_DIR)/reset +SOC_DM_RTC_DIR = $(SOC_DM_DIR)/rtc +SOC_DM_SDIO_DIR = $(SOC_DM_DIR)/sdio +SOC_DM_SERIAL_DIR = $(SOC_DM_DIR)/serial +SOC_DM_SOC_DIR = $(SOC_DM_DIR)/soc +SOC_DM_SPI_DIR = $(SOC_DM_DIR)/spi +SOC_DM_THERMAL_DIR = $(SOC_DM_DIR)/thermal +SOC_DM_WDT_DIR = $(SOC_DM_DIR)/watchdog diff --git a/bsp/spacemit/dm/SConscript b/bsp/spacemit/dm/SConscript new file mode 100644 index 000000000000..3d15055d62d2 --- /dev/null +++ b/bsp/spacemit/dm/SConscript @@ -0,0 +1,13 @@ +import os +from building import * + +cwd = GetCurrentDir() +objs = [] +list = os.listdir(cwd) + +for d in list: + path = os.path.join(cwd, d) + if os.path.isfile(os.path.join(path, 'SConscript')): + objs = objs + SConscript(os.path.join(d, 'SConscript')) + +Return('objs') diff --git a/bsp/spacemit/dm/adc/Kconfig b/bsp/spacemit/dm/adc/Kconfig new file mode 100644 index 000000000000..b93a301f8e60 --- /dev/null +++ b/bsp/spacemit/dm/adc/Kconfig @@ -0,0 +1,6 @@ +config RT_ADC_SPACEMIT_PMIC + bool "Spacemit PMIC ADC driver" + depends on RT_USING_DM + depends on RT_USING_ADC + depends on RT_MFD_SPACEMIT_PMIC + default n diff --git a/bsp/spacemit/dm/adc/SConscript b/bsp/spacemit/dm/adc/SConscript new file mode 100644 index 000000000000..a8ffbf9482dc --- /dev/null +++ b/bsp/spacemit/dm/adc/SConscript @@ -0,0 +1,14 @@ +from building import * + +group = [] +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../include'] + +src = [] + +if GetDepend(['RT_ADC_SPACEMIT_PMIC']): + src += ['adc-spacemit-pmic.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/spacemit/dm/adc/adc-spacemit-pmic.c b/bsp/spacemit/dm/adc/adc-spacemit-pmic.c new file mode 100644 index 000000000000..b7bf65b00a7c --- /dev/null +++ b/bsp/spacemit/dm/adc/adc-spacemit-pmic.c @@ -0,0 +1,308 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#define DBG_TAG "adc.spacemit-pmic" +#define DBG_LVL DBG_INFO +#include + +#define __SPACEMIT_ADC_INTERNAL +#include + +#define SPACEMIT_PMIC_ADC_TIMEOUT_MS 1000 + +struct spacemit_pmic_adc +{ + struct rt_adc_device parent; + + int irq; + + struct spacemit_pmic *pmic; + const struct spacemit_pmic_adc_data *data; + + struct rt_mutex lock; + struct rt_completion completion; +}; + +#define raw_to_spacemit_pmic_adc(raw) rt_container_of(raw, struct spacemit_pmic_adc, parent) + +static rt_err_t spacemit_pmic_adc_enabled(struct rt_adc_device *device, + rt_int8_t channel, rt_bool_t enabled) +{ + struct spacemit_pmic_adc *pmic_adc = raw_to_spacemit_pmic_adc(device); + + if (channel < 0 || channel >= pmic_adc->data->iio_desc_nr) + { + return -RT_EINVAL; + } + + return RT_EOK; +} + +static rt_err_t spacemit_pmic_adc_convert(struct rt_adc_device *device, + rt_int8_t channel, rt_uint32_t *value) +{ + rt_err_t err; + rt_uint32_t tmp, adc_val_h, adc_val_l; + struct spacemit_pmic_adc *pmic_adc = raw_to_spacemit_pmic_adc(device); + struct spacemit_pmic *pmic = pmic_adc->pmic; + + if (!value || channel < 0 || channel >= pmic_adc->data->iio_desc_nr) + { + return -RT_EINVAL; + } + + if ((err = rt_mutex_take(&pmic_adc->lock, RT_WAITING_FOREVER))) + { + return err; + } + + /* Reset the ADC auto register */ + if ((err = spacemit_pmic_update_bits(pmic, SPM8821_ADC_AUTO_REG, + SPM8821_ADC_AUTO_BIT_MSK, 0))) + { + goto _out_lock; + } + + /* Enable the ADC : ADC_CTRL[0] */ + if ((err = spacemit_pmic_update_bits(pmic, SPM8821_ADC_CTRL_REG, + SPM8821_ADC_CTRL_BIT_MSK, (1 << SPM8821_ADC_CTRL_EN_BIT_OFFSET)))) + { + goto _out_lock; + } + + /* Choose the channel of adc : ADC_CFG[1] */ + if ((err = spacemit_pmic_update_bits(pmic, SPM8821_ADC_CFG1_REG, + SPM8821_ADC_CFG1_ADC_CHNNL_SEL_BIT_MSK, + (channel + SPM8821_ADC_EXTERNAL_CHANNEL_OFFSET) << + SPM8821_ADC_CFG1_ADC_CHNNL_SEL_BIT_OFFSET))) + { + goto _out_lock; + } + + rt_completion_init(&pmic_adc->completion); + + /* ADC go */ + if ((err = spacemit_pmic_update_bits(pmic, SPM8821_ADC_CTRL_REG, + SPM8821_ADC_CTRL_BIT_MSK, + (1 << SPM8821_ADC_CTRL_GO_BIT_OFFSET) | + (1 << SPM8821_ADC_CTRL_EN_BIT_OFFSET)))) + { + goto _out_lock; + } + + err = rt_completion_wait(&pmic_adc->completion, + rt_tick_from_millisecond(SPACEMIT_PMIC_ADC_TIMEOUT_MS)); + + if (err) + { + unsigned long auto_reg, cfg1, cfg2, ctrl; + unsigned long enable, result_h, result_l, status; + + ctrl = spacemit_pmic_read(pmic, SPM8821_ADC_CTRL_REG); + cfg1 = spacemit_pmic_read(pmic, SPM8821_ADC_CFG1_REG); + cfg2 = spacemit_pmic_read(pmic, SPM8821_ADC_CFG2_REG); + auto_reg = spacemit_pmic_read(pmic, SPM8821_ADC_AUTO_REG); + status = spacemit_pmic_read(pmic, SPM8821_E_STATUS_REG_BASE + 1); + enable = spacemit_pmic_read(pmic, SPM8821_E_EN_REG_BASE + 1); + result_h = spacemit_pmic_read(pmic, + SPM8821_ADCIN0_RES_H_REG + channel * 2); + result_l = spacemit_pmic_read(pmic, + SPM8821_ADCIN0_RES_L_REG + channel * 2); + + LOG_E("ADC channel %d conversion timed out: %s", channel, rt_strerror(err)); + LOG_E("ADC regs: ctrl=%02lx cfg1=%02lx cfg2=%02lx auto=%02lx " + "status=%02lx enable=%02lx result=%02lx:%02lx", + ctrl, cfg1, cfg2, auto_reg, status, enable, result_h, result_l); + goto _out_lock; + } + + adc_val_h = spacemit_pmic_read(pmic, SPM8821_ADCIN0_RES_H_REG + channel * 2); + + if ((rt_err_t)adc_val_h < 0) + { + err = (rt_err_t)adc_val_h; + goto _out_lock; + } + + adc_val_l = spacemit_pmic_read(pmic, SPM8821_ADCIN0_RES_L_REG + channel * 2); + + if ((rt_err_t)adc_val_l < 0) + { + err = (rt_err_t)adc_val_l; + goto _out_lock; + } + + tmp = spacemit_pmic_read(pmic, SPM8821_VERSION_ID_REG); + + if ((rt_err_t)tmp < 0) + { + err = (rt_err_t)tmp; + goto _out_lock; + } + + *value = (adc_val_h << (__rt_ffs(SPM8821_ADCIN0_REG_L_BIT_MSK) - 1)) | + ((adc_val_l & SPM8821_ADCIN0_REG_L_BIT_MSK) >> + (__rt_ffs(SPM8821_ADCIN0_REG_L_BIT_MSK) - 1)); + + if (tmp == 0) + { + /* + * if the version of P1 is A, the data read from + * the register is the inverse of the real data + * and the conversion accuracy of P1 is 12 bits + */ + *value = 4095 - *value; + } + + err = RT_EOK; + +_out_lock: + rt_mutex_release(&pmic_adc->lock); + + return err; +} + +static rt_uint8_t spacemit_pmic_adc_get_resolution(struct rt_adc_device *device) +{ + return 12; +} + +static rt_int16_t spacemit_pmic_adc_get_vref(struct rt_adc_device *device) +{ + return 3000; +} + +static const struct rt_adc_ops spacemit_pmic_adc_ops = +{ + .enabled = spacemit_pmic_adc_enabled, + .convert = spacemit_pmic_adc_convert, + .get_resolution = spacemit_pmic_adc_get_resolution, + .get_vref = spacemit_pmic_adc_get_vref, +}; + +static void spacemit_pmic_adc_isr(int irq, void *param) +{ + struct spacemit_pmic_adc *pmic_adc = param; + + rt_completion_done(&pmic_adc->completion); +} + +static rt_err_t spacemit_pmic_adc_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + const char *dev_name; + struct rt_device *dev = &pdev->parent; + struct spacemit_pmic *pmic = pdev->priv; + struct spacemit_pmic_adc *pmic_adc = rt_calloc(1, sizeof(*pmic_adc)); + const struct spacemit_pmic_adc_data *data = pdev->id->data; + + if (!pmic_adc) + { + return -RT_ENOMEM; + } + + pmic_adc->pmic = pmic; + pmic_adc->data = data; + + if ((pmic_adc->irq = rt_dm_dev_get_irq(dev, 0)) < 0) + { + err = pmic_adc->irq; + goto _fail; + } + + /* Enable chop */ + if ((err = spacemit_pmic_update_bits(pmic, + SPM8821_ADC_CFG1_REG, + SPM8821_ADC_CFG1_ADC_CHOP_EN_BIT_MSK, + 1 << SPM8821_ADC_CFG1_ADC_CHOP_EN_BIT_OFFSET))) + { + goto _fail; + } + + /* Set the vref: 3v3 */ + if ((err = spacemit_pmic_update_bits(pmic, + SPM8821_ADC_CFG2_REG, + SPM8821_ADC_CFG2_REF_SEL_BIT_MSK, + SPM8821_ADC_CFG2_3V3_REF << SPM8821_ADC_CFG2_REF_SEL_BIT_OFFSET))) + { + goto _fail; + } + + /* Set adc deb num: 7 */ + if ((err = spacemit_pmic_update_bits(pmic, + SPM8821_ADC_CFG2_REG, + SPM8821_ADC_CFG2_DEB_NUM_BIT_MSK, + SPM8821_ADC_CFG2_7_DEB_NUM << SPM8821_ADC_CFG2_DEB_NUM_BIT_OFFSET))) + { + goto _fail; + } + + dev->user_data = pmic_adc; + + rt_dm_dev_set_name_auto(&pmic_adc->parent.parent, "adc"); + dev_name = rt_dm_dev_get_name(&pmic_adc->parent.parent); + + if ((err = rt_mutex_init(&pmic_adc->lock, dev_name, RT_IPC_FLAG_PRIO))) + { + goto _fail; + } + + rt_completion_init(&pmic_adc->completion); + + if ((err = rt_hw_adc_register(&pmic_adc->parent, dev_name, + &spacemit_pmic_adc_ops, pmic_adc))) + { + rt_mutex_detach(&pmic_adc->lock); + goto _fail; + } + + rt_hw_interrupt_install(pmic_adc->irq, spacemit_pmic_adc_isr, pmic_adc, "adc-spacemit-pmic"); + rt_hw_interrupt_umask(pmic_adc->irq); + + rt_dm_dev_bind_fwdata(dev, RT_NULL, pmic_adc); + + return RT_EOK; + +_fail: + rt_free(pmic_adc); + + return err; +} + +static rt_err_t spacemit_pmic_adc_remove(struct rt_platform_device *pdev) +{ + struct spacemit_pmic_adc *pmic_adc = pdev->parent.user_data; + + rt_hw_interrupt_mask(pmic_adc->irq); + rt_pic_detach_irq(pmic_adc->irq, pmic_adc); + + rt_device_unregister(&pmic_adc->parent.parent); + rt_mutex_detach(&pmic_adc->lock); + + rt_free(pmic_adc); + + return RT_EOK; +} + +static const struct rt_ofw_node_id spacemit_pmic_adc_ofw_ids[] = +{ + { .compatible = "pmic,adc,spm8821", .data = &spm8821_adc_data }, + { /* sentinel */ } +}; + +static struct rt_platform_driver spacemit_pmic_adc_driver = +{ + .name = "spacemit-pmic-adc", + .ids = spacemit_pmic_adc_ofw_ids, + + .probe = spacemit_pmic_adc_probe, + .remove = spacemit_pmic_adc_remove, +}; +RT_PLATFORM_DRIVER_EXPORT(spacemit_pmic_adc_driver); diff --git a/bsp/spacemit/dm/audio/Kconfig b/bsp/spacemit/dm/audio/Kconfig new file mode 100644 index 000000000000..85d9b65f7485 --- /dev/null +++ b/bsp/spacemit/dm/audio/Kconfig @@ -0,0 +1,29 @@ +config RT_AUDIO_SPACEMIT + bool "Spacemit K1 audio" + depends on RT_USING_AUDIO + depends on RT_USING_OFW + depends on RT_USING_DMA + depends on RT_USING_CLK + depends on RT_USING_RESET + depends on RT_USING_PIN + depends on RT_USING_I2C + depends on RT_USING_RPMSG + depends on RT_VIRTIO_RPMSG + depends on RT_SOC_SPACEMIT_K1X_RPROC + select RT_AUDIO_SPACEMIT_CODEC_ES8326 + default n + help + Enable the K1 I2S and HDMI audio paths. Both cards operate at 48 kHz, + stereo, 16-bit PCM. The HDMI card supports playback. + +config RT_AUDIO_SPACEMIT_CODEC + bool "Spacemit codec support" + depends on RT_AUDIO_SPACEMIT + default y + +config RT_AUDIO_SPACEMIT_CODEC_ES8326 + bool "ES8326 codec" + depends on RT_AUDIO_SPACEMIT_CODEC + default y + help + ES8326 codec supports playback and capture diff --git a/bsp/spacemit/dm/audio/SConscript b/bsp/spacemit/dm/audio/SConscript new file mode 100644 index 000000000000..352f617cebde --- /dev/null +++ b/bsp/spacemit/dm/audio/SConscript @@ -0,0 +1,15 @@ +from building import * + +cwd = GetCurrentDir() +src = [] + +if GetDepend(['RT_AUDIO_SPACEMIT']): + src += ['spacemit-snd-card.c', 'spacemit-snd-i2s.c', 'spacemit-snd-pcm-dma.c', 'spacemit-snd-sspa.c'] + +if GetDepend(['RT_AUDIO_SPACEMIT_CODEC_ES8326']): + src += ['codec/es8326.c'] + +group = DefineGroup('DeviceDrivers', src, depend=[], + CPPPATH=[cwd, cwd + '/../include']) + +Return('group') diff --git a/bsp/spacemit/dm/audio/codec/es8326.c b/bsp/spacemit/dm/audio/codec/es8326.c new file mode 100644 index 000000000000..114fa580935b --- /dev/null +++ b/bsp/spacemit/dm/audio/codec/es8326.c @@ -0,0 +1,528 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#define DBG_TAG "codec.es8326" +#define DBG_LVL DBG_INFO +#include + +#include "spacemit-audio.h" +#include "es8326.h" + +struct es8326_codec +{ + struct rt_i2c_client *client; + struct rt_ofw_node *np; + struct rt_mutex lock; + + rt_uint8_t mic1_src; + rt_uint8_t mic2_src; + rt_uint8_t jack_pol; + rt_uint8_t interrupt_clk; + rt_uint8_t version; + rt_uint8_t volume; + + rt_base_t speaker_pin; + rt_uint8_t speaker_active; + rt_bool_t calibrated; + rt_bool_t muted; + + rt_list_t list; +}; + +struct es8326_coeff +{ + rt_uint16_t mclk_fs; + rt_uint8_t reg[8]; +}; + +static const struct es8326_coeff es8326_coeff_v0[] = +{ + { 64, { 0xe0, 0x00, 0x03, 0x2d, 0x4a, 0x0a, 0x1f, 0x1f } }, + { 128, { 0xe0, 0x01, 0x03, 0x2d, 0x4a, 0x0a, 0x1f, 0x1f } }, + { 256, { 0xe0, 0x00, 0x30, 0x2d, 0x4a, 0x0a, 0x1f, 0x1f } }, +}; + +static const struct es8326_coeff es8326_coeff_v3[] = +{ + { 64, { 0xe0, 0x00, 0x31, 0x2d, 0xca, 0x0a, 0x1f, 0x1f } }, + { 128, { 0xe0, 0x00, 0x01, 0x2d, 0xca, 0x0a, 0x1f, 0x1f } }, + { 256, { 0xe0, 0x00, 0x30, 0x2d, 0xca, 0x0a, 0x1f, 0x1f } }, +}; + +static rt_list_t codec_nodes = RT_LIST_OBJECT_INIT(codec_nodes); +static RT_DEFINE_SPINLOCK(codec_nodes_lock); + +static rt_err_t es8326_write_reg(struct es8326_codec *codec, + rt_uint8_t reg, rt_uint8_t value) +{ + rt_uint8_t data[2] = { reg, value }; + + return rt_i2c_master_send(codec->client->bus, codec->client->client_addr, + RT_I2C_WR, data, sizeof(data)) == sizeof(data) ? RT_EOK : -RT_EIO; +} + +static rt_err_t es8326_read_reg(struct es8326_codec *codec, + rt_uint8_t reg, rt_uint8_t *value) +{ + struct rt_i2c_msg messages[2]; + + messages[0].addr = codec->client->client_addr; + messages[0].flags = RT_I2C_WR; + messages[0].buf = ® + messages[0].len = 1; + messages[1].addr = codec->client->client_addr; + messages[1].flags = RT_I2C_RD; + messages[1].buf = value; + messages[1].len = 1; + + return rt_i2c_transfer(codec->client->bus, messages, 2) == 2 ? + RT_EOK : -RT_EIO; +} + +static rt_err_t es8326_update_bits(struct es8326_codec *codec, + rt_uint8_t reg, rt_uint8_t mask, rt_uint8_t value) +{ + rt_err_t err; + rt_uint8_t old; + + if ((err = es8326_read_reg(codec, reg, &old))) + { + return err; + } + + value = (old & ~mask) | (value & mask); + return value == old ? RT_EOK : es8326_write_reg(codec, reg, value); +} + +static void es8326_speaker_set(struct es8326_codec *codec, rt_bool_t enable) +{ + if (codec->speaker_pin >= 0) + { + rt_pin_write(codec->speaker_pin, + enable ? codec->speaker_active : !codec->speaker_active); + } +} + +static rt_err_t es8326_calibrate(struct es8326_codec *codec) +{ + rt_err_t err; + rt_uint8_t status, offset_l, offset_r; + + if (codec->version != ES8326_VERSION_B || codec->calibrated) + { + return RT_EOK; + } + + LOG_D("ES8326 B revision headphone calibration begin"); + + if ((err = es8326_write_reg(codec, ES8326_CLK_INV, 0xc0)) || + (err = es8326_write_reg(codec, ES8326_CLK_DIV1, 0x03)) || + (err = es8326_write_reg(codec, ES8326_CLK_DLL, 0x30)) || + (err = es8326_write_reg(codec, ES8326_CLK_MUX, 0xed)) || + (err = es8326_write_reg(codec, ES8326_CLK_DAC_SEL, 0x08)) || + (err = es8326_write_reg(codec, ES8326_CLK_TRI, 0xc1)) || + (err = es8326_write_reg(codec, ES8326_DAC_MUTE, 0x03)) || + (err = es8326_write_reg(codec, ES8326_ANA_VSEL, 0x7f)) || + (err = es8326_write_reg(codec, ES8326_VMIDLOW, 0x23)) || + (err = es8326_write_reg(codec, ES8326_DAC2HPMIX, 0x88))) + { + return err; + } + + rt_thread_mdelay(16); + es8326_write_reg(codec, ES8326_HP_OFFSET_CAL, 0x8c); + rt_thread_mdelay(16); + es8326_write_reg(codec, ES8326_RESET, 0xc0); + rt_thread_mdelay(16); + es8326_write_reg(codec, ES8326_HP_OFFSET_CAL, ES8326_HP_OFF); + + if (!es8326_read_reg(codec, ES8326_CSM_MUTE_STA, &status) && + (status & 0xf0) != 0x40) + { + rt_thread_mdelay(50); + } + + es8326_write_reg(codec, ES8326_HP_CAL, 0xd4); + rt_thread_mdelay(200); + es8326_write_reg(codec, ES8326_HP_CAL, 0x4d); + rt_thread_mdelay(200); + es8326_write_reg(codec, ES8326_HP_CAL, ES8326_HP_OFF); + + if ((err = es8326_read_reg(codec, ES8326_HPL_OFFSET_INI, &offset_l)) || + (err = es8326_read_reg(codec, ES8326_HPR_OFFSET_INI, &offset_r))) + { + return err; + } + + es8326_write_reg(codec, ES8326_HP_OFFSET_CAL, 0x8c); + es8326_write_reg(codec, ES8326_HPL_OFFSET_INI, offset_l); + es8326_write_reg(codec, ES8326_HPR_OFFSET_INI, offset_r); + es8326_write_reg(codec, ES8326_CLK_INV, 0x00); + codec->calibrated = RT_TRUE; + + return RT_EOK; +} + +static rt_err_t es8326_hw_init(struct es8326_codec *codec) +{ + rt_err_t err; + rt_uint8_t id1, id2; + + if ((err = es8326_read_reg(codec, ES8326_CHIP_ID1, &id1)) || + (err = es8326_read_reg(codec, ES8326_CHIP_ID2, &id2)) || + (err = es8326_read_reg(codec, ES8326_CHIP_VERSION, &codec->version))) + { + return err; + } + + es8326_write_reg(codec, ES8326_RESET, 0x1f); + es8326_write_reg(codec, ES8326_VMIDSEL, 0x0e); + es8326_write_reg(codec, ES8326_ANA_LP, 0xf0); + rt_thread_mdelay(10); + es8326_write_reg(codec, ES8326_HPJACK_TIMER, 0xd9); + es8326_write_reg(codec, ES8326_ANA_MICBIAS, 0xd8); + es8326_write_reg(codec, ES8326_HPDET_TYPE, 0x83); + es8326_write_reg(codec, ES8326_CLK_RESAMPLE, 0x05); + es8326_write_reg(codec, ES8326_CLK_DIV_CPC, 0x89); + es8326_write_reg(codec, ES8326_CLK_CTL, ES8326_CLK_ON); + es8326_write_reg(codec, ES8326_RESET, 0x17); + es8326_write_reg(codec, ES8326_HP_MISC, 0x3d); + es8326_write_reg(codec, ES8326_PULLUP_CTL, 0x00); + + es8326_write_reg(codec, ES8326_HP_VOL, 0xc4); + es8326_write_reg(codec, ES8326_HP_DRIVER, 0xa7); + rt_hw_us_delay(2000); + es8326_write_reg(codec, ES8326_HP_DRIVER_REF, 0x23); + es8326_write_reg(codec, ES8326_HP_DRIVER_REF, 0x33); + es8326_write_reg(codec, ES8326_HP_DRIVER, 0xa1); + + es8326_write_reg(codec, ES8326_CLK_INV, 0x00); + es8326_write_reg(codec, ES8326_CLK_VMIDS1, 0xc4); + es8326_write_reg(codec, ES8326_CLK_VMIDS2, 0x81); + es8326_write_reg(codec, ES8326_CLK_CAL_TIME, 0x00); + + if ((err = es8326_calibrate(codec))) + { + return err; + } + + es8326_write_reg(codec, ES8326_DAC_CROSSTALK, 0xaa); + es8326_write_reg(codec, ES8326_DAC_RAMPRATE, 0x00); + es8326_write_reg(codec, ES8326_HP_CAL, ES8326_HP_OFF); + es8326_write_reg(codec, ES8326_ANA_LP, 0xf0); + es8326_write_reg(codec, ES8326_ANA_VSEL, 0x7f); + es8326_write_reg(codec, ES8326_VMIDLOW, 0x03); + es8326_write_reg(codec, ES8326_DAC_DSM, 0x08); + es8326_write_reg(codec, ES8326_DAC_VPPSCALE, 0x15); + es8326_write_reg(codec, ES8326_HPDET_TYPE, 0x80 | + ES8326_HP_DET_SRC_PIN9 | codec->jack_pol | + (codec->version == ES8326_VERSION_B ? 0 : 0x04)); + rt_thread_mdelay(60); + es8326_update_bits(codec, ES8326_HPDET_TYPE, 0x03, 0x00); + es8326_write_reg(codec, ES8326_INT_SOURCE, ES8326_INT_SRC_PIN9); + es8326_write_reg(codec, ES8326_INTOUT_IO, codec->interrupt_clk); + es8326_write_reg(codec, ES8326_SDINOUT1_IO, + ES8326_IO_DMIC_CLK << ES8326_SDINOUT1_SHIFT); + es8326_write_reg(codec, ES8326_SDINOUT23_IO, ES8326_IO_INPUT); + es8326_write_reg(codec, ES8326_ANA_PDN, 0x00); + es8326_write_reg(codec, ES8326_RESET, ES8326_CSM_ON); + es8326_update_bits(codec, ES8326_PGAGAIN, + ES8326_MIC_SEL_MASK, ES8326_MIC1_SEL); + es8326_update_bits(codec, ES8326_DAC_MUTE, + ES8326_MUTE_MASK, ES8326_MUTE); + es8326_write_reg(codec, ES8326_ADC_MUTE, 0x0f); + es8326_write_reg(codec, ES8326_ADC1_SRC, codec->mic1_src); + es8326_write_reg(codec, ES8326_ADC2_SRC, codec->mic2_src); + es8326_write_reg(codec, ES8326_FMT, ES8326_S16_LE); + + codec->muted = RT_TRUE; + LOG_D("ES8326 id=%02x%02x revision=%u", id1, id2, codec->version); + + return RT_EOK; +} + +struct es8326_codec *es8326_codec_find(struct rt_ofw_node *np) +{ + struct es8326_codec *codec; + + rt_spin_lock(&codec_nodes_lock); + rt_list_for_each_entry(codec, &codec_nodes, list) + { + if (codec->np == np) + { + rt_spin_unlock(&codec_nodes_lock); + return codec; + } + } + rt_spin_unlock(&codec_nodes_lock); + + return RT_NULL; +} + +rt_err_t es8326_codec_hw_params(struct es8326_codec *codec, + const struct spacemit_audio_config *config) +{ + const struct es8326_coeff *coeffs; + rt_size_t count; + rt_err_t err = -RT_EINVAL; + + if (!codec || !config || config->samplerate != 48000 || + config->channels != 2 || config->samplebits != 16) + { + return -RT_EINVAL; + } + + if (codec->version == 0) + { + coeffs = es8326_coeff_v0; + count = RT_ARRAY_SIZE(es8326_coeff_v0); + } + else + { + coeffs = es8326_coeff_v3; + count = RT_ARRAY_SIZE(es8326_coeff_v3); + } + + rt_mutex_take(&codec->lock, RT_WAITING_FOREVER); + for (rt_size_t i = 0; i < count; ++i) + { + if (coeffs[i].mclk_fs == config->mclk_fs) + { + err = es8326_update_bits(codec, ES8326_FMT, + ES8326_DATA_LEN_MASK, ES8326_S16_LE); + for (rt_size_t reg = 0; !err && reg < sizeof(coeffs[i].reg); ++reg) + { + err = es8326_write_reg(codec, ES8326_CLK_DIV1 + reg, + coeffs[i].reg[reg]); + } + break; + } + } + rt_mutex_release(&codec->lock); + + return err; +} + +rt_err_t es8326_codec_start(struct es8326_codec *codec, int stream) +{ + rt_err_t err = RT_EOK; + rt_uint8_t hpdet; + + if (!codec || (stream != AUDIO_STREAM_REPLAY && stream != AUDIO_STREAM_RECORD)) + { + return -RT_EINVAL; + } + + rt_mutex_take(&codec->lock, RT_WAITING_FOREVER); + if (stream == AUDIO_STREAM_REPLAY) + { + es8326_update_bits(codec, ES8326_DAC_DSM, 0x01, 0x01); + rt_hw_us_delay(1000); + es8326_update_bits(codec, ES8326_DAC_DSM, 0x01, 0x00); + rt_hw_us_delay(1000); + es8326_update_bits(codec, ES8326_HP_DRIVER_REF, 0x30, 0x20); + es8326_update_bits(codec, ES8326_HP_DRIVER_REF, 0x30, 0x30); + es8326_write_reg(codec, ES8326_HP_DRIVER, 0xa1); + es8326_write_reg(codec, ES8326_HP_CAL, ES8326_HP_ON); + err = es8326_update_bits(codec, ES8326_DAC_MUTE, + ES8326_MUTE_MASK, 0); + codec->muted = RT_FALSE; + + if (es8326_read_reg(codec, ES8326_HPDET_STA, &hpdet) || + !(hpdet & ES8326_HPINSERT_FLAG)) + { + es8326_speaker_set(codec, RT_TRUE); + } + } + else + { + rt_thread_mdelay(300); + err = es8326_update_bits(codec, ES8326_ADC_MUTE, 0x0f, 0x00); + } + rt_mutex_release(&codec->lock); + + return err; +} + +rt_err_t es8326_codec_stop(struct es8326_codec *codec, int stream) +{ + rt_err_t err; + + if (!codec || (stream != AUDIO_STREAM_REPLAY && stream != AUDIO_STREAM_RECORD)) + { + return -RT_EINVAL; + } + + rt_mutex_take(&codec->lock, RT_WAITING_FOREVER); + if (stream == AUDIO_STREAM_REPLAY) + { + es8326_speaker_set(codec, RT_FALSE); + es8326_write_reg(codec, ES8326_HP_CAL, ES8326_HP_OFF); + err = es8326_update_bits(codec, ES8326_DAC_MUTE, + ES8326_MUTE_MASK, ES8326_MUTE); + es8326_update_bits(codec, ES8326_HP_DRIVER_REF, 0x30, 0x00); + codec->muted = RT_TRUE; + } + else + { + err = es8326_update_bits(codec, ES8326_ADC_MUTE, 0x0f, 0x0f); + } + rt_mutex_release(&codec->lock); + + return err; +} + +rt_err_t es8326_codec_set_volume(struct es8326_codec *codec, int volume) +{ + rt_err_t err; + + if (!codec) + { + return -RT_EINVAL; + } + + if (volume < AUDIO_VOLUME_MIN) + { + volume = AUDIO_VOLUME_MIN; + } + if (volume > AUDIO_VOLUME_MAX) + { + volume = AUDIO_VOLUME_MAX; + } + rt_mutex_take(&codec->lock, RT_WAITING_FOREVER); + err = es8326_write_reg(codec, ES8326_DAC_VOL, + (rt_uint8_t)(volume * 0xbf / AUDIO_VOLUME_MAX)); + if (!err) + { + codec->volume = volume; + } + rt_mutex_release(&codec->lock); + + return err; +} + +rt_err_t es8326_codec_set_mute(struct es8326_codec *codec, rt_bool_t mute) +{ + rt_err_t err; + rt_uint8_t hpdet; + + if (!codec) + { + return -RT_EINVAL; + } + + rt_mutex_take(&codec->lock, RT_WAITING_FOREVER); + err = es8326_update_bits(codec, ES8326_DAC_MUTE, + ES8326_MUTE_MASK, mute ? ES8326_MUTE : 0); + if (!err) + { + codec->muted = mute; + if (mute) + { + es8326_speaker_set(codec, RT_FALSE); + } + else if (es8326_read_reg(codec, ES8326_HPDET_STA, &hpdet) || + !(hpdet & ES8326_HPINSERT_FLAG)) + { + es8326_speaker_set(codec, RT_TRUE); + } + } + rt_mutex_release(&codec->lock); + + return err; +} + +static rt_err_t es8326_probe(struct rt_i2c_client *client) +{ + rt_err_t err; + rt_uint8_t pin_mode; + struct es8326_codec *codec = rt_calloc(1, sizeof(*codec)); + + if (!codec) + { + return -RT_ENOMEM; + } + + codec->client = client; + codec->np = client->parent.ofw_node; + codec->mic1_src = ES8326_ADC_AMIC; + codec->mic2_src = ES8326_ADC_DMIC; + codec->jack_pol = ES8326_HP_TYPE_AUTO; + codec->volume = 70; + codec->speaker_pin = -1; + rt_mutex_init(&codec->lock, "es8326", RT_IPC_FLAG_PRIO); + + rt_ofw_prop_read_u8(codec->np, "everest,mic1-src", &codec->mic1_src); + rt_ofw_prop_read_u8(codec->np, "everest,mic2-src", &codec->mic2_src); + rt_ofw_prop_read_u8(codec->np, "everest,jack-pol", &codec->jack_pol); + rt_ofw_prop_read_u8(codec->np, "everest,interrupt-clk", &codec->interrupt_clk); + + codec->speaker_pin = rt_pin_get_named_pin(&client->parent, "spk-ctl", 0, + &pin_mode, &codec->speaker_active); + if (codec->speaker_pin >= 0) + { + rt_pin_mode(codec->speaker_pin, PIN_MODE_OUTPUT); + es8326_speaker_set(codec, RT_FALSE); + } + + if ((err = es8326_hw_init(codec)) || + (err = es8326_codec_hw_params(codec, + &(struct spacemit_audio_config){ 48000, 2, 16, 64 })) || + (err = es8326_codec_set_volume(codec, codec->volume))) + { + LOG_E("ES8326 initialization failed: %s", rt_strerror(err)); + rt_mutex_detach(&codec->lock); + rt_free(codec); + return err; + } + + rt_spin_lock(&codec_nodes_lock); + rt_list_insert_before(&codec_nodes, &codec->list); + rt_spin_unlock(&codec_nodes_lock); + + client->parent.user_data = codec; + rt_dm_dev_bind_fwdata(&client->parent, RT_NULL, codec); + + return RT_EOK; +} + +static rt_err_t es8326_remove(struct rt_i2c_client *client) +{ + struct es8326_codec *codec = client->parent.user_data; + + if (!codec) + { + return RT_EOK; + } + + es8326_speaker_set(codec, RT_FALSE); + rt_spin_lock(&codec_nodes_lock); + rt_list_remove(&codec->list); + rt_spin_unlock(&codec_nodes_lock); + rt_dm_dev_unbind_fwdata(&client->parent, RT_NULL); + rt_mutex_detach(&codec->lock); + rt_free(codec); + + return RT_EOK; +} + +static const struct rt_ofw_node_id es8326_ofw_ids[] = +{ + { .compatible = "everest,es8326" }, + { /* sentinel */ } +}; + +static struct rt_i2c_driver es8326_driver = +{ + .ofw_ids = es8326_ofw_ids, + .probe = es8326_probe, + .remove = es8326_remove, +}; +RT_I2C_DRIVER_EXPORT(es8326_driver); diff --git a/bsp/spacemit/dm/audio/codec/es8326.h b/bsp/spacemit/dm/audio/codec/es8326.h new file mode 100644 index 000000000000..57c58221d1ab --- /dev/null +++ b/bsp/spacemit/dm/audio/codec/es8326.h @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#ifndef __SPACEMIT_ES8326_H__ +#define __SPACEMIT_ES8326_H__ + +#include + +#define ES8326_RESET 0x00 +#define ES8326_CLK_CTL 0x01 +#define ES8326_CLK_INV 0x02 +#define ES8326_CLK_RESAMPLE 0x03 +#define ES8326_CLK_DIV1 0x04 +#define ES8326_CLK_DIV2 0x05 +#define ES8326_CLK_DLL 0x06 +#define ES8326_CLK_MUX 0x07 +#define ES8326_CLK_ADC_SEL 0x08 +#define ES8326_CLK_DAC_SEL 0x09 +#define ES8326_CLK_ADC_OSR 0x0a +#define ES8326_CLK_DAC_OSR 0x0b +#define ES8326_CLK_DIV_CPC 0x0c +#define ES8326_CLK_DIV_BCLK 0x0d +#define ES8326_CLK_TRI 0x0e +#define ES8326_CLK_VMIDS1 0x10 +#define ES8326_CLK_VMIDS2 0x11 +#define ES8326_CLK_CAL_TIME 0x12 +#define ES8326_FMT 0x13 +#define ES8326_DAC_MUTE 0x14 +#define ES8326_ADC_MUTE 0x15 +#define ES8326_ANA_PDN 0x16 +#define ES8326_VMIDSEL 0x18 +#define ES8326_ANA_LP 0x19 +#define ES8326_ANA_MICBIAS 0x1b +#define ES8326_ANA_VSEL 0x1c +#define ES8326_VMIDLOW 0x22 +#define ES8326_PGAGAIN 0x23 +#define ES8326_HP_DRIVER 0x24 +#define ES8326_DAC2HPMIX 0x25 +#define ES8326_HP_VOL 0x26 +#define ES8326_HP_CAL 0x27 +#define ES8326_HP_DRIVER_REF 0x28 +#define ES8326_ADC1_SRC 0x2a +#define ES8326_ADC2_SRC 0x2b +#define ES8326_HP_OFFSET_CAL 0x4a +#define ES8326_HPL_OFFSET_INI 0x4b +#define ES8326_HPR_OFFSET_INI 0x4c +#define ES8326_DAC_DSM 0x4d +#define ES8326_DAC_RAMPRATE 0x4e +#define ES8326_DAC_VPPSCALE 0x4f +#define ES8326_DAC_VOL 0x50 +#define ES8326_DAC_CROSSTALK 0x55 +#define ES8326_HPJACK_TIMER 0x56 +#define ES8326_HPDET_TYPE 0x57 +#define ES8326_INT_SOURCE 0x58 +#define ES8326_INTOUT_IO 0x59 +#define ES8326_SDINOUT1_IO 0x5a +#define ES8326_SDINOUT23_IO 0x5b +#define ES8326_HP_MISC 0xf7 +#define ES8326_PULLUP_CTL 0xf9 +#define ES8326_HPDET_STA 0xfb +#define ES8326_CSM_MUTE_STA 0xfc +#define ES8326_CHIP_ID1 0xfd +#define ES8326_CHIP_ID2 0xfe +#define ES8326_CHIP_VERSION 0xff + +#define ES8326_CSM_ON RT_BIT(7) +#define ES8326_CLK_ON 0x7e +#define ES8326_S16_LE (3 << 2) +#define ES8326_DATA_LEN_MASK (7 << 2) +#define ES8326_MUTE_MASK (3 << 0) +#define ES8326_MUTE (3 << 0) +#define ES8326_MIC_SEL_MASK (3 << 4) +#define ES8326_MIC1_SEL RT_BIT(4) +#define ES8326_HP_OFF 0 +#define ES8326_HP_ON 0x77 +#define ES8326_HP_DET_SRC_PIN9 RT_BIT(4) +#define ES8326_HP_TYPE_AUTO RT_BIT(0) +#define ES8326_INT_SRC_PIN9 RT_BIT(3) +#define ES8326_IO_INPUT 0 +#define ES8326_IO_DMIC_CLK 9 +#define ES8326_SDINOUT1_SHIFT 4 +#define ES8326_HPINSERT_FLAG RT_BIT(1) +#define ES8326_VERSION_B 3 + +#define ES8326_ADC_AMIC 0x22 +#define ES8326_ADC_DMIC 0x44 + +#endif /* __SPACEMIT_ES8326_H__ */ diff --git a/bsp/spacemit/dm/audio/spacemit-audio.h b/bsp/spacemit/dm/audio/spacemit-audio.h new file mode 100644 index 000000000000..1367d40b2cd0 --- /dev/null +++ b/bsp/spacemit/dm/audio/spacemit-audio.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#ifndef __SPACEMIT_AUDIO_H__ +#define __SPACEMIT_AUDIO_H__ + +#include +#include +#include + +struct spacemit_i2s; +struct spacemit_hdmi_audio; +struct es8326_codec; + +struct spacemit_audio_config +{ + rt_uint32_t samplerate; + rt_uint16_t channels; + rt_uint16_t samplebits; + rt_uint32_t mclk_fs; +}; + +struct spacemit_pcm +{ + struct rt_device *dev; + struct rt_ofw_node *np; + struct rt_dma_chan *tx; + struct rt_dma_chan *rx; + + rt_bool_t is_hdmi; + void *hdmi_buffer; + rt_ubase_t hdmi_dma; + rt_size_t hdmi_size; + + rt_list_t list; +}; + +struct spacemit_pcm *spacemit_pcm_find(struct rt_ofw_node *np); + +struct spacemit_i2s *spacemit_i2s_find(struct rt_ofw_node *np); +rt_err_t spacemit_i2s_configure(struct spacemit_i2s *i2s, + const struct spacemit_audio_config *config); +rt_err_t spacemit_i2s_start(struct spacemit_i2s *i2s); +rt_err_t spacemit_i2s_stop(struct spacemit_i2s *i2s); +rt_ubase_t spacemit_i2s_fifo_phys(struct spacemit_i2s *i2s); + +struct spacemit_hdmi_audio *spacemit_hdmi_audio_find(struct rt_ofw_node *np); +rt_err_t spacemit_hdmi_audio_start(struct spacemit_hdmi_audio *hdmi); +rt_err_t spacemit_hdmi_audio_stop(struct spacemit_hdmi_audio *hdmi); +rt_ubase_t spacemit_hdmi_audio_fifo_phys(struct spacemit_hdmi_audio *hdmi); +rt_bool_t spacemit_hdmi_audio_connected(struct spacemit_hdmi_audio *hdmi); + +struct es8326_codec *es8326_codec_find(struct rt_ofw_node *np); +rt_err_t es8326_codec_hw_params(struct es8326_codec *codec, + const struct spacemit_audio_config *config); +rt_err_t es8326_codec_start(struct es8326_codec *codec, int stream); +rt_err_t es8326_codec_stop(struct es8326_codec *codec, int stream); +rt_err_t es8326_codec_set_volume(struct es8326_codec *codec, int volume); +rt_err_t es8326_codec_set_mute(struct es8326_codec *codec, rt_bool_t mute); + +#endif /* __SPACEMIT_AUDIO_H__ */ diff --git a/bsp/spacemit/dm/audio/spacemit-snd-card.c b/bsp/spacemit/dm/audio/spacemit-snd-card.c new file mode 100644 index 000000000000..9d3290c22f30 --- /dev/null +++ b/bsp/spacemit/dm/audio/spacemit-snd-card.c @@ -0,0 +1,1087 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#define DBG_TAG "audio.card.spacemit" +#define DBG_LVL DBG_INFO +#include + +#include "spacemit-audio.h" + +#define CARD_PREFIX "simple-audio-card," +#define CARD_DAI "sound-dai" + +#define ANALOG_BLOCK_SIZE 4096 +#define ANALOG_BLOCK_COUNT 4 +#define ANALOG_BUFFER_SIZE (ANALOG_BLOCK_SIZE * ANALOG_BLOCK_COUNT) +#define CAPTURE_PERIOD_SIZE 2048 +#define CAPTURE_PERIOD_COUNT 4 +#define CAPTURE_BUFFER_SIZE (CAPTURE_PERIOD_SIZE * CAPTURE_PERIOD_COUNT) + +#define HDMI_PCM_BLOCK_SIZE (480 * 4) +#define HDMI_PCM_BLOCK_COUNT 4 +#define HDMI_PCM_BUFFER_SIZE (HDMI_PCM_BLOCK_SIZE * HDMI_PCM_BLOCK_COUNT) +#define HDMI_RAW_BLOCK_SIZE (HDMI_PCM_BLOCK_SIZE * 2) +#define HDMI_RAW_BUFFER_SIZE (HDMI_RAW_BLOCK_SIZE * HDMI_PCM_BLOCK_COUNT) + +#define AUDIO_DMA_BURST 32 +#define AUDIO_TX_THREAD_STACK 4096 +#define AUDIO_TX_THREAD_PRIO 12 +#define HDMI_SAMPLE_PRESENT RT_BIT(31) +#define HDMI_FRAME_START RT_BIT(30) +#define HDMI_PARITY RT_BIT(27) +#define HDMI_CHANNEL_STATUS RT_BIT(26) +#define HDMI_VALID RT_BIT(24) + +struct spacemit_audio_card +{ + struct rt_audio_device audio; + struct spacemit_audio_config config; + struct rt_device *dev; + + struct spacemit_i2s *i2s; + struct spacemit_hdmi_audio *hdmi; + struct es8326_codec *codec; + struct spacemit_pcm *pcm; + + void *playback_buffer; + rt_ubase_t playback_dma; + rt_size_t playback_size; + rt_size_t playback_block_size; + + void *capture_buffer; + rt_ubase_t capture_dma; + rt_size_t capture_pos; + + rt_bool_t is_hdmi; + rt_bool_t replay_started; + rt_bool_t record_started; + rt_bool_t tx_running; + rt_bool_t rx_running; + rt_bool_t tx_silent; + rt_bool_t tx_drain; + rt_bool_t tx_drain_timer_inited; + rt_bool_t muted; + rt_uint8_t volume; + rt_uint8_t iec_offset; + rt_uint8_t tx_primed_periods; + rt_uint32_t tx_done_count; + rt_uint32_t tx_service_count; + rt_bool_t tx_sem_inited; + rt_bool_t tx_thread_exit; + struct rt_semaphore tx_sem; + rt_thread_t tx_thread; + struct rt_timer tx_drain_timer; + char name[32]; +}; + +static void spacemit_hdmi_reformat(struct spacemit_audio_card *card, + rt_uint32_t *destination, const rt_int16_t *source, rt_size_t frames); + +static struct rt_ofw_node *spacemit_audio_parse_dai(struct rt_ofw_node *card_np, + const char *link_name) +{ + struct rt_ofw_node *link_np, *args_np; + struct rt_ofw_cell_args args; + + link_np = rt_ofw_get_child_by_tag(card_np, link_name); + if (!link_np) + { + return RT_NULL; + } + + if (rt_ofw_parse_phandle_cells(link_np, CARD_DAI, + "#sound-dai-cells", 0, &args)) + { + rt_ofw_node_put(link_np); + return RT_NULL; + } + + args_np = args.data; + rt_ofw_node_get(args_np); + rt_ofw_node_put(link_np); + + return args_np; +} + +static rt_err_t spacemit_audio_validate_config( + const struct rt_audio_configure *config) +{ + return config->samplerate == 48000 && config->channels == 2 && + config->samplebits == 16 ? RT_EOK : -RT_EINVAL; +} + +static rt_err_t spacemit_audio_apply_config(struct spacemit_audio_card *card) +{ + rt_err_t err; + + if (card->is_hdmi) + { + return RT_EOK; + } + + if ((err = spacemit_i2s_configure(card->i2s, &card->config))) + { + return err; + } + + return es8326_codec_hw_params(card->codec, &card->config); +} + +static rt_err_t spacemit_audio_getcaps(struct rt_audio_device *audio, + struct rt_audio_caps *caps) +{ + struct spacemit_audio_card *card = audio->parent.user_data; + + switch (caps->main_type) + { + case AUDIO_TYPE_QUERY: + caps->udata.mask = AUDIO_TYPE_OUTPUT | AUDIO_TYPE_MIXER; + if (!card->is_hdmi) + { + caps->udata.mask |= AUDIO_TYPE_INPUT; + } + break; + + case AUDIO_TYPE_OUTPUT: + case AUDIO_TYPE_INPUT: + if (caps->main_type == AUDIO_TYPE_INPUT && card->is_hdmi) + { + return -RT_ENOSYS; + } + switch (caps->sub_type) + { + case AUDIO_DSP_PARAM: + caps->udata.config.samplerate = card->config.samplerate; + caps->udata.config.channels = card->config.channels; + caps->udata.config.samplebits = card->config.samplebits; + break; + case AUDIO_DSP_SAMPLERATE: + caps->udata.config.samplerate = card->config.samplerate; + caps->udata.mask = AUDIO_SAMP_RATE_48K; + break; + case AUDIO_DSP_CHANNELS: + caps->udata.config.channels = card->config.channels; + break; + case AUDIO_DSP_SAMPLEBITS: + caps->udata.config.samplebits = card->config.samplebits; + break; + default: + return -RT_ENOSYS; + } + break; + + case AUDIO_TYPE_MIXER: + switch (caps->sub_type) + { + case AUDIO_MIXER_QUERY: + caps->udata.mask = AUDIO_MIXER_VOLUME | AUDIO_MIXER_MUTE; + break; + case AUDIO_MIXER_VOLUME: + caps->udata.value = card->volume; + break; + case AUDIO_MIXER_MUTE: + caps->udata.value = card->muted; + break; + default: + return -RT_ENOSYS; + } + break; + + default: + return -RT_ENOSYS; + } + + return RT_EOK; +} + +static rt_err_t spacemit_audio_configure(struct rt_audio_device *audio, + struct rt_audio_caps *caps) +{ + rt_err_t err; + struct spacemit_audio_card *card = audio->parent.user_data; + + switch (caps->main_type) + { + case AUDIO_TYPE_OUTPUT: + case AUDIO_TYPE_INPUT: + if (caps->main_type == AUDIO_TYPE_INPUT && card->is_hdmi) + { + return -RT_ENOSYS; + } + if (caps->sub_type != AUDIO_DSP_PARAM) + { + return -RT_ENOSYS; + } + if ((err = spacemit_audio_validate_config(&caps->udata.config))) + { + LOG_W("%s supports 48000 Hz, stereo, 16-bit PCM only", card->name); + return err; + } + card->config.samplerate = caps->udata.config.samplerate; + card->config.channels = caps->udata.config.channels; + card->config.samplebits = caps->udata.config.samplebits; + return spacemit_audio_apply_config(card); + + case AUDIO_TYPE_MIXER: + if (caps->sub_type == AUDIO_MIXER_VOLUME) + { + int volume = caps->udata.value; + + if (volume < AUDIO_VOLUME_MIN) + { + volume = AUDIO_VOLUME_MIN; + } + if (volume > AUDIO_VOLUME_MAX) + { + volume = AUDIO_VOLUME_MAX; + } + card->volume = volume; + return card->codec ? es8326_codec_set_volume(card->codec, volume) : RT_EOK; + } + if (caps->sub_type == AUDIO_MIXER_MUTE) + { + card->muted = !!caps->udata.value; + return card->codec ? es8326_codec_set_mute(card->codec, card->muted) : RT_EOK; + } + return -RT_ENOSYS; + + default: + return -RT_ENOSYS; + } +} + +static rt_err_t spacemit_audio_dma_prepare_tx(struct spacemit_audio_card *card, + rt_ubase_t source, rt_size_t length, rt_size_t period) +{ + rt_err_t err; + struct rt_dma_slave_config config = { 0 }; + struct rt_dma_slave_transfer transfer = { 0 }; + + config.direction = RT_DMA_MEM_TO_DEV; + config.src_addr = source; + config.dst_addr = card->is_hdmi ? + spacemit_hdmi_audio_fifo_phys(card->hdmi) : + spacemit_i2s_fifo_phys(card->i2s); + config.src_addr_width = RT_DMA_SLAVE_BUSWIDTH_4_BYTES; + config.dst_addr_width = RT_DMA_SLAVE_BUSWIDTH_4_BYTES; + config.src_maxburst = AUDIO_DMA_BURST; + config.dst_maxburst = AUDIO_DMA_BURST; + + if (card->is_hdmi) + { + LOG_D("%s: TX DMA config begin: src=%08lx dst=%08lx len=%u period=%u", + card->name, (unsigned long)source, + (unsigned long)config.dst_addr, + (unsigned int)length, (unsigned int)period); + } + if ((err = rt_dma_chan_config(card->pcm->tx, &config))) + { + if (card->is_hdmi) + { + LOG_E("%s: TX DMA config failed: %s", card->name, + rt_strerror(err)); + } + return err; + } + if (card->is_hdmi) + { + LOG_D("%s: TX DMA config done", card->name); + } + + transfer.src_addr = source; + transfer.dst_addr = config.dst_addr; + transfer.buffer_len = length; + transfer.period_len = period; + + if (card->is_hdmi) + { + LOG_D("%s: TX DMA prep begin", card->name); + } + if ((err = rt_dma_prep_cyclic(card->pcm->tx, &transfer))) + { + if (card->is_hdmi) + { + LOG_E("%s: TX DMA prep failed: %s", card->name, + rt_strerror(err)); + } + return err; + } + if (card->is_hdmi) + { + LOG_D("%s: TX DMA prep done, start begin", card->name); + } + + err = rt_dma_chan_start(card->pcm->tx); + if (card->is_hdmi) + { + if (err) + { + LOG_E("%s: TX DMA start failed: %s", card->name, + rt_strerror(err)); + } + else + { + LOG_D("%s: TX DMA start done", card->name); + } + } + + return err; +} + +static void spacemit_audio_drain_timer(void *parameter) +{ + struct spacemit_audio_card *card = parameter; + + if (card->replay_started && card->tx_drain) + { + rt_audio_tx_complete(&card->audio); + } +} + +static void spacemit_audio_start_drain_tx(struct spacemit_audio_card *card) +{ + rt_tick_t tick; + + if (!card->tx_drain_timer_inited) + { + return; + } + + tick = rt_tick_from_millisecond(10); + if (!tick) + { + tick = 1; + } + + card->tx_running = RT_TRUE; + card->tx_silent = RT_FALSE; + card->tx_drain = RT_TRUE; + rt_timer_control(&card->tx_drain_timer, RT_TIMER_CTRL_SET_TIME, &tick); + rt_timer_start(&card->tx_drain_timer); +} + +static void spacemit_audio_stop_drain_tx(struct spacemit_audio_card *card) +{ + if (card->tx_drain_timer_inited) + { + rt_timer_stop(&card->tx_drain_timer); + } + card->tx_drain = RT_FALSE; +} + +static void spacemit_audio_hdmi_silence(struct spacemit_audio_card *card) +{ + rt_memset(card->pcm->hdmi_buffer, 0, HDMI_RAW_BUFFER_SIZE); + rt_hw_wmb(); +} + +static void spacemit_audio_tx_worker(void *parameter) +{ + struct spacemit_audio_card *card = parameter; + + while (!card->tx_thread_exit) + { + rt_sem_take(&card->tx_sem, RT_WAITING_FOREVER); + + if (card->tx_thread_exit) + { + break; + } + if (card->replay_started && !card->tx_silent) + { + card->tx_service_count++; + if (card->tx_service_count <= 4 || + !(card->tx_service_count % 100)) + { + LOG_D("%s: TX service #%u", card->name, + card->tx_service_count); + } + rt_audio_tx_complete(&card->audio); + } + } +} + +static rt_err_t spacemit_audio_ensure_tx_thread(struct spacemit_audio_card *card) +{ + if (card->tx_thread) + { + return RT_EOK; + } + + if (!card->tx_sem_inited) + { + return -RT_ERROR; + } + + card->tx_thread_exit = RT_FALSE; + card->tx_thread = rt_thread_create("audtx", + spacemit_audio_tx_worker, card, + AUDIO_TX_THREAD_STACK, AUDIO_TX_THREAD_PRIO, 10); + if (!card->tx_thread) + { + return -RT_ENOMEM; + } + + return rt_thread_startup(card->tx_thread); +} + +static rt_err_t spacemit_audio_start_silent_tx(struct spacemit_audio_card *card) +{ + rt_err_t err; + + rt_memset(card->playback_buffer, 0, card->playback_size); + if ((err = spacemit_audio_dma_prepare_tx(card, card->playback_dma, + card->playback_size, card->playback_block_size))) + { + return err; + } + + card->tx_running = RT_TRUE; + card->tx_silent = RT_TRUE; + return RT_EOK; +} + +static rt_err_t spacemit_audio_start_rx(struct spacemit_audio_card *card) +{ + rt_err_t err; + struct rt_dma_slave_config config = { 0 }; + struct rt_dma_slave_transfer transfer = { 0 }; + + config.direction = RT_DMA_DEV_TO_MEM; + config.src_addr = spacemit_i2s_fifo_phys(card->i2s); + config.dst_addr = card->capture_dma; + config.src_addr_width = RT_DMA_SLAVE_BUSWIDTH_4_BYTES; + config.dst_addr_width = RT_DMA_SLAVE_BUSWIDTH_4_BYTES; + config.src_maxburst = AUDIO_DMA_BURST; + config.dst_maxburst = AUDIO_DMA_BURST; + + if ((err = rt_dma_chan_config(card->pcm->rx, &config))) + { + return err; + } + + transfer.src_addr = config.src_addr; + transfer.dst_addr = card->capture_dma; + transfer.buffer_len = CAPTURE_BUFFER_SIZE; + transfer.period_len = CAPTURE_PERIOD_SIZE; + + if ((err = rt_dma_prep_cyclic(card->pcm->rx, &transfer))) + { + return err; + } + if ((err = rt_dma_chan_start(card->pcm->rx))) + { + return err; + } + + card->capture_pos = 0; + card->rx_running = RT_TRUE; + return RT_EOK; +} + +static rt_err_t spacemit_audio_init(struct rt_audio_device *audio) +{ + struct spacemit_audio_card *card = audio->parent.user_data; + + return spacemit_audio_apply_config(card); +} + +static rt_err_t spacemit_audio_start(struct rt_audio_device *audio, int stream) +{ + rt_err_t err; + rt_bool_t codec_started = RT_FALSE; + rt_bool_t silent_started = RT_FALSE; + rt_bool_t was_silent = RT_FALSE; + struct spacemit_audio_card *card = audio->parent.user_data; + + if (stream == AUDIO_STREAM_REPLAY) + { + if (card->replay_started) + { + return RT_EOK; + } + + if (card->tx_running && card->tx_silent) + { + was_silent = RT_TRUE; + rt_dma_chan_stop(card->pcm->tx); + card->tx_running = RT_FALSE; + card->tx_silent = RT_FALSE; + } + + if (card->is_hdmi) + { + if ((err = spacemit_hdmi_audio_start(card->hdmi))) + { + return err; + } + } + else + { + if ((err = es8326_codec_start(card->codec, stream))) + { + goto _restore_silent_tx; + } + codec_started = RT_TRUE; + if ((err = spacemit_i2s_start(card->i2s))) + { + es8326_codec_stop(card->codec, stream); + goto _restore_silent_tx; + } + } + + card->iec_offset = 0; + card->replay_started = RT_TRUE; + card->tx_drain = RT_FALSE; + card->tx_primed_periods = 0; + card->tx_done_count = 0; + card->tx_service_count = 0; + if (audio->replay) + { + audio->replay->read_index = 0; + } + if (card->is_hdmi) + { + spacemit_audio_hdmi_silence(card); + } + + /* Prime the first hardware period from a playback worker thread. */ + if ((err = spacemit_audio_ensure_tx_thread(card))) + { + card->replay_started = RT_FALSE; + goto _stop_playback; + } + if (card->is_hdmi) + { + for (int i = 0; i < HDMI_PCM_BLOCK_COUNT; ++i) + { + rt_sem_release(&card->tx_sem); + } + } + else + { + rt_sem_release(&card->tx_sem); + } + return RT_EOK; + } + + if (stream == AUDIO_STREAM_RECORD && !card->is_hdmi) + { + if (card->record_started) + { + return RT_EOK; + } + if (!card->tx_running && + (err = spacemit_audio_start_silent_tx(card))) + { + return err; + } + silent_started = !card->replay_started && card->tx_silent; + if ((err = spacemit_audio_start_rx(card))) + { + goto _stop_silent_tx; + } + if ((err = es8326_codec_start(card->codec, stream))) + { + goto _stop_rx; + } + codec_started = RT_TRUE; + if ((err = spacemit_i2s_start(card->i2s))) + { + goto _stop_codec; + } + card->record_started = RT_TRUE; + return RT_EOK; + } + + return -RT_EINVAL; + +_stop_playback: + if (card->is_hdmi) + { + spacemit_hdmi_audio_stop(card->hdmi); + } + else + { + if (codec_started) + { + es8326_codec_stop(card->codec, stream); + } + spacemit_i2s_stop(card->i2s); + } + return err; + +_stop_codec: + if (codec_started) + { + es8326_codec_stop(card->codec, stream); + } +_stop_rx: + if (card->rx_running) + { + rt_dma_chan_stop(card->pcm->rx); + card->rx_running = RT_FALSE; + } +_stop_silent_tx: + if (silent_started && card->tx_running) + { + rt_dma_chan_stop(card->pcm->tx); + card->tx_running = RT_FALSE; + card->tx_silent = RT_FALSE; + } + return err; + +_restore_silent_tx: + if (was_silent && spacemit_audio_start_silent_tx(card)) + { + LOG_E("%s: failed to restore capture clock DMA", card->name); + } + return err; +} + +static rt_err_t spacemit_audio_stop(struct rt_audio_device *audio, int stream) +{ + rt_err_t err = RT_EOK; + struct spacemit_audio_card *card = audio->parent.user_data; + + if (stream == AUDIO_STREAM_REPLAY && card->replay_started) + { + if (card->tx_drain) + { + spacemit_audio_stop_drain_tx(card); + } + + if (card->tx_running) + { + rt_dma_chan_stop(card->pcm->tx); + card->tx_running = RT_FALSE; + } + card->tx_silent = RT_FALSE; + card->tx_primed_periods = 0; + if (audio->replay) + { + audio->replay->read_index = 0; + } + card->replay_started = RT_FALSE; + + if (card->is_hdmi) + { + err = spacemit_hdmi_audio_stop(card->hdmi); + } + else + { + es8326_codec_stop(card->codec, stream); + spacemit_i2s_stop(card->i2s); + if (card->record_started) + { + err = spacemit_audio_start_silent_tx(card); + } + } + return err; + } + + if (stream == AUDIO_STREAM_RECORD && card->record_started) + { + if (card->rx_running) + { + rt_dma_chan_stop(card->pcm->rx); + card->rx_running = RT_FALSE; + } + if (!card->replay_started && card->tx_running) + { + rt_dma_chan_stop(card->pcm->tx); + card->tx_running = RT_FALSE; + card->tx_silent = RT_FALSE; + } + card->record_started = RT_FALSE; + es8326_codec_stop(card->codec, stream); + return spacemit_i2s_stop(card->i2s); + } + + return RT_EOK; +} + +static rt_uint32_t spacemit_hdmi_parity(rt_uint32_t sample) +{ + sample ^= sample >> 16; + sample ^= sample >> 8; + sample ^= sample >> 4; + sample &= 0xf; + return (0x6996 >> sample) & 1; +} + +static void spacemit_hdmi_reformat(struct spacemit_audio_card *card, + rt_uint32_t *destination, const rt_int16_t *source, rt_size_t frames) +{ + while (frames--) + { + for (int channel = 0; channel < 2; ++channel) + { + rt_uint32_t sample = (rt_uint16_t)*source++ << 8; + + sample |= HDMI_SAMPLE_PRESENT | HDMI_VALID; + if (!card->iec_offset) + { + sample |= HDMI_FRAME_START; + } + if (card->iec_offset == 25 || card->iec_offset == 32) + { + sample |= HDMI_CHANNEL_STATUS; + } + sample |= spacemit_hdmi_parity(sample) << 27; + *destination++ = sample; + } + + if (++card->iec_offset == 192) + { + card->iec_offset = 0; + } + } +} + +static rt_ssize_t spacemit_audio_transmit(struct rt_audio_device *audio, + const void *write_buf, void *read_buf, rt_size_t size) +{ + rt_err_t err; + rt_ubase_t offset; + struct spacemit_audio_card *card = audio->parent.user_data; + + RT_UNUSED(read_buf); + + if (!card->replay_started || size != card->playback_block_size) + { + return 0; + } + + offset = (const rt_uint8_t *)write_buf - + (const rt_uint8_t *)card->playback_buffer; + if (offset >= card->playback_size) + { + return -RT_EINVAL; + } + + if (card->is_hdmi) + { + spacemit_hdmi_reformat(card, + (rt_uint32_t *)((rt_uint8_t *)card->pcm->hdmi_buffer + offset * 2), + write_buf, size / 4); + rt_hw_wmb(); + } + + if (!card->tx_running) + { + rt_ubase_t dma = card->is_hdmi ? card->pcm->hdmi_dma : card->playback_dma; + rt_size_t length = card->is_hdmi ? HDMI_RAW_BUFFER_SIZE : card->playback_size; + rt_size_t period = card->is_hdmi ? HDMI_RAW_BLOCK_SIZE : card->playback_block_size; + + if (card->is_hdmi && ++card->tx_primed_periods < HDMI_PCM_BLOCK_COUNT) + { + return size; + } + + card->tx_done_count = 0; + card->tx_running = RT_TRUE; + card->tx_silent = RT_FALSE; + if ((err = spacemit_audio_dma_prepare_tx(card, dma, length, period))) + { + card->tx_running = RT_FALSE; + card->tx_primed_periods = 0; + LOG_E("%s: TX DMA start failed: %s", card->name, rt_strerror(err)); + LOG_D("%s: drain playback queue without hardware DMA", card->name); + spacemit_audio_start_drain_tx(card); + return size; + } + } + + return size; +} + +static void spacemit_audio_buffer_info(struct rt_audio_device *audio, + struct rt_audio_buf_info *info) +{ + struct spacemit_audio_card *card = audio->parent.user_data; + + info->buffer = card->playback_buffer; + info->block_size = card->playback_block_size; + info->block_count = card->is_hdmi ? HDMI_PCM_BLOCK_COUNT : ANALOG_BLOCK_COUNT; + info->total_size = card->playback_size; +} + +static const struct rt_audio_ops spacemit_audio_ops = +{ + .getcaps = spacemit_audio_getcaps, + .configure = spacemit_audio_configure, + .init = spacemit_audio_init, + .start = spacemit_audio_start, + .stop = spacemit_audio_stop, + .transmit = spacemit_audio_transmit, + .buffer_info = spacemit_audio_buffer_info, +}; + +static void spacemit_audio_tx_done(struct rt_dma_chan *channel, rt_size_t size) +{ + struct spacemit_audio_card *card = channel->priv; + + RT_UNUSED(size); + + if (card->replay_started && !card->tx_silent) + { + card->tx_done_count++; + if (card->tx_done_count <= 4 || !(card->tx_done_count % 100)) + { + LOG_D("%s: TX period done #%u", card->name, card->tx_done_count); + } + if (card->tx_sem_inited) + { + rt_sem_release(&card->tx_sem); + } + } +} + +static void spacemit_audio_rx_done(struct rt_dma_chan *channel, rt_size_t size) +{ + struct spacemit_audio_card *card = channel->priv; + + RT_UNUSED(size); + + if (card->record_started) + { + rt_audio_rx_done(&card->audio, + (rt_uint8_t *)card->capture_buffer + card->capture_pos, + CAPTURE_PERIOD_SIZE); + card->capture_pos += CAPTURE_PERIOD_SIZE; + card->capture_pos %= CAPTURE_BUFFER_SIZE; + } +} + +static void spacemit_audio_card_free(struct spacemit_audio_card *card) +{ + if (!card) + { + return; + } + + if (card->capture_buffer) + { + rt_dma_free_coherent(card->dev, CAPTURE_BUFFER_SIZE, + card->capture_buffer, card->capture_dma); + } + if (card->tx_drain_timer_inited) + { + rt_timer_stop(&card->tx_drain_timer); + rt_timer_detach(&card->tx_drain_timer); + } + if (card->tx_thread) + { + card->tx_thread_exit = RT_TRUE; + rt_sem_release(&card->tx_sem); + rt_thread_delete(card->tx_thread); + } + if (card->tx_sem_inited) + { + rt_sem_detach(&card->tx_sem); + } + if (card->playback_buffer) + { + rt_dma_free_coherent(card->dev, card->playback_size, + card->playback_buffer, card->playback_dma); + } + rt_free(card); +} + +static rt_err_t spacemit_audio_card_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + rt_uint32_t mclk_fs = 64; + rt_uint32_t flags; + const char *name = "spacemit-audio"; + struct rt_device *dev = &pdev->parent; + struct rt_ofw_node *cpu_np = RT_NULL, *plat_np = RT_NULL, *codec_np = RT_NULL; + struct spacemit_audio_card *card = rt_calloc(1, sizeof(*card)); + + if (!card) + { + return -RT_ENOMEM; + } + + card->dev = dev; + card->volume = 70; + card->config.samplerate = 48000; + card->config.channels = 2; + card->config.samplebits = 16; + rt_ofw_prop_read_string(dev->ofw_node, CARD_PREFIX "name", &name); + rt_strncpy(card->name, name, sizeof(card->name) - 1); + if (rt_ofw_prop_read_u32(dev->ofw_node, "spacemit,mclk-fs", &mclk_fs)) + { + rt_ofw_prop_read_u32(dev->ofw_node, CARD_PREFIX "mclk-fs", &mclk_fs); + } + card->config.mclk_fs = mclk_fs; + + cpu_np = spacemit_audio_parse_dai(dev->ofw_node, CARD_PREFIX "cpu"); + plat_np = spacemit_audio_parse_dai(dev->ofw_node, CARD_PREFIX "plat"); + codec_np = spacemit_audio_parse_dai(dev->ofw_node, CARD_PREFIX "codec"); + if (!cpu_np || !plat_np) + { + err = -RT_EINVAL; + LOG_E("%s: missing CPU or platform DAI", card->name); + goto _fail; + } + + card->pcm = spacemit_pcm_find(plat_np); + card->is_hdmi = rt_ofw_node_is_compatible(cpu_np, + "spacemit,spacemit-snd-sspa"); + if (!card->pcm) + { + err = -RT_ENOSYS; + LOG_E("%s: DMA platform is not ready", card->name); + goto _fail; + } + + if (card->is_hdmi) + { + card->hdmi = spacemit_hdmi_audio_find(cpu_np); + if (!card->hdmi || !card->pcm->is_hdmi || + card->pcm->hdmi_size < HDMI_RAW_BUFFER_SIZE) + { + err = -RT_ENOSYS; + LOG_E("%s: HDMI audio resources are not ready", card->name); + goto _fail; + } + card->playback_size = HDMI_PCM_BUFFER_SIZE; + card->playback_block_size = HDMI_PCM_BLOCK_SIZE; + flags = RT_DEVICE_FLAG_WRONLY; + } + else + { + card->i2s = spacemit_i2s_find(cpu_np); + card->codec = es8326_codec_find(codec_np); + if (!card->i2s || !card->codec || card->pcm->is_hdmi || !card->pcm->rx) + { + err = -RT_ENOSYS; + LOG_E("%s: I2S or ES8326 is not ready", card->name); + goto _fail; + } + card->playback_size = ANALOG_BUFFER_SIZE; + card->playback_block_size = ANALOG_BLOCK_SIZE; + flags = RT_DEVICE_FLAG_RDWR; + } + + card->playback_buffer = rt_dma_alloc_coherent(dev, card->playback_size, + &card->playback_dma); + if (!card->playback_buffer) + { + err = -RT_ENOMEM; + goto _fail; + } + rt_memset(card->playback_buffer, 0, card->playback_size); + + if (!card->is_hdmi) + { + card->capture_buffer = rt_dma_alloc_coherent(dev, CAPTURE_BUFFER_SIZE, + &card->capture_dma); + if (!card->capture_buffer) + { + err = -RT_ENOMEM; + goto _fail; + } + rt_memset(card->capture_buffer, 0, CAPTURE_BUFFER_SIZE); + } + + card->audio.ops = (struct rt_audio_ops *)&spacemit_audio_ops; + card->audio.parent.user_data = card; + rt_timer_init(&card->tx_drain_timer, "auddrn", + spacemit_audio_drain_timer, card, + rt_tick_from_millisecond(10), + RT_TIMER_FLAG_PERIODIC | RT_TIMER_FLAG_SOFT_TIMER); + card->tx_drain_timer_inited = RT_TRUE; + rt_sem_init(&card->tx_sem, "audtx", 0, RT_IPC_FLAG_PRIO); + card->tx_sem_inited = RT_TRUE; + + if ((err = rt_audio_register(&card->audio, card->name, flags, card))) + { + if (rt_device_find(card->name) == &card->audio.parent) + { + rt_device_unregister(&card->audio.parent); + } + goto _fail; + } + card->pcm->tx->callback = spacemit_audio_tx_done; + card->pcm->tx->priv = card; + if (card->pcm->rx) + { + card->pcm->rx->callback = spacemit_audio_rx_done; + card->pcm->rx->priv = card; + } + + dev->user_data = card; + rt_dm_dev_bind_fwdata(dev, RT_NULL, card); + rt_ofw_node_put(cpu_np); + rt_ofw_node_put(plat_np); + rt_ofw_node_put(codec_np); + + LOG_I("%s: 48 kHz stereo 16-bit %s audio ready", card->name, + card->is_hdmi ? "HDMI" : "ES8326"); + return RT_EOK; + +_fail: + rt_ofw_node_put(cpu_np); + rt_ofw_node_put(plat_np); + rt_ofw_node_put(codec_np); + spacemit_audio_card_free(card); + return err; +} + +static rt_err_t spacemit_audio_card_remove(struct rt_platform_device *pdev) +{ + struct spacemit_audio_card *card = pdev->parent.user_data; + + if (!card) + { + return RT_EOK; + } + if (card->replay_started || card->record_started) + { + return -RT_EBUSY; + } + + rt_device_unregister(&card->audio.parent); + rt_dm_dev_unbind_fwdata(&pdev->parent, RT_NULL); + card->pcm->tx->callback = RT_NULL; + card->pcm->tx->priv = RT_NULL; + if (card->pcm->rx) + { + card->pcm->rx->callback = RT_NULL; + card->pcm->rx->priv = RT_NULL; + } + spacemit_audio_card_free(card); + + return RT_EOK; +} + +static const struct rt_ofw_node_id spacemit_audio_card_ofw_ids[] = +{ + { .compatible = "spacemit,simple-audio-card" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver spacemit_audio_card_driver = +{ + .name = "spacemit-audio-card", + .ids = spacemit_audio_card_ofw_ids, + .probe = spacemit_audio_card_probe, + .remove = spacemit_audio_card_remove, +}; + +static int spacemit_audio_card_register(void) +{ + rt_platform_driver_register(&spacemit_audio_card_driver); + return 0; +} +INIT_COMPONENT_EXPORT(spacemit_audio_card_register); diff --git a/bsp/spacemit/dm/audio/spacemit-snd-i2s.c b/bsp/spacemit/dm/audio/spacemit-snd-i2s.c new file mode 100644 index 000000000000..1ed6b59bc7fc --- /dev/null +++ b/bsp/spacemit/dm/audio/spacemit-snd-i2s.c @@ -0,0 +1,376 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#define DBG_TAG "i2s.spacemit" +#define DBG_LVL DBG_INFO +#include + +#include "spacemit-audio.h" +#include "spacemit-snd-i2s.h" + +#define K1_APBC_BASE 0xd4015000UL +#define K1_APBC_SIZE 0x100 +#define K1_APBC_SSPA0 0x80 +#define K1_APBC_SSPA1 0x84 +#define K1_APBC_SSPA_AUDIO_MODE RT_BIT(3) + +#define K1_MPMU_BASE 0xd4050000UL +#define K1_MPMU_SIZE 0x100 +#define K1_MPMU_SYSCLK_PRE_CTRL 0x08 +#define K1_MPMU_ISCCR1 0x44 +#define K1_MPMU_SYSCLK_BASE_156M RT_BIT(30) +#define K1_MPMU_I2S_BCLK_ENABLE RT_BIT(29) + +struct spacemit_i2s +{ + struct rt_device *dev; + struct rt_ofw_node *np; + + void *regs; + void *apbc; + void *mpmu; + rt_ubase_t phys; + + struct rt_clk *clk; + struct rt_reset_control *reset; + struct spacemit_audio_config config; + + int port; + int users; + rt_list_t list; +}; + +static rt_list_t i2s_nodes = RT_LIST_OBJECT_INIT(i2s_nodes); +static RT_DEFINE_SPINLOCK(i2s_nodes_lock); + +static rt_uint32_t i2s_read(struct spacemit_i2s *i2s, rt_ubase_t reg) +{ + return HWREG32((char *)i2s->regs + reg); +} + +static void i2s_write(struct spacemit_i2s *i2s, rt_ubase_t reg, rt_uint32_t value) +{ + HWREG32((char *)i2s->regs + reg) = value; +} + +struct spacemit_i2s *spacemit_i2s_find(struct rt_ofw_node *np) +{ + struct spacemit_i2s *i2s; + + rt_spin_lock(&i2s_nodes_lock); + rt_list_for_each_entry(i2s, &i2s_nodes, list) + { + if (i2s->np == np) + { + rt_spin_unlock(&i2s_nodes_lock); + return i2s; + } + } + rt_spin_unlock(&i2s_nodes_lock); + + return RT_NULL; +} + +static rt_err_t spacemit_i2s_set_clock(struct spacemit_i2s *i2s, + const struct spacemit_audio_config *config) +{ + rt_uint32_t divider, mclk_fs, ratio, target, value; + rt_uint64_t bclk, mclk; + + bclk = (rt_uint64_t)config->samplerate * config->channels * config->samplebits; + mclk_fs = config->mclk_fs ? config->mclk_fs : 64; + mclk = (rt_uint64_t)config->samplerate * mclk_fs; + + if (!bclk || mclk > 0xffffffffU || mclk % bclk) + { + return -RT_EINVAL; + } + + switch (mclk_fs) + { + case 64: + divider = 326; + break; + case 128: + divider = 652; + break; + case 256: + divider = 1304; + break; + default: + return -RT_EINVAL; + } + + ratio = (rt_uint32_t)(mclk / bclk); + switch (ratio) + { + case 2: + ratio = 0; + break; + case 4: + ratio = 1; + break; + case 6: + ratio = 2; + break; + case 8: + ratio = 3; + break; + default: + return -RT_EINVAL; + } + + target = K1_MPMU_SYSCLK_BASE_156M | (ratio << 27) | + (divider << 15) | 32600; + value = HWREG32((char *)i2s->mpmu + K1_MPMU_ISCCR1); + value &= ~0x5fffffffU; + HWREG32((char *)i2s->mpmu + K1_MPMU_ISCCR1) = value | target; + + value = HWREG32((char *)i2s->mpmu + K1_MPMU_SYSCLK_PRE_CTRL); + HWREG32((char *)i2s->mpmu + K1_MPMU_SYSCLK_PRE_CTRL) = + value | K1_MPMU_I2S_BCLK_ENABLE; + + if (!rt_is_err_or_null(i2s->clk)) + { + rt_clk_set_rate(i2s->clk, (rt_uint32_t)bclk); + } + + return RT_EOK; +} + +rt_err_t spacemit_i2s_configure(struct spacemit_i2s *i2s, + const struct spacemit_audio_config *config) +{ + rt_uint32_t fifo, psp, top; + rt_err_t err; + + if (!i2s || !config || config->samplerate != 48000 || + config->channels != 2 || config->samplebits != 16) + { + return -RT_EINVAL; + } + + if (i2s->users) + { + return rt_memcmp(&i2s->config, config, sizeof(*config)) ? + -RT_EBUSY : RT_EOK; + } + + if ((err = spacemit_i2s_set_clock(i2s, config))) + { + return err; + } + + top = SSPA_TOP_TRAIL_DMA | SSPA_TOP_DATA_WIDTH_32 | SSPA_TOP_FRAME_PSP; + fifo = SSPA_FIFO_RX_DMA_REQ | SSPA_FIFO_TX_DMA_REQ | + SSPA_FIFO_RX_THRESHOLD(15) | SSPA_FIFO_TX_THRESHOLD(15); + psp = SSPA_PSP_FRAME_WIDTH(16) | SSPA_PSP_FRAME_SYNC_RELATIVE | + SSPA_PSP_FRAME_POLARITY; + + i2s_write(i2s, SSPA_TOP_CTRL, top); + i2s_write(i2s, SSPA_FIFO_CTRL, fifo); + i2s_write(i2s, SSPA_INT_EN, 0); + i2s_write(i2s, SSPA_TIMEOUT, 0); + i2s_write(i2s, SSPA_PSP_CTRL, psp); + i2s_write(i2s, SSPA_NETWORK_CTRL, 0); + + i2s->config = *config; + + return RT_EOK; +} + +rt_err_t spacemit_i2s_start(struct spacemit_i2s *i2s) +{ + rt_uint32_t value; + + if (!i2s) + { + return -RT_EINVAL; + } + + if (!i2s->users++) + { + value = i2s_read(i2s, SSPA_TOP_CTRL); + i2s_write(i2s, SSPA_TOP_CTRL, value | SSPA_TOP_ENABLE); + } + + return RT_EOK; +} + +rt_err_t spacemit_i2s_stop(struct spacemit_i2s *i2s) +{ + rt_uint32_t value; + + if (!i2s) + { + return -RT_EINVAL; + } + + if (i2s->users > 0 && !--i2s->users) + { + value = i2s_read(i2s, SSPA_TOP_CTRL); + i2s_write(i2s, SSPA_TOP_CTRL, value & ~SSPA_TOP_ENABLE); + } + + return RT_EOK; +} + +rt_ubase_t spacemit_i2s_fifo_phys(struct spacemit_i2s *i2s) +{ + return i2s ? i2s->phys + SSPA_DATA : 0; +} + +static void spacemit_i2s_free(struct spacemit_i2s *i2s) +{ + if (!i2s) + { + return; + } + + if (!rt_is_err_or_null(i2s->reset)) + { + rt_reset_control_assert(i2s->reset); + rt_reset_control_put(i2s->reset); + } + if (!rt_is_err_or_null(i2s->clk)) + { + rt_clk_disable_unprepare(i2s->clk); + rt_clk_put(i2s->clk); + } + if (i2s->regs) + { + rt_iounmap(i2s->regs); + } + if (i2s->apbc) + { + rt_iounmap(i2s->apbc); + } + if (i2s->mpmu) + { + rt_iounmap(i2s->mpmu); + } + + rt_free(i2s); +} + +static rt_err_t spacemit_i2s_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + rt_uint64_t phys; + rt_uint32_t apbc_offset, value; + struct rt_device *dev = &pdev->parent; + struct spacemit_i2s *i2s = rt_calloc(1, sizeof(*i2s)); + + if (!i2s) + { + return -RT_ENOMEM; + } + + i2s->dev = dev; + i2s->np = dev->ofw_node; + i2s->regs = rt_dm_dev_iomap(dev, 0); + if (!i2s->regs || rt_dm_dev_get_address(dev, 0, &phys, RT_NULL)) + { + err = -RT_EIO; + goto _fail; + } + i2s->phys = (rt_ubase_t)phys; + i2s->port = phys == 0xd4026000UL ? 0 : 1; + + i2s->apbc = rt_ioremap((void *)K1_APBC_BASE, K1_APBC_SIZE); + i2s->mpmu = rt_ioremap((void *)K1_MPMU_BASE, K1_MPMU_SIZE); + if (!i2s->apbc || !i2s->mpmu) + { + err = -RT_EIO; + goto _fail; + } + + i2s->clk = rt_clk_get_by_name(dev, "sspa-clk"); + if (rt_is_err(i2s->clk)) + { + err = rt_ptr_err(i2s->clk); + goto _fail; + } + if ((err = rt_clk_prepare_enable(i2s->clk))) + { + goto _fail; + } + + i2s->reset = rt_reset_control_get_by_name(dev, "sspa-rst"); + if (rt_is_err(i2s->reset)) + { + err = rt_ptr_err(i2s->reset); + goto _fail; + } + if ((err = rt_reset_control_deassert(i2s->reset))) + { + goto _fail; + } + + apbc_offset = i2s->port ? K1_APBC_SSPA1 : K1_APBC_SSPA0; + value = HWREG32((char *)i2s->apbc + apbc_offset); + HWREG32((char *)i2s->apbc + apbc_offset) = value | K1_APBC_SSPA_AUDIO_MODE; + + rt_spin_lock(&i2s_nodes_lock); + rt_list_insert_before(&i2s_nodes, &i2s->list); + rt_spin_unlock(&i2s_nodes_lock); + + dev->user_data = i2s; + rt_dm_dev_bind_fwdata(dev, RT_NULL, i2s); + + LOG_D("%s: I2S%d controller ready", rt_dm_dev_get_name(dev), i2s->port); + + return RT_EOK; + +_fail: + spacemit_i2s_free(i2s); + return err; +} + +static rt_err_t spacemit_i2s_remove(struct rt_platform_device *pdev) +{ + struct spacemit_i2s *i2s = pdev->parent.user_data; + + if (!i2s) + { + return RT_EOK; + } + + rt_spin_lock(&i2s_nodes_lock); + rt_list_remove(&i2s->list); + rt_spin_unlock(&i2s_nodes_lock); + + rt_dm_dev_unbind_fwdata(&pdev->parent, RT_NULL); + spacemit_i2s_free(i2s); + + return RT_EOK; +} + +static const struct rt_ofw_node_id spacemit_i2s_ofw_ids[] = +{ + { .compatible = "spacemit,spacemit-i2s0" }, + { .compatible = "spacemit,spacemit-i2s1" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver spacemit_i2s_driver = +{ + .name = "spacemit-i2s", + .ids = spacemit_i2s_ofw_ids, + .probe = spacemit_i2s_probe, + .remove = spacemit_i2s_remove, +}; + +static int spacemit_i2s_register(void) +{ + rt_platform_driver_register(&spacemit_i2s_driver); + return 0; +} +INIT_DEVICE_EXPORT(spacemit_i2s_register); diff --git a/bsp/spacemit/dm/audio/spacemit-snd-i2s.h b/bsp/spacemit/dm/audio/spacemit-snd-i2s.h new file mode 100644 index 000000000000..c428b4f2c62e --- /dev/null +++ b/bsp/spacemit/dm/audio/spacemit-snd-i2s.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#ifndef __SPACEMIT_SND_I2S_H__ +#define __SPACEMIT_SND_I2S_H__ + +#include + +#define SSPA_TOP_CTRL 0x00 +#define SSPA_FIFO_CTRL 0x04 +#define SSPA_INT_EN 0x08 +#define SSPA_TIMEOUT 0x0c +#define SSPA_DATA 0x10 +#define SSPA_STATUS 0x14 +#define SSPA_PSP_CTRL 0x18 +#define SSPA_NETWORK_CTRL 0x1c + +#define SSPA_TOP_TRAIL_DMA RT_BIT(13) +#define SSPA_TOP_DATA_WIDTH_MASK (0x1fU << 5) +#define SSPA_TOP_DATA_WIDTH_32 (0x1fU << 5) +#define SSPA_TOP_FRAME_PSP (0x3U << 1) +#define SSPA_TOP_ENABLE RT_BIT(0) + +#define SSPA_FIFO_RX_DMA_REQ RT_BIT(11) +#define SSPA_FIFO_TX_DMA_REQ RT_BIT(10) +#define SSPA_FIFO_RX_THRESHOLD(v) ((v) << 5) +#define SSPA_FIFO_TX_THRESHOLD(v) (v) + +#define SSPA_PSP_FRAME_WIDTH(v) ((v) << 12) +#define SSPA_PSP_FRAME_POLARITY RT_BIT(4) +#define SSPA_PSP_FRAME_SYNC_RELATIVE RT_BIT(3) + +#endif /* __SPACEMIT_SND_I2S_H__ */ diff --git a/bsp/spacemit/dm/audio/spacemit-snd-pcm-dma.c b/bsp/spacemit/dm/audio/spacemit-snd-pcm-dma.c new file mode 100644 index 000000000000..b90f6341985c --- /dev/null +++ b/bsp/spacemit/dm/audio/spacemit-snd-pcm-dma.c @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#define DBG_TAG "audio.pcm.spacemit" +#define DBG_LVL DBG_INFO +#include + +#include "spacemit-audio.h" + +static rt_list_t pcm_nodes = RT_LIST_OBJECT_INIT(pcm_nodes); +static RT_DEFINE_SPINLOCK(pcm_nodes_lock); + +struct spacemit_pcm *spacemit_pcm_find(struct rt_ofw_node *np) +{ + struct spacemit_pcm *pcm; + + rt_spin_lock(&pcm_nodes_lock); + rt_list_for_each_entry(pcm, &pcm_nodes, list) + { + if (pcm->np == np) + { + rt_spin_unlock(&pcm_nodes_lock); + return pcm; + } + } + rt_spin_unlock(&pcm_nodes_lock); + + return RT_NULL; +} + +static void spacemit_pcm_free(struct spacemit_pcm *pcm) +{ + if (!pcm) + { + return; + } + + if (!rt_is_err_or_null(pcm->rx)) + { + rt_dma_chan_release(pcm->rx); + } + if (!rt_is_err_or_null(pcm->tx)) + { + rt_dma_chan_release(pcm->tx); + } + if (pcm->hdmi_buffer) + { + rt_iounmap(pcm->hdmi_buffer); + } + + rt_free(pcm); +} + +static rt_err_t spacemit_pcm_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + rt_uint64_t address, size; + struct rt_device *dev = &pdev->parent; + struct spacemit_pcm *pcm = rt_calloc(1, sizeof(*pcm)); + + if (!pcm) + { + return -RT_ENOMEM; + } + + pcm->dev = dev; + pcm->np = dev->ofw_node; + pcm->is_hdmi = rt_ofw_node_is_compatible(dev->ofw_node, + "spacemit,spacemit-snd-dma-hdmi"); + + if (pcm->is_hdmi) + { + pcm->hdmi_buffer = rt_dm_dev_iomap(dev, 0); + if (!pcm->hdmi_buffer || + rt_dm_dev_get_address(dev, 0, &address, &size)) + { + err = -RT_EIO; + goto _fail; + } + + pcm->hdmi_dma = (rt_ubase_t)address; + pcm->hdmi_size = (rt_size_t)size; + rt_memset(pcm->hdmi_buffer, 0, pcm->hdmi_size); + rt_hw_wmb(); + } + + pcm->tx = rt_dma_chan_request(dev, "tx"); + if (rt_is_err_or_null(pcm->tx)) + { + err = pcm->tx ? rt_ptr_err(pcm->tx) : -RT_ENOSYS; + goto _fail; + } + + if (!pcm->is_hdmi) + { + pcm->rx = rt_dma_chan_request(dev, "rx"); + if (rt_is_err_or_null(pcm->rx)) + { + err = pcm->rx ? rt_ptr_err(pcm->rx) : -RT_ENOSYS; + goto _fail; + } + } + + rt_spin_lock(&pcm_nodes_lock); + rt_list_insert_before(&pcm_nodes, &pcm->list); + rt_spin_unlock(&pcm_nodes_lock); + + dev->user_data = pcm; + rt_dm_dev_bind_fwdata(dev, RT_NULL, pcm); + + LOG_D("%s: %s DMA path ready", rt_dm_dev_get_name(dev), + pcm->is_hdmi ? "HDMI" : "I2S"); + + return RT_EOK; + +_fail: + spacemit_pcm_free(pcm); + return err; +} + +static rt_err_t spacemit_pcm_remove(struct rt_platform_device *pdev) +{ + struct spacemit_pcm *pcm = pdev->parent.user_data; + + if (!pcm) + { + return RT_EOK; + } + + rt_spin_lock(&pcm_nodes_lock); + rt_list_remove(&pcm->list); + rt_spin_unlock(&pcm_nodes_lock); + + rt_dm_dev_unbind_fwdata(&pdev->parent, RT_NULL); + spacemit_pcm_free(pcm); + + return RT_EOK; +} + +static const struct rt_ofw_node_id spacemit_pcm_ofw_ids[] = +{ + { .compatible = "spacemit,spacemit-snd-dma0" }, + { .compatible = "spacemit,spacemit-snd-dma1" }, + { .compatible = "spacemit,spacemit-snd-dma-hdmi" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver spacemit_pcm_driver = +{ + .name = "spacemit-audio-pcm", + .ids = spacemit_pcm_ofw_ids, + .probe = spacemit_pcm_probe, + .remove = spacemit_pcm_remove, +}; + +static int spacemit_pcm_register(void) +{ + rt_platform_driver_register(&spacemit_pcm_driver); + return 0; +} +INIT_DEVICE_EXPORT(spacemit_pcm_register); diff --git a/bsp/spacemit/dm/audio/spacemit-snd-sspa.c b/bsp/spacemit/dm/audio/spacemit-snd-sspa.c new file mode 100644 index 000000000000..f4a97ebb3199 --- /dev/null +++ b/bsp/spacemit/dm/audio/spacemit-snd-sspa.c @@ -0,0 +1,969 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#define DBG_TAG "audio.hdmi.spacemit" +#define DBG_LVL DBG_INFO +#include + +#include + +#include "spacemit-audio.h" +#include "spacemit-snd-sspa.h" + +#define K1_ADMA_HDMI_BYTES_PER_SECOND \ + (HDMI_SSPA_SAMPLE_RATE * 2U * sizeof(rt_uint32_t)) +#define K1_ADMA_RPMSG_LOCAL_ADDR 1024 +#define K1_ADMA_RPMSG_BOOT_TIMEOUT_MS 3000 +#define K1_ADMA_RPMSG_SEND_TIMEOUT_MS 1000 +#define K1_ADMA_RPMSG_STARTUP_MSG "startup" +#define K1_ADMA_RPMSG_STARTUP_OK_MSG "startup-ok" +struct spacemit_hdmi_audio +{ + struct rt_device *dev; + struct rt_ofw_node *np; + + void *regs; + void *clock_regs; + void *hdmi_regs; + rt_ubase_t phys; + + struct rt_clk *audio_clk; + struct rt_clk *hdmi_clk; + struct rt_reset_control *reset; + + int users; + rt_bool_t warned_unplugged; + rt_list_t list; +}; + +struct spacemit_adma +{ + struct rt_dma_controller parent; + struct rt_dma_chan channel; + struct rt_device *dev; + + void *regs; + void *control; + void *descriptors; + rt_ubase_t descriptors_dma; + + rt_ubase_t buffer_dma; + rt_size_t period_len; + rt_size_t period_count; + rt_size_t period_index; + rt_tick_t period_tick; + rt_uint32_t period_done_count; + rt_bool_t allocated; + rt_bool_t unpack_sample; + rt_bool_t running; + rt_bool_t rpmsg_started; +#ifdef RT_USING_RPMSG + struct rt_rpmsg_device *rpmsg_dev; + struct rt_rpmsg_endpoint *rpmsg_ept; + rt_uint32_t rpmsg_remote_addr; + struct rt_completion rpmsg_startup_done; + rt_uint32_t rpmsg_rx_count; + rt_bool_t rpmsg_startup_ready; +#endif +}; + +static rt_list_t hdmi_nodes = RT_LIST_OBJECT_INIT(hdmi_nodes); +static RT_DEFINE_SPINLOCK(hdmi_nodes_lock); +#ifdef RT_USING_RPMSG +static struct spacemit_adma *spacemit_adma_global; +static RT_DEFINE_SPINLOCK(spacemit_adma_global_lock); + +struct spacemit_rpmsg_char_ctrl +{ + struct rt_device parent; + struct rt_rpmsg_device *rdev; +}; +#endif + +struct spacemit_hdmi_audio *spacemit_hdmi_audio_find(struct rt_ofw_node *np) +{ + struct spacemit_hdmi_audio *hdmi; + + rt_spin_lock(&hdmi_nodes_lock); + rt_list_for_each_entry(hdmi, &hdmi_nodes, list) + { + if (hdmi->np == np) + { + rt_spin_unlock(&hdmi_nodes_lock); + return hdmi; + } + } + rt_spin_unlock(&hdmi_nodes_lock); + + return RT_NULL; +} + +rt_bool_t spacemit_hdmi_audio_connected(struct spacemit_hdmi_audio *hdmi) +{ + return hdmi && + (HWREG32((char *)hdmi->hdmi_regs + HDMI_PHY_STATUS) & HDMI_PHY_HPD); +} + +rt_err_t spacemit_hdmi_audio_start(struct spacemit_hdmi_audio *hdmi) +{ + rt_err_t err; + rt_ubase_t rate; + rt_uint32_t clock; + rt_uint32_t value; + + if (!hdmi) + { + return -RT_EINVAL; + } + + if (!hdmi->users) + { + if ((err = rt_clk_set_rate(hdmi->audio_clk, HDMI_SSPA_SAMPLE_RATE))) + { + LOG_E("failed to set HDMI audio clock: %s", rt_strerror(err)); + return err; + } + if ((err = rt_reset_control_deassert(hdmi->reset))) + { + LOG_E("failed to deassert HDMI audio reset: %s", rt_strerror(err)); + return err; + } + + rate = rt_clk_get_rate(hdmi->audio_clk); + clock = HWREG32((char *)hdmi->clock_regs + HDMI_SSPA_CLOCK_CONTROL); + if (rate != HDMI_SSPA_SAMPLE_RATE || + (clock & HDMI_SSPA_CLOCK_READY) != HDMI_SSPA_CLOCK_READY) + { + LOG_E("HDMI audio clock is not ready: rate=%lu ctrl=%08x", + (unsigned long)rate, clock); + return -RT_EIO; + } + + value = HWREG32((char *)hdmi->hdmi_regs + HDMI_AUDIO_ENABLE); + HWREG32((char *)hdmi->hdmi_regs + HDMI_AUDIO_ENABLE) = + value | HDMI_AUDIO_ENABLE_BIT; + rt_hw_wmb(); + value = HWREG32((char *)hdmi->hdmi_regs + HDMI_AUDIO_ENABLE); + if (!(value & HDMI_AUDIO_ENABLE_BIT)) + { + LOG_E("failed to enable HDMI audio path: ctrl=%08x", value); + return -RT_EIO; + } + + LOG_D("HDMI path enabled: rate=%lu clk=%08x audio=%08x HPD=%d", + (unsigned long)rate, clock, value, + spacemit_hdmi_audio_connected(hdmi)); + } + ++hdmi->users; + + if (!spacemit_hdmi_audio_connected(hdmi) && !hdmi->warned_unplugged) + { + hdmi->warned_unplugged = RT_TRUE; + LOG_W("HDMI is not connected; audio clock will keep running"); + } + + return RT_EOK; +} + +rt_err_t spacemit_hdmi_audio_stop(struct spacemit_hdmi_audio *hdmi) +{ + rt_uint32_t value; + + if (!hdmi) + { + return -RT_EINVAL; + } + + if (hdmi->users > 0 && !--hdmi->users) + { + value = HWREG32((char *)hdmi->hdmi_regs + HDMI_AUDIO_ENABLE); + HWREG32((char *)hdmi->hdmi_regs + HDMI_AUDIO_ENABLE) = + value & ~HDMI_AUDIO_ENABLE_BIT; + } + + return RT_EOK; +} + +rt_ubase_t spacemit_hdmi_audio_fifo_phys(struct spacemit_hdmi_audio *hdmi) +{ + return hdmi ? hdmi->phys + HDMI_SSPA_TX_DATA : 0; +} + +static void spacemit_adma_abort_hw(struct spacemit_adma *adma) +{ + rt_uint32_t control; + + control = HWREG32((char *)adma->regs + K1_ADMA_CONTROL); + HWREG32((char *)adma->regs + K1_ADMA_CONTROL) = control | K1_ADMA_ABORT; + rt_hw_us_delay(500); + control = HWREG32((char *)adma->regs + K1_ADMA_CONTROL); + HWREG32((char *)adma->regs + K1_ADMA_CONTROL) = + control & ~K1_ADMA_ENABLE; + HWREG32((char *)adma->regs + K1_ADMA_INT_ENABLE) = 0; + HWREG32((char *)adma->regs + K1_ADMA_INT_STATUS) = 0; + HWREG32(adma->control) = 0; +} + +static void spacemit_adma_stop_period(struct spacemit_adma *adma) +{ + adma->running = RT_FALSE; +} + +static rt_err_t spacemit_adma_build_ring(struct spacemit_adma *adma) +{ + rt_size_t index; + + if (adma->period_count * K1_ADMA_DESC_STRIDE > 0x400) + { + return -RT_EINVAL; + } + + for (index = 0; index < adma->period_count; ++index) + { + void *descriptor = (char *)adma->descriptors + + index * K1_ADMA_DESC_STRIDE; + rt_uint32_t next = (rt_uint32_t)(adma->descriptors_dma + + ((index + 1) % adma->period_count) * K1_ADMA_DESC_STRIDE); + + HWREG32((char *)descriptor + K1_ADMA_DESC_BYTE_COUNT) = + adma->period_len; + HWREG32((char *)descriptor + K1_ADMA_DESC_SOURCE_ADDR) = + (rt_uint32_t)(adma->buffer_dma + index * adma->period_len); + HWREG32((char *)descriptor + K1_ADMA_DESC_DEST_ADDR) = + (rt_uint32_t)adma->channel.conf.dst_addr; + HWREG32((char *)descriptor + K1_ADMA_DESC_NEXT) = next; + if (index < 4) + { + LOG_D("ADMA desc[%u]: BCR=%08x SAR=%08x DAR=%08x NDR=%08x", + (unsigned int)index, + HWREG32((char *)descriptor + K1_ADMA_DESC_BYTE_COUNT), + HWREG32((char *)descriptor + K1_ADMA_DESC_SOURCE_ADDR), + HWREG32((char *)descriptor + K1_ADMA_DESC_DEST_ADDR), + HWREG32((char *)descriptor + K1_ADMA_DESC_NEXT)); + } + } + rt_hw_wmb(); + + return RT_EOK; +} + +static void spacemit_adma_period_done(struct spacemit_adma *adma) +{ + if (!adma->running) + { + return; + } + + adma->period_index = (adma->period_index + 1) % adma->period_count; + adma->period_done_count++; + if (adma->period_done_count <= 4 || + !(adma->period_done_count % 100)) + { + LOG_D("ADMA period done #%u", adma->period_done_count); + } + rt_dma_chan_done(&adma->channel, adma->period_len); +} + +#ifdef RT_USING_RPMSG +static struct rt_rpmsg_device *spacemit_adma_get_rpmsg_device(void) +{ + char name[16]; + rt_device_t dev = RT_NULL; + + for (int i = 0; i < 4; ++i) + { + struct spacemit_rpmsg_char_ctrl *ctrl; + + rt_snprintf(name, sizeof(name), "rpmsg_char%d", i); + dev = rt_device_find(name); + if (dev) + { + ctrl = rt_container_of(dev, struct spacemit_rpmsg_char_ctrl, + parent); + if (ctrl->rdev) + { + LOG_D("ADMA RPMsg transport found via %s", name); + return ctrl->rdev; + } + } + } + + LOG_E("ADMA RPMsg control device rpmsg_charN not found"); + return RT_NULL; +} + +static rt_bool_t spacemit_adma_get_remote_addr(struct rt_rpmsg_device *rdev, + rt_uint32_t *addr) +{ + rt_ubase_t level; + struct rt_rpmsg_endpoint *ept; + + level = rt_spin_lock_irqsave(&rdev->lock); + rt_list_for_each_entry(ept, &rdev->ept_nodes, list) + { + if (ept->info.src == RT_RPMSG_ADDR_ANY && + ept->info.dst != RT_RPMSG_ADDR_ANY && + !rt_strncmp(ept->info.name, "adma-service", RT_RPMSG_NAME_SIZE)) + { + *addr = ept->info.dst; + rt_spin_unlock_irqrestore(&rdev->lock, level); + return RT_TRUE; + } + } + rt_spin_unlock_irqrestore(&rdev->lock, level); + + return RT_FALSE; +} + +static rt_err_t spacemit_adma_rpmsg_rx(struct rt_rpmsg_device *rdev, + rt_uint32_t src, void *data, rt_size_t len) +{ + rt_ubase_t level; + struct spacemit_adma *adma; + rt_bool_t startup_ok = RT_FALSE; + rt_bool_t period_done = RT_FALSE; + + RT_UNUSED(rdev); + + level = rt_spin_lock_irqsave(&spacemit_adma_global_lock); + adma = spacemit_adma_global; + rt_spin_unlock_irqrestore(&spacemit_adma_global_lock, level); + + if (adma && data && len) + { + adma->rpmsg_rx_count++; + startup_ok = len >= sizeof(K1_ADMA_RPMSG_STARTUP_OK_MSG) - 1 && + !rt_memcmp(data, K1_ADMA_RPMSG_STARTUP_OK_MSG, + sizeof(K1_ADMA_RPMSG_STARTUP_OK_MSG) - 1); + period_done = *(const char *)data == '#'; + + if (adma->rpmsg_rx_count <= 8 || + !(adma->rpmsg_rx_count % 100)) + { + LOG_D("ADMA RPMsg rx #%u: src=%u len=%u type=%s running=%d", + adma->rpmsg_rx_count, src, (unsigned int)len, + startup_ok ? "startup-ok" : + (period_done ? "period" : "unknown"), adma->running); + } + } + + if (adma && startup_ok) + { + adma->rpmsg_startup_ready = RT_TRUE; + rt_completion_done(&adma->rpmsg_startup_done); + } + else if (adma && period_done && adma->running) + { + spacemit_adma_period_done(adma); + } + + return RT_EOK; +} + +static rt_err_t spacemit_adma_create_rpmsg_endpoint(struct spacemit_adma *adma) +{ + struct rt_rpmsg_endpoint_info info; + + if (adma->rpmsg_ept) + { + return RT_EOK; + } + + if (!adma->rpmsg_dev) + { + adma->rpmsg_dev = spacemit_adma_get_rpmsg_device(); + if (!adma->rpmsg_dev) + { + return -RT_EBUSY; + } + } + + rt_memset(&info, 0, sizeof(info)); + rt_strncpy(info.name, "adma-service", RT_RPMSG_NAME_SIZE); + info.src = K1_ADMA_RPMSG_LOCAL_ADDR; + info.dst = RT_RPMSG_NS_ADDR; + + adma->rpmsg_ept = rt_rpmsg_create_endpoint(adma->rpmsg_dev, + &info, spacemit_adma_rpmsg_rx); + if (rt_is_err(adma->rpmsg_ept)) + { + rt_err_t err = rt_ptr_err(adma->rpmsg_ept); + + adma->rpmsg_ept = RT_NULL; + LOG_E("ADMA RPMsg endpoint create failed: %s", rt_strerror(err)); + return err; + } + + LOG_D("ADMA RPMsg endpoint created: src=%u", + K1_ADMA_RPMSG_LOCAL_ADDR); + + return RT_EOK; +} + +static rt_err_t spacemit_adma_ensure_rpmsg(struct spacemit_adma *adma) +{ + rt_err_t err; + rt_tick_t deadline; + rt_uint32_t remote_addr = RT_RPMSG_ADDR_ANY; + +#ifdef RT_SOC_SPACEMIT_K1X_RPROC + err = spacemit_k1x_rproc_boot("esos.elf"); + if (err) + { + LOG_E("RCPU firmware is not ready: %s", rt_strerror(err)); + return err; + } +#else + LOG_E("ADMA requires K1X RCPU remoteproc"); + return -RT_EBUSY; +#endif + + err = spacemit_adma_create_rpmsg_endpoint(adma); + if (err) + { + LOG_E("ADMA RPMsg endpoint is not ready: %s", rt_strerror(err)); + return err; + } + + deadline = rt_tick_get() + + rt_tick_from_millisecond(K1_ADMA_RPMSG_BOOT_TIMEOUT_MS); + while (!spacemit_adma_get_remote_addr(adma->rpmsg_dev, &remote_addr)) + { + if ((rt_int32_t)(rt_tick_get() - deadline) >= 0) + { + LOG_E("RCPU adma-service is not ready"); + spacemit_k1x_rproc_dump_status(); + return -RT_EBUSY; + } + rt_thread_mdelay(10); + } + + if (adma->rpmsg_remote_addr != remote_addr) + { + LOG_D("ADMA RPMsg remote service: dst=%u", remote_addr); + adma->rpmsg_remote_addr = remote_addr; + adma->rpmsg_started = RT_FALSE; + adma->rpmsg_startup_ready = RT_FALSE; + } + + if (!adma->rpmsg_started) + { + rt_completion_init(&adma->rpmsg_startup_done); + adma->rpmsg_startup_ready = RT_FALSE; + err = rt_rpmsg_sendto_wait(adma->rpmsg_ept, remote_addr, + K1_ADMA_RPMSG_STARTUP_MSG, + sizeof(K1_ADMA_RPMSG_STARTUP_MSG) - 1, + rt_tick_from_millisecond(K1_ADMA_RPMSG_SEND_TIMEOUT_MS)); + if (err) + { + LOG_E("ADMA RPMsg startup failed: %s", rt_strerror(err)); + return err; + } + LOG_D("ADMA RPMsg startup sent"); + + err = rt_completion_wait(&adma->rpmsg_startup_done, + rt_tick_from_millisecond(K1_ADMA_RPMSG_SEND_TIMEOUT_MS)); + if (err || !adma->rpmsg_startup_ready) + { + LOG_E("ADMA RPMsg startup reply timeout"); + spacemit_k1x_rproc_dump_status(); + return -RT_ETIMEOUT; + } + + adma->rpmsg_started = RT_TRUE; + LOG_D("ADMA RPMsg startup acknowledged"); + } + + return RT_EOK; +} +#else +static rt_err_t spacemit_adma_ensure_rpmsg(struct spacemit_adma *adma) +{ + RT_UNUSED(adma); + + LOG_E("ADMA requires RT_USING_RPMSG"); + return -RT_EBUSY; +} +#endif + +static struct rt_dma_chan *spacemit_adma_request(struct rt_dma_controller *controller, + struct rt_device *slave, void *fw_data) +{ + struct spacemit_adma *adma = rt_container_of(controller, + struct spacemit_adma, parent); + + RT_UNUSED(slave); + RT_UNUSED(fw_data); + + if (adma->allocated) + { + return rt_err_ptr(-RT_EBUSY); + } + + adma->allocated = RT_TRUE; + return &adma->channel; +} + +static rt_err_t spacemit_adma_release(struct rt_dma_chan *channel) +{ + struct spacemit_adma *adma = rt_container_of(channel, + struct spacemit_adma, channel); + + spacemit_adma_stop_period(adma); + adma->allocated = RT_FALSE; + + return RT_EOK; +} + +static rt_err_t spacemit_adma_config(struct rt_dma_chan *channel, + struct rt_dma_slave_config *config) +{ + LOG_D("ADMA config: dir=%d src=%08lx dst=%08lx sw=%u dw=%u burst=%u/%u", + config->direction, + (unsigned long)config->src_addr, + (unsigned long)config->dst_addr, + (unsigned int)config->src_addr_width, + (unsigned int)config->dst_addr_width, + (unsigned int)config->src_maxburst, + (unsigned int)config->dst_maxburst); + if (config->direction != RT_DMA_MEM_TO_DEV || + config->dst_addr_width != RT_DMA_SLAVE_BUSWIDTH_4_BYTES) + { + LOG_E("ADMA config rejected"); + return -RT_EINVAL; + } + + RT_UNUSED(channel); + return RT_EOK; +} + +static rt_err_t spacemit_adma_prep_cyclic(struct rt_dma_chan *channel, + rt_ubase_t buffer, rt_size_t length, rt_size_t period, + enum rt_dma_transfer_direction direction) +{ + rt_size_t count; + struct spacemit_adma *adma = rt_container_of(channel, + struct spacemit_adma, channel); + + LOG_D("ADMA prep cyclic: buf=%08lx len=%u period=%u dir=%d dst=%08lx", + (unsigned long)buffer, (unsigned int)length, + (unsigned int)period, direction, + (unsigned long)channel->conf.dst_addr); + if (direction != RT_DMA_MEM_TO_DEV || !period || length % period || + buffer > 0xffffffffUL || channel->conf.dst_addr > 0xffffffffUL) + { + LOG_E("ADMA prep rejected"); + return -RT_EINVAL; + } + + count = length / period; + if (!count) + { + return -RT_EINVAL; + } + + adma->buffer_dma = buffer; + adma->period_len = period; + adma->period_count = count; + adma->period_index = 0; + adma->period_tick = (rt_tick_t)(((rt_uint64_t)period * + RT_TICK_PER_SECOND + K1_ADMA_HDMI_BYTES_PER_SECOND - 1U) / + K1_ADMA_HDMI_BYTES_PER_SECOND); + if (!adma->period_tick) + { + adma->period_tick = 1; + } + LOG_D("ADMA prep done: count=%u tick=%u", + (unsigned int)adma->period_count, + (unsigned int)adma->period_tick); + + return RT_EOK; +} + +static rt_err_t spacemit_adma_start(struct rt_dma_chan *channel) +{ + rt_err_t err; + rt_uint32_t control; + struct spacemit_adma *adma = rt_container_of(channel, + struct spacemit_adma, channel); + + LOG_D("ADMA start begin"); + if ((err = spacemit_adma_ensure_rpmsg(adma))) + { + LOG_E("ADMA remote service failed: %s", rt_strerror(err)); + return err; + } + + control = HWREG32((char *)adma->regs + K1_ADMA_CONTROL); + LOG_D("ADMA start hw state: BCR=%08x SAR=%08x DAR=%08x NDR=%08x " + "DCR=%08x CUR=%08x IER=%08x ISR=%08x CTRL=%08x", + HWREG32((char *)adma->regs + K1_ADMA_BYTE_COUNT), + HWREG32((char *)adma->regs + K1_ADMA_SOURCE_ADDR), + HWREG32((char *)adma->regs + K1_ADMA_DEST_ADDR), + HWREG32((char *)adma->regs + K1_ADMA_NEXT_DESC), + control, + HWREG32((char *)adma->regs + K1_ADMA_CURRENT_DESC), + HWREG32((char *)adma->regs + K1_ADMA_INT_ENABLE), + HWREG32((char *)adma->regs + K1_ADMA_INT_STATUS), + HWREG32(adma->control)); + if (control & K1_ADMA_ENABLE) + { + HWREG32((char *)adma->regs + K1_ADMA_CONTROL) = + control | K1_ADMA_ABORT; + rt_hw_us_delay(500); + HWREG32((char *)adma->regs + K1_ADMA_CONTROL) = + control & ~K1_ADMA_ENABLE; + } + + HWREG32((char *)adma->regs + K1_ADMA_INT_ENABLE) = 0; + HWREG32((char *)adma->regs + K1_ADMA_INT_STATUS) = 0; + control = K1_ADMA_SAMPLE_BITS(5) | K1_ADMA_ABORT | + K1_ADMA_DST_HOLD | K1_ADMA_SRC_INCREMENT; + if (adma->unpack_sample) + { + control |= K1_ADMA_UNPACK; + } + adma->period_index = 0; + adma->period_done_count = 0; + LOG_D("ADMA build ring begin"); + if ((err = spacemit_adma_build_ring(adma))) + { + LOG_E("ADMA build ring failed: %s", rt_strerror(err)); + return err; + } + LOG_D("ADMA build ring done"); + + HWREG32((char *)adma->regs + K1_ADMA_NEXT_DESC) = + (rt_uint32_t)adma->descriptors_dma; + HWREG32((char *)adma->regs + K1_ADMA_CONTROL) = control; + HWREG32(adma->control) = adma->unpack_sample ? 0 : K1_ADMA_HDMI_ENABLE; + HWREG32((char *)adma->regs + K1_ADMA_DEST_ADDR) = + (rt_uint32_t)adma->channel.conf.dst_addr; + HWREG32((char *)adma->regs + K1_ADMA_INT_ENABLE) = 1; + rt_hw_wmb(); + + /* ABORT is a command bit and clears itself. Reads DCR back before + * enabling the channel so ABORT is not asserted together with CH_EN. */ + adma->running = RT_TRUE; + control = HWREG32((char *)adma->regs + K1_ADMA_CONTROL); + HWREG32((char *)adma->regs + K1_ADMA_CONTROL) = control | + K1_ADMA_FETCH_NEXT_DESC | K1_ADMA_ENABLE; + rt_hw_wmb(); + + LOG_D("ADMA started: DCR=%08x CUR=%08x NDR=%08x CTRL=%08x", + HWREG32((char *)adma->regs + K1_ADMA_CONTROL), + HWREG32((char *)adma->regs + K1_ADMA_CURRENT_DESC), + HWREG32((char *)adma->regs + K1_ADMA_NEXT_DESC), + HWREG32(adma->control)); + return RT_EOK; +} + +static rt_err_t spacemit_adma_stop(struct rt_dma_chan *channel) +{ + struct spacemit_adma *adma = rt_container_of(channel, + struct spacemit_adma, channel); + + spacemit_adma_stop_period(adma); + + spacemit_adma_abort_hw(adma); + + return RT_EOK; +} + +static const struct rt_dma_controller_ops spacemit_adma_ops = +{ + .request_chan = spacemit_adma_request, + .release_chan = spacemit_adma_release, + .start = spacemit_adma_start, + .stop = spacemit_adma_stop, + .config = spacemit_adma_config, + .prep_cyclic = spacemit_adma_prep_cyclic, +}; + +static rt_err_t spacemit_adma_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + rt_uint64_t address; + struct rt_device *dev = &pdev->parent; + struct spacemit_adma *adma = rt_calloc(1, sizeof(*adma)); + + if (!adma) + { + return -RT_ENOMEM; + } + + adma->dev = dev; + adma->regs = rt_dm_dev_iomap(dev, 0); + adma->control = rt_dm_dev_iomap(dev, 1); + adma->descriptors = rt_dm_dev_iomap(dev, 2); + if (!adma->regs || !adma->control || !adma->descriptors || + rt_dm_dev_get_address(dev, 2, &address, RT_NULL) || + address > 0xffffffffULL) + { + err = -RT_EIO; + goto _fail; + } + adma->descriptors_dma = (rt_ubase_t)address; + adma->unpack_sample = !rt_dm_dev_prop_read_bool(dev, "hdmi-sample"); +#ifdef RT_USING_RPMSG + adma->rpmsg_remote_addr = RT_RPMSG_ADDR_ANY; + rt_completion_init(&adma->rpmsg_startup_done); +#endif + + adma->parent.dev = dev; + adma->parent.ops = &spacemit_adma_ops; + rt_dma_controller_add_direction(&adma->parent, RT_DMA_MEM_TO_DEV); + rt_dma_controller_set_addr_mask(&adma->parent, RT_DMA_ADDR_MASK(32)); + if ((err = rt_dma_controller_register(&adma->parent))) + { + goto _fail; + } + + dev->user_data = adma; +#ifdef RT_USING_RPMSG + rt_spin_lock(&spacemit_adma_global_lock); + spacemit_adma_global = adma; + rt_spin_unlock(&spacemit_adma_global_lock); +#endif + LOG_D("K1 HDMI ADMA ready in cyclic descriptor mode, hdmi-sample=%d", + !adma->unpack_sample); + + return RT_EOK; + +_fail: + if (adma->regs) + { + rt_iounmap(adma->regs); + } + if (adma->control) + { + rt_iounmap(adma->control); + } + if (adma->descriptors) + { + rt_iounmap(adma->descriptors); + } + rt_free(adma); + return err; +} + +static rt_err_t spacemit_adma_remove(struct rt_platform_device *pdev) +{ + struct spacemit_adma *adma = pdev->parent.user_data; + + if (!adma) + { + return RT_EOK; + } + + if (rt_dma_controller_unregister(&adma->parent)) + { + return -RT_EBUSY; + } + + spacemit_adma_stop_period(adma); +#ifdef RT_USING_RPMSG + rt_spin_lock(&spacemit_adma_global_lock); + if (spacemit_adma_global == adma) + { + spacemit_adma_global = RT_NULL; + } + rt_spin_unlock(&spacemit_adma_global_lock); + if (adma->rpmsg_dev && adma->rpmsg_ept) + { + rt_rpmsg_destroy_endpoint(adma->rpmsg_dev, adma->rpmsg_ept); + } +#endif + rt_iounmap(adma->regs); + rt_iounmap(adma->control); + rt_iounmap(adma->descriptors); + rt_free(adma); + + return RT_EOK; +} + +static const struct rt_ofw_node_id spacemit_adma_ofw_ids[] = +{ + { .compatible = "spacemit,k1x-adma" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver spacemit_adma_driver = +{ + .name = "spacemit-hdmi-adma", + .ids = spacemit_adma_ofw_ids, + .probe = spacemit_adma_probe, + .remove = spacemit_adma_remove, +}; + +static int spacemit_adma_register(void) +{ + rt_platform_driver_register(&spacemit_adma_driver); + return 0; +} +INIT_SUBSYS_EXPORT(spacemit_adma_register); + +static void spacemit_hdmi_audio_free(struct spacemit_hdmi_audio *hdmi) +{ + if (!hdmi) + { + return; + } + + if (!rt_is_err_or_null(hdmi->reset)) + { + rt_reset_control_assert(hdmi->reset); + rt_reset_control_put(hdmi->reset); + } + if (!rt_is_err_or_null(hdmi->audio_clk)) + { + rt_clk_disable_unprepare(hdmi->audio_clk); + rt_clk_put(hdmi->audio_clk); + } + if (!rt_is_err_or_null(hdmi->hdmi_clk)) + { + rt_clk_disable_unprepare(hdmi->hdmi_clk); + rt_clk_put(hdmi->hdmi_clk); + } + if (hdmi->regs) + { + rt_iounmap(hdmi->regs); + } + if (hdmi->clock_regs) + { + rt_iounmap(hdmi->clock_regs); + } + if (hdmi->hdmi_regs) + { + rt_iounmap(hdmi->hdmi_regs); + } + rt_free(hdmi); +} + +static rt_err_t spacemit_hdmi_audio_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + rt_uint64_t address; + struct rt_device *dev = &pdev->parent; + struct spacemit_hdmi_audio *hdmi = rt_calloc(1, sizeof(*hdmi)); + + if (!hdmi) + { + return -RT_ENOMEM; + } + + hdmi->dev = dev; + hdmi->np = dev->ofw_node; + hdmi->regs = rt_dm_dev_iomap(dev, 0); + hdmi->clock_regs = rt_dm_dev_iomap(dev, 1); + hdmi->hdmi_regs = rt_ioremap((void *)HDMI_PHY_BASE, HDMI_PHY_SIZE); + if (!hdmi->regs || !hdmi->clock_regs || !hdmi->hdmi_regs || + rt_dm_dev_get_address(dev, 0, &address, RT_NULL)) + { + err = -RT_EIO; + goto _fail; + } + hdmi->phys = (rt_ubase_t)address; + + hdmi->audio_clk = rt_clk_get_by_index(dev, 0); + if (rt_is_err(hdmi->audio_clk)) + { + err = rt_ptr_err(hdmi->audio_clk); + goto _fail; + } + if ((err = rt_clk_set_rate(hdmi->audio_clk, HDMI_SSPA_SAMPLE_RATE))) + { + goto _fail; + } + if ((err = rt_clk_prepare_enable(hdmi->audio_clk))) + { + goto _fail; + } + + hdmi->hdmi_clk = rt_clk_get_by_index(dev, 1); + if (!rt_is_err(hdmi->hdmi_clk)) + { + if ((err = rt_clk_prepare_enable(hdmi->hdmi_clk))) + { + goto _fail; + } + } + + hdmi->reset = rt_reset_control_get_by_index(dev, 0); + if (rt_is_err(hdmi->reset)) + { + err = rt_ptr_err(hdmi->reset); + goto _fail; + } + if ((err = rt_reset_control_deassert(hdmi->reset))) + { + goto _fail; + } + + LOG_D("%s: clock=%lu Hz ctrl=%08x", rt_dm_dev_get_name(dev), + (unsigned long)rt_clk_get_rate(hdmi->audio_clk), + HWREG32((char *)hdmi->clock_regs + HDMI_SSPA_CLOCK_CONTROL)); + + rt_spin_lock(&hdmi_nodes_lock); + rt_list_insert_before(&hdmi_nodes, &hdmi->list); + rt_spin_unlock(&hdmi_nodes_lock); + + dev->user_data = hdmi; + rt_dm_dev_bind_fwdata(dev, RT_NULL, hdmi); + + LOG_D("%s: HDMI SSPA ready, HPD=%d", rt_dm_dev_get_name(dev), + spacemit_hdmi_audio_connected(hdmi)); + + return RT_EOK; + +_fail: + spacemit_hdmi_audio_free(hdmi); + return err; +} + +static rt_err_t spacemit_hdmi_audio_remove(struct rt_platform_device *pdev) +{ + struct spacemit_hdmi_audio *hdmi = pdev->parent.user_data; + + if (!hdmi) + { + return RT_EOK; + } + + rt_spin_lock(&hdmi_nodes_lock); + rt_list_remove(&hdmi->list); + rt_spin_unlock(&hdmi_nodes_lock); + + rt_dm_dev_unbind_fwdata(&pdev->parent, RT_NULL); + spacemit_hdmi_audio_free(hdmi); + + return RT_EOK; +} + +static const struct rt_ofw_node_id spacemit_hdmi_audio_ofw_ids[] = +{ + { .compatible = "spacemit,spacemit-snd-sspa" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver spacemit_hdmi_audio_driver = +{ + .name = "spacemit-hdmi-audio", + .ids = spacemit_hdmi_audio_ofw_ids, + .probe = spacemit_hdmi_audio_probe, + .remove = spacemit_hdmi_audio_remove, +}; + +static int spacemit_hdmi_audio_register(void) +{ + rt_platform_driver_register(&spacemit_hdmi_audio_driver); + return 0; +} +INIT_DEVICE_EXPORT(spacemit_hdmi_audio_register); diff --git a/bsp/spacemit/dm/audio/spacemit-snd-sspa.h b/bsp/spacemit/dm/audio/spacemit-snd-sspa.h new file mode 100644 index 000000000000..b86321e539da --- /dev/null +++ b/bsp/spacemit/dm/audio/spacemit-snd-sspa.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#ifndef __SPACEMIT_SND_SSPA_H__ +#define __SPACEMIT_SND_SSPA_H__ + +#include + +#define HDMI_SSPA_TX_DATA 0x80 + +#define HDMI_PHY_BASE 0xc0400500UL +#define HDMI_PHY_SIZE 0x200 +#define HDMI_PHY_STATUS 0x0c +#define HDMI_PHY_HPD RT_BIT(12) +#define HDMI_AUDIO_ENABLE 0x30 +#define HDMI_AUDIO_ENABLE_BIT RT_BIT(0) + +#define HDMI_SSPA_CLOCK_CONTROL 0x44 +#define HDMI_SSPA_CLOCK_READY 0x7 +#define HDMI_SSPA_SAMPLE_RATE 48000 + +#define K1_ADMA_BYTE_COUNT 0x00 +#define K1_ADMA_SOURCE_ADDR 0x10 +#define K1_ADMA_DEST_ADDR 0x20 +#define K1_ADMA_NEXT_DESC 0x30 +#define K1_ADMA_CONTROL 0x40 +#define K1_ADMA_CURRENT_DESC 0x70 +#define K1_ADMA_INT_ENABLE 0x80 +#define K1_ADMA_INT_STATUS 0xa0 + +#define K1_ADMA_SAMPLE_BITS(v) (((v) & 0x7U) << 22) +#define K1_ADMA_ABORT RT_BIT(20) +#define K1_ADMA_UNPACK RT_BIT(16) +#define K1_ADMA_ACTIVE RT_BIT(14) +#define K1_ADMA_FETCH_NEXT_DESC RT_BIT(13) +#define K1_ADMA_ENABLE RT_BIT(12) +#define K1_ADMA_DST_HOLD (0x2U << 4) +#define K1_ADMA_SRC_INCREMENT (0x0U << 2) + +#define K1_ADMA_HDMI_ENABLE RT_BIT(0) + +#define K1_ADMA_DESC_BYTE_COUNT 0x00 +#define K1_ADMA_DESC_SOURCE_ADDR 0x04 +#define K1_ADMA_DESC_DEST_ADDR 0x08 +#define K1_ADMA_DESC_NEXT 0x0c +#define K1_ADMA_DESC_STRIDE 0x100 + +#endif /* __SPACEMIT_SND_SSPA_H__ */ diff --git a/bsp/spacemit/dm/clk/Kconfig b/bsp/spacemit/dm/clk/Kconfig new file mode 100644 index 000000000000..abc9ab79a3c6 --- /dev/null +++ b/bsp/spacemit/dm/clk/Kconfig @@ -0,0 +1,9 @@ +menuconfig RT_CLK_SPACEMIT + bool "Spacemit clock controller common" + depends on RT_USING_OFW + default y + +config RT_CLK_SPACEMIT_K1X + bool "Spacemit k1x clock controller support" + depends on RT_CLK_SPACEMIT + default n diff --git a/bsp/spacemit/dm/clk/SConscript b/bsp/spacemit/dm/clk/SConscript new file mode 100644 index 000000000000..3051d69dfb64 --- /dev/null +++ b/bsp/spacemit/dm/clk/SConscript @@ -0,0 +1,15 @@ +from building import * + +cwd = GetCurrentDir() +src = [] +CPPPATH = [cwd + '/../include'] + +if GetDepend(['RT_CLK_SPACEMIT']): + src += ['ccu_ddn.c', 'ccu_ddr.c', 'ccu_dpll.c', 'ccu_mix.c', 'ccu_pll.c'] + + if GetDepend(['RT_CLK_SPACEMIT_K1X']): + src += ['ccu-spacemit-k1x.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/spacemit/dm/clk/ccu-spacemit-k1x.c b/bsp/spacemit/dm/clk/ccu-spacemit-k1x.c new file mode 100644 index 000000000000..69cee1d44878 --- /dev/null +++ b/bsp/spacemit/dm/clk/ccu-spacemit-k1x.c @@ -0,0 +1,1244 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#include +#include + +#include "ccu_ddn.h" +#include "ccu_ddr.h" +#include "ccu_mix.h" +#include "ccu_dpll.h" +#include "ccu_pll.h" + +#include +#include + +struct k1x_clk +{ + struct rt_clk_node parent; + + union + { + struct + { + void *mpmu_base; + void *apmu_base; + void *apbc_base; + void *apbs_base; + void *ciu_base; + void *dciu_base; + void *ddrc_base; + void *apbc2_base; + void *rcpu_base; + void *rcpu2_base; + void *audpmu_base; + void *audio_ctrl_base; + }; + void *mmio[CRU_BASE_TYPE_MAX]; + }; +}; + +static const struct ccu_pll_rate_tbl pll2_rate_tbl[] = +{ + PLL_RATE(3000000000UL, 0x66, 0xdd, 0x50, 0x00, 0x3f, 0xe00000), + PLL_RATE(3200000000UL, 0x67, 0xdd, 0x50, 0x00, 0x43, 0xeaaaab), + PLL_RATE(2457600000UL, 0x64, 0xdd, 0x50, 0x00, 0x33, 0x0ccccd), + PLL_RATE(2800000000UL, 0x66, 0xdd, 0x50, 0x00, 0x3a, 0x155555), +}; + +static const struct ccu_pll_rate_tbl pll3_rate_tbl[] = +{ + PLL_RATE(1600000000UL, 0x61, 0xcd, 0x50, 0x00, 0x43, 0xeaaaab), + PLL_RATE(1800000000UL, 0x61, 0xcd, 0x50, 0x00, 0x4b, 0x000000), + PLL_RATE(2000000000UL, 0x62, 0xdd, 0x50, 0x00, 0x2a, 0xeaaaab), + PLL_RATE(3000000000UL, 0x66, 0xdd, 0x50, 0x00, 0x3f, 0xe00000), + PLL_RATE(3200000000UL, 0x67, 0xdd, 0x50, 0x00, 0x43, 0xeaaaab), + PLL_RATE(2457600000UL, 0x64, 0xdd, 0x50, 0x00, 0x33, 0x0ccccd), +}; + +static SPACEMIT_CCU_PLL(pll2, "pll2", &pll2_rate_tbl, RT_ARRAY_SIZE(pll2_rate_tbl), + CRU_BASE_TYPE_APBS, APB_SPARE7_REG, APB_SPARE8_REG, APB_SPARE9_REG, + MPMU_POSR, POSR_PLL2_LOCK, 1, RT_CLK_F_IGNORE_UNUSED); + +static SPACEMIT_CCU_PLL(pll3, "pll3", &pll3_rate_tbl, RT_ARRAY_SIZE(pll3_rate_tbl), + CRU_BASE_TYPE_APBS, APB_SPARE10_REG, APB_SPARE11_REG, APB_SPARE12_REG, + MPMU_POSR, POSR_PLL3_LOCK, 1, RT_CLK_F_IGNORE_UNUSED); + +/* PLL1 */ +static SPACEMIT_CCU_GATE_FACTOR(pll1_d2, "pll1_d2", "pll1_2457p6_vco", + CRU_BASE_TYPE_APBS, APB_SPARE2_REG, RT_BIT(1), RT_BIT(1), 0x0, 2, 1, RT_CLK_F_IGNORE_UNUSED); +static SPACEMIT_CCU_GATE_FACTOR(pll1_d3, "pll1_d3", "pll1_2457p6_vco", + CRU_BASE_TYPE_APBS, APB_SPARE2_REG, RT_BIT(2), RT_BIT(2), 0x0, 3, 1, RT_CLK_F_IGNORE_UNUSED); +static SPACEMIT_CCU_GATE_FACTOR(pll1_d4, "pll1_d4", "pll1_2457p6_vco", + CRU_BASE_TYPE_APBS, APB_SPARE2_REG, RT_BIT(3), RT_BIT(3), 0x0, 4, 1, RT_CLK_F_IGNORE_UNUSED); +static SPACEMIT_CCU_GATE_FACTOR(pll1_d5, "pll1_d5", "pll1_2457p6_vco", + CRU_BASE_TYPE_APBS, APB_SPARE2_REG, RT_BIT(4), RT_BIT(4), 0x0, 5, 1, RT_CLK_F_IGNORE_UNUSED); +static SPACEMIT_CCU_GATE_FACTOR(pll1_d6, "pll1_d6", "pll1_2457p6_vco", + CRU_BASE_TYPE_APBS, APB_SPARE2_REG, RT_BIT(5), RT_BIT(5), 0x0, 6, 1, RT_CLK_F_IGNORE_UNUSED); +static SPACEMIT_CCU_GATE_FACTOR(pll1_d7, "pll1_d7", "pll1_2457p6_vco", + CRU_BASE_TYPE_APBS, APB_SPARE2_REG, RT_BIT(6), RT_BIT(6), 0x0, 7, 1, RT_CLK_F_IGNORE_UNUSED); +static SPACEMIT_CCU_GATE_FACTOR(pll1_d8, "pll1_d8", "pll1_2457p6_vco", + CRU_BASE_TYPE_APBS, APB_SPARE2_REG, RT_BIT(7), RT_BIT(7), 0x0, 8, 1, RT_CLK_F_IGNORE_UNUSED); +static SPACEMIT_CCU_GATE_FACTOR(pll1_d11_223p4, "pll1_d11_223p4", "pll1_2457p6_vco", + CRU_BASE_TYPE_APBS, APB_SPARE2_REG, RT_BIT(15), RT_BIT(15), 0x0, 11, 1, RT_CLK_F_IGNORE_UNUSED); +static SPACEMIT_CCU_GATE_FACTOR(pll1_d13_189, "pll1_d13_189", "pll1_2457p6_vco", + CRU_BASE_TYPE_APBS, APB_SPARE2_REG, RT_BIT(16), RT_BIT(16), 0x0, 13, 1, RT_CLK_F_IGNORE_UNUSED); +static SPACEMIT_CCU_GATE_FACTOR(pll1_d23_106p8, "pll1_d23_106p8", "pll1_2457p6_vco", + CRU_BASE_TYPE_APBS, APB_SPARE2_REG, RT_BIT(20), RT_BIT(20), 0x0, 23, 1, RT_CLK_F_IGNORE_UNUSED); +static SPACEMIT_CCU_GATE_FACTOR(pll1_d64_38p4, "pll1_d64_38p4", "pll1_2457p6_vco", + CRU_BASE_TYPE_APBS, APB_SPARE2_REG, RT_BIT(0), RT_BIT(0), 0x0, 64, 1, RT_CLK_F_IGNORE_UNUSED); +static SPACEMIT_CCU_GATE_FACTOR(pll1_aud_245p7, "pll1_aud_245p7", "pll1_2457p6_vco", + CRU_BASE_TYPE_APBS, APB_SPARE2_REG, RT_BIT(10), RT_BIT(10), 0x0, 10, 1, RT_CLK_F_IGNORE_UNUSED); +static SPACEMIT_CCU_GATE_FACTOR(pll1_aud_24p5, "pll1_aud_24p5", "pll1_2457p6_vco", + CRU_BASE_TYPE_APBS, APB_SPARE2_REG, RT_BIT(11), RT_BIT(11), 0x0, 100, 1, RT_CLK_F_IGNORE_UNUSED); + +/* PLL2 */ +static SPACEMIT_CCU_GATE_FACTOR(pll2_d1, "pll2_d1", "pll2", + CRU_BASE_TYPE_APBS, APB_SPARE8_REG, RT_BIT(0), RT_BIT(0), 0x0, 1, 1, RT_CLK_F_IGNORE_UNUSED); +static SPACEMIT_CCU_GATE_FACTOR(pll2_d2, "pll2_d2", "pll2", + CRU_BASE_TYPE_APBS, APB_SPARE8_REG, RT_BIT(1), RT_BIT(1), 0x0, 2, 1, RT_CLK_F_IGNORE_UNUSED); +static SPACEMIT_CCU_GATE_FACTOR(pll2_d3, "pll2_d3", "pll2", + CRU_BASE_TYPE_APBS, APB_SPARE8_REG, RT_BIT(2), RT_BIT(2), 0x0, 3, 1, RT_CLK_F_IGNORE_UNUSED); +static SPACEMIT_CCU_GATE_FACTOR(pll2_d4, "pll2_d4", "pll2", + CRU_BASE_TYPE_APBS, APB_SPARE8_REG, RT_BIT(3), RT_BIT(3), 0x0, 4, 1, RT_CLK_F_IGNORE_UNUSED); +static SPACEMIT_CCU_GATE_FACTOR(pll2_d5, "pll2_d5", "pll2", + CRU_BASE_TYPE_APBS, APB_SPARE8_REG, RT_BIT(4), RT_BIT(4), 0x0, 5, 1, RT_CLK_F_IGNORE_UNUSED); +static SPACEMIT_CCU_GATE_FACTOR(pll2_d6, "pll2_d6", "pll2", + CRU_BASE_TYPE_APBS, APB_SPARE8_REG, RT_BIT(5), RT_BIT(5), 0x0, 6, 1, RT_CLK_F_IGNORE_UNUSED); +static SPACEMIT_CCU_GATE_FACTOR(pll2_d7, "pll2_d7", "pll2", + CRU_BASE_TYPE_APBS, APB_SPARE8_REG, RT_BIT(6), RT_BIT(6), 0x0, 7, 1, RT_CLK_F_IGNORE_UNUSED); +static SPACEMIT_CCU_GATE_FACTOR(pll2_d8, "pll2_d8", "pll2", + CRU_BASE_TYPE_APBS, APB_SPARE8_REG, RT_BIT(7), RT_BIT(7), 0x0, 8, 1, RT_CLK_F_IGNORE_UNUSED); + +/* PLL3 */ +static SPACEMIT_CCU_GATE_FACTOR(pll3_d1, "pll3_d1", "pll3", + CRU_BASE_TYPE_APBS, APB_SPARE11_REG, RT_BIT(0), RT_BIT(0), 0x0, 1, 1, RT_CLK_F_IGNORE_UNUSED); +static SPACEMIT_CCU_GATE_FACTOR(pll3_d2, "pll3_d2", "pll3", + CRU_BASE_TYPE_APBS, APB_SPARE11_REG, RT_BIT(1), RT_BIT(1), 0x0, 2, 1, RT_CLK_F_IGNORE_UNUSED); +static SPACEMIT_CCU_GATE_FACTOR(pll3_d3, "pll3_d3", "pll3", + CRU_BASE_TYPE_APBS, APB_SPARE11_REG, RT_BIT(2), RT_BIT(2), 0x0, 3, 1, RT_CLK_F_IGNORE_UNUSED); +static SPACEMIT_CCU_GATE_FACTOR(pll3_d4, "pll3_d4", "pll3", + CRU_BASE_TYPE_APBS, APB_SPARE11_REG, RT_BIT(3), RT_BIT(3), 0x0, 4, 1, RT_CLK_F_IGNORE_UNUSED); +static SPACEMIT_CCU_GATE_FACTOR(pll3_d5, "pll3_d5", "pll3", + CRU_BASE_TYPE_APBS, APB_SPARE11_REG, RT_BIT(4), RT_BIT(4), 0x0, 5, 1, RT_CLK_F_IGNORE_UNUSED); +static SPACEMIT_CCU_GATE_FACTOR(pll3_d6, "pll3_d6", "pll3", + CRU_BASE_TYPE_APBS, APB_SPARE11_REG, RT_BIT(5), RT_BIT(5), 0x0, 6, 1, RT_CLK_F_IGNORE_UNUSED); +static SPACEMIT_CCU_GATE_FACTOR(pll3_d7, "pll3_d7", "pll3", + CRU_BASE_TYPE_APBS, APB_SPARE11_REG, RT_BIT(6), RT_BIT(6), 0x0, 7, 1, RT_CLK_F_IGNORE_UNUSED); +static SPACEMIT_CCU_GATE_FACTOR(pll3_d8, "pll3_d8", "pll3", + CRU_BASE_TYPE_APBS, APB_SPARE11_REG, RT_BIT(7), RT_BIT(7), 0x0, 8, 1, RT_CLK_F_IGNORE_UNUSED); + +/* PLL3_DIV */ +static SPACEMIT_CCU_FACTOR(pll3_80, "pll3_80", "pll3_d8", 5, 1); +static SPACEMIT_CCU_FACTOR(pll3_40, "pll3_40", "pll3_d8", 10, 1); +static SPACEMIT_CCU_FACTOR(pll3_20, "pll3_20", "pll3_d8", 20, 1); + +/* PLL1_D8 */ +static SPACEMIT_CCU_GATE(pll1_d8_307p2, "pll1_d8_307p2", "pll1_d8", + CRU_BASE_TYPE_MPMU, MPMU_ACGR, RT_BIT(13), RT_BIT(13), 0x0, RT_CLK_F_IGNORE_UNUSED); +static SPACEMIT_CCU_FACTOR(pll1_d32_76p8, "pll1_d32_76p8", "pll1_d8_307p2", 4, 1); +static SPACEMIT_CCU_FACTOR(pll1_d40_61p44, "pll1_d40_61p44", "pll1_d8_307p2", 5, 1); +static SPACEMIT_CCU_FACTOR(pll1_d16_153p6, "pll1_d16_153p6", "pll1_d8", 2, 1); +static SPACEMIT_CCU_GATE_FACTOR(pll1_d24_102p4, "pll1_d24_102p4", "pll1_d8", + CRU_BASE_TYPE_MPMU, MPMU_ACGR, RT_BIT(12), RT_BIT(12), 0x0, 3, 1, RT_CLK_F_IGNORE_UNUSED); +static SPACEMIT_CCU_GATE_FACTOR(pll1_d48_51p2, "pll1_d48_51p2", "pll1_d8", + CRU_BASE_TYPE_MPMU, MPMU_ACGR, RT_BIT(7), RT_BIT(7), 0x0, 6, 1, RT_CLK_F_IGNORE_UNUSED); +static SPACEMIT_CCU_GATE_FACTOR(pll1_d48_51p2_ap, "pll1_d48_51p2_ap", "pll1_d8", + CRU_BASE_TYPE_MPMU, MPMU_ACGR, RT_BIT(11), RT_BIT(11), 0x0, 6, 1, RT_CLK_F_IGNORE_UNUSED); +static SPACEMIT_CCU_GATE_FACTOR(pll1_m3d128_57p6, "pll1_m3d128_57p6", "pll1_d8", + CRU_BASE_TYPE_MPMU, MPMU_ACGR, RT_BIT(8), RT_BIT(8), 0x0, 16, 3, RT_CLK_F_IGNORE_UNUSED); +static SPACEMIT_CCU_GATE_FACTOR(pll1_d96_25p6, "pll1_d96_25p6", "pll1_d8", + CRU_BASE_TYPE_MPMU, MPMU_ACGR, RT_BIT(4), RT_BIT(4), 0x0, 12, 1, RT_CLK_F_IGNORE_UNUSED); +static SPACEMIT_CCU_GATE_FACTOR(pll1_d192_12p8, "pll1_d192_12p8", "pll1_d8", + CRU_BASE_TYPE_MPMU, MPMU_ACGR, RT_BIT(3), RT_BIT(3), 0x0, 24, 1, RT_CLK_F_IGNORE_UNUSED); +static SPACEMIT_CCU_GATE_FACTOR(pll1_d192_12p8_wdt, "pll1_d192_12p8_wdt", "pll1_d8", + CRU_BASE_TYPE_MPMU, MPMU_ACGR, RT_BIT(19), RT_BIT(19), 0x0, 24, 1, RT_CLK_F_IGNORE_UNUSED); +static SPACEMIT_CCU_GATE_FACTOR(pll1_d384_6p4, "pll1_d384_6p4", "pll1_d8", + CRU_BASE_TYPE_MPMU, MPMU_ACGR, RT_BIT(2), RT_BIT(2), 0x0, 48, 1, RT_CLK_F_IGNORE_UNUSED); +static SPACEMIT_CCU_FACTOR(pll1_d768_3p2, "pll1_d768_3p2", "pll1_d384_6p4", 2, 1); +static SPACEMIT_CCU_FACTOR(pll1_d1536_1p6, "pll1_d1536_1p6", "pll1_d384_6p4", 4, 1); +static SPACEMIT_CCU_FACTOR(pll1_d3072_0p8, "pll1_d3072_0p8", "pll1_d384_6p4", 8, 1); +/* PLL1_D7 */ +static SPACEMIT_CCU_FACTOR(pll1_d7_351p08, "pll1_d7_351p08", "pll1_d7", 1, 1); +/* PLL1_D6 */ +static SPACEMIT_CCU_GATE(pll1_d6_409p6, "pll1_d6_409p6", "pll1_d6", + CRU_BASE_TYPE_MPMU, MPMU_ACGR, RT_BIT(0), RT_BIT(0), 0x0, RT_CLK_F_IGNORE_UNUSED); +static SPACEMIT_CCU_GATE_FACTOR(pll1_d12_204p8, "pll1_d12_204p8", "pll1_d6", + CRU_BASE_TYPE_MPMU, MPMU_ACGR, RT_BIT(5), RT_BIT(5), 0x0, 2, 1, RT_CLK_F_IGNORE_UNUSED); +/* PLL1_D5 */ +static SPACEMIT_CCU_GATE(pll1_d5_491p52, "pll1_d5_491p52", "pll1_d5", + CRU_BASE_TYPE_MPMU, MPMU_ACGR, RT_BIT(21), RT_BIT(21), 0x0, RT_CLK_F_IGNORE_UNUSED); +static SPACEMIT_CCU_GATE_FACTOR(pll1_d10_245p76, "pll1_d10_245p76", "pll1_d5", + CRU_BASE_TYPE_MPMU, MPMU_ACGR, RT_BIT(18), RT_BIT(18), 0x0, 2, 1, RT_CLK_F_IGNORE_UNUSED); +/* PLL1_D4 */ +static SPACEMIT_CCU_GATE(pll1_d4_614p4, "pll1_d4_614p4", "pll1_d4", + CRU_BASE_TYPE_MPMU, MPMU_ACGR, RT_BIT(15), RT_BIT(15), 0x0, RT_CLK_F_IGNORE_UNUSED); +static SPACEMIT_CCU_GATE_FACTOR(pll1_d52_47p26, "pll1_d52_47p26", "pll1_d4", + CRU_BASE_TYPE_MPMU, MPMU_ACGR, RT_BIT(10), RT_BIT(10), 0x0, 13, 1, RT_CLK_F_IGNORE_UNUSED); +static SPACEMIT_CCU_GATE_FACTOR(pll1_d78_31p5, "pll1_d78_31p5", "pll1_d4", + CRU_BASE_TYPE_MPMU, MPMU_ACGR, RT_BIT(6), RT_BIT(6), 0x0, 39, 2, RT_CLK_F_IGNORE_UNUSED); +/* PLL1_D3 */ +static SPACEMIT_CCU_GATE(pll1_d3_819p2, "pll1_d3_819p2", "pll1_d3", + CRU_BASE_TYPE_MPMU, MPMU_ACGR, RT_BIT(14), RT_BIT(14), 0x0, RT_CLK_F_IGNORE_UNUSED); +/* PLL1_D2 */ +static SPACEMIT_CCU_GATE(pll1_d2_1228p8, "pll1_d2_1228p8", "pll1_d2", + CRU_BASE_TYPE_MPMU, MPMU_ACGR, RT_BIT(16), RT_BIT(16), 0x0, RT_CLK_F_IGNORE_UNUSED); + +/* DPLL */ +static const struct ccu_dpll_rate_tbl dpll1_rate_tbl[] = +{ + DPLL_RATE(2400000000UL, 0x00, 0x00, 0x20, 0x2a, 0x32, 0x64, 0xdd, 0x50), /* 5000 ppm */ + DPLL_RATE(2400000000UL, 0x00, 0x3b, 0x20, 0x2a, 0x32, 0x64, 0xdd, 0x50), /* 5000 ppm + pre-setting */ +}; + +static const struct ccu_dpll_rate_tbl dpll2_rate_tbl[] = +{ + DPLL_RATE(3200000000UL, 0x55, 0x55, 0x3d, 0x2a, 0x43, 0x67, 0xdd, 0x50), /* 5000ppm */ +}; + +static SPACEMIT_CCU_DPLL(dpll1, "dpll1", &dpll1_rate_tbl, RT_ARRAY_SIZE(dpll1_rate_tbl), + CRU_BASE_TYPE_APMU, APMU_DPLL1_CLK_CTRL1, APMU_DPLL1_CLK_CTRL2, 0, RT_CLK_F_IGNORE_UNUSED); + +static SPACEMIT_CCU_DPLL(dpll2, "dpll2", &dpll2_rate_tbl, RT_ARRAY_SIZE(dpll2_rate_tbl), + CRU_BASE_TYPE_APMU, APMU_DPLL2_CLK_CTRL1, APMU_DPLL2_CLK_CTRL2, 0, RT_CLK_F_IGNORE_UNUSED); + +static const char *const dfc_lvl_parents[] = +{ + "dpll2", "dpll1" +}; + +static SPACEMIT_CCU_DIV_MUX(dfc_lvl0, "dfc_lvl0", dfc_lvl_parents, + CRU_BASE_TYPE_APMU, APMU_DFC_LEVEL0, 14, 2, 8, 1, 0); +static SPACEMIT_CCU_DIV_MUX(dfc_lvl1, "dfc_lvl1", dfc_lvl_parents, + CRU_BASE_TYPE_APMU, APMU_DFC_LEVEL1, 14, 2, 8, 1, 0); +static SPACEMIT_CCU_DIV_MUX(dfc_lvl2, "dfc_lvl2", dfc_lvl_parents, + CRU_BASE_TYPE_APMU, APMU_DFC_LEVEL2, 14, 2, 8, 1, 0); +static SPACEMIT_CCU_DIV_MUX(dfc_lvl3, "dfc_lvl3", dfc_lvl_parents, + CRU_BASE_TYPE_APMU, APMU_DFC_LEVEL3, 14, 2, 8, 1, 0); +static SPACEMIT_CCU_DIV_MUX(dfc_lvl4, "dfc_lvl4", dfc_lvl_parents, + CRU_BASE_TYPE_APMU, APMU_DFC_LEVEL4, 14, 2, 8, 1, 0); +static SPACEMIT_CCU_DIV_MUX(dfc_lvl5, "dfc_lvl5", dfc_lvl_parents, + CRU_BASE_TYPE_APMU, APMU_DFC_LEVEL5, 14, 2, 8, 1, 0); +static SPACEMIT_CCU_DIV_MUX(dfc_lvl6, "dfc_lvl6", dfc_lvl_parents, + CRU_BASE_TYPE_APMU, APMU_DFC_LEVEL6, 14, 2, 8, 1, 0); +static SPACEMIT_CCU_DIV_MUX(dfc_lvl7, "dfc_lvl7", dfc_lvl_parents, + CRU_BASE_TYPE_APMU, APMU_DFC_LEVEL7, 14, 2, 8, 1, 0); +static const char *const ddr_clk_parents[] = +{ + "dfc_lvl0", "dfc_lvl1", "dfc_lvl2", "dfc_lvl3", "dfc_lvl4", "dfc_lvl5", "dfc_lvl6", "dfc_lvl7" +}; +static SPACEMIT_CCU_DDR_FC(ddr, "ddr", ddr_clk_parents, + CRU_BASE_TYPE_APMU, APMU_DFC_AP, RT_BIT(0), 1, 3, 0); + +/* MPMU */ +static const struct ccu_ddn_info uart_ddn_mask_info = +{ + .factor = 2, + .num_mask = 0x1fff, + .den_mask = 0x1fff, + .num_shift = 16, + .den_shift = 0, +}; +static struct ccu_ddn_tbl slow_uart1_tbl[] = +{ + { .num = 125, .den = 24 }, /* rate = parent_rate * 24/125/2) */ +}; +static struct ccu_ddn_tbl slow_uart2_tbl[] = +{ + { .num = 6144, .den = 960 }, /* rate = parent_rate * 960/6144/2) */ +}; + +static SPACEMIT_CCU_GATE_NO_PARENT(slow_uart, "slow_uart", RT_NULL, + CRU_BASE_TYPE_MPMU, MPMU_ACGR, RT_BIT(1), RT_BIT(1), 0x0, 0); +static SPACEMIT_CCU_DDN(slow_uart1_14p74, "slow_uart1_14p74", "pll1_d16_153p6", + &uart_ddn_mask_info, &slow_uart1_tbl, RT_ARRAY_SIZE(slow_uart1_tbl), + CRU_BASE_TYPE_MPMU, MPMU_SUCCR, RT_CLK_F_IGNORE_UNUSED); +static SPACEMIT_CCU_DDN(slow_uart2_48, "slow_uart2_48", "pll1_d4_614p4", + &uart_ddn_mask_info, &slow_uart2_tbl, RT_ARRAY_SIZE(slow_uart2_tbl), + CRU_BASE_TYPE_MPMU, MPMU_SUCCR_1, RT_CLK_F_IGNORE_UNUSED); + +/* rate = parent_rate * den / num / 2) */ +static struct ccu_ddn_info mn_ddn_mask_info = +{ + .factor = 2, + .num_mask = 0x1fff, + .den_mask = 0x1fff, + .num_shift = 16, + .den_shift = 0, +}; + +/* parent_rate = 614400000Hz */ +static struct ccu_ddn_tbl mn_tbl[] = +{ + { .num = 6144, .den = 120 * 2 }, + { .num = 6144, .den = 200 * 2 }, + { .num = 6144, .den = 240 * 2 }, + { .num = 6144, .den = 250 * 2 }, + { .num = 6144, .den = 260 * 2 }, + { .num = 6144, .den = 270 * 2 }, + { .num = 6144, .den = 300 * 2 }, + { .num = 6144, .den = 480 * 2 }, +}; + +static const char *const mn_parent_names[] = +{ + "vctcxo_24", "pll1_d4_614p4" +}; + +static SPACEMIT_CCU_MUX_GATE(mn_src_clk, "mn_src_clk", mn_parent_names, + CRU_BASE_TYPE_MPMU, MPMU_PM_MN, 1, 1, RT_BIT(0), RT_BIT(0), 0x0, 0); + +static SPACEMIT_CCU_DDN(mn_clk, "mn_clk", "mn_src_clk", + &mn_ddn_mask_info, &mn_tbl, RT_ARRAY_SIZE(mn_tbl), CRU_BASE_TYPE_MPMU, MPMU_PM_MN_GPCR, 0); + +/* parent_rate = 600000000Hz */ +static struct ccu_ddn_tbl mn2_tbl[] = +{ + {.num = 6000, .den = 120 * 2}, + {.num = 6000, .den = 200 * 2}, + {.num = 6000, .den = 240 * 2}, + {.num = 6000, .den = 250 * 2}, + {.num = 6000, .den = 260 * 2}, + {.num = 6000, .den = 270 * 2}, + {.num = 6000, .den = 300 * 2}, + {.num = 6000, .den = 480 * 2}, +}; + +static const char *const mn2_parent_names[] = +{ + "vctcxo_24", "pll2_d5" +}; + +static SPACEMIT_CCU_MUX_GATE(mn2_src_clk, "mn2_src_clk", mn2_parent_names, + CRU_BASE_TYPE_MPMU, MPMU_PM_MN, 5, 1, RT_BIT(4), RT_BIT(4), 0x0, 0); + +static SPACEMIT_CCU_DDN(mn2_clk, "mn2_clk", "mn2_src_clk", + &mn_ddn_mask_info, &mn2_tbl, RT_ARRAY_SIZE(mn2_tbl), CRU_BASE_TYPE_MPMU, MPMU_PM_MN_GPCR2, 0); + +/* APBC */ +static const char *const uart_parent_names[] = +{ + "pll1_m3d128_57p6", "slow_uart1_14p74", "slow_uart2_48" +}; +static SPACEMIT_CCU_MUX_GATE(uart1_clk, "uart1_clk", uart_parent_names, + CRU_BASE_TYPE_APBC, APBC_UART1_CLK_RST, 4, 3, 0x3, 0x3, 0x0, 0); +static SPACEMIT_CCU_MUX_GATE(uart2_clk, "uart2_clk", uart_parent_names, + CRU_BASE_TYPE_APBC, APBC_UART2_CLK_RST, 4, 3, 0x3, 0x3, 0x0, 0); +static SPACEMIT_CCU_MUX_GATE(uart3_clk, "uart3_clk", uart_parent_names, + CRU_BASE_TYPE_APBC, APBC_UART3_CLK_RST, 4, 3, 0x3, 0x3, 0x0, 0); +static SPACEMIT_CCU_MUX_GATE(uart4_clk, "uart4_clk", uart_parent_names, + CRU_BASE_TYPE_APBC, APBC_UART4_CLK_RST, 4, 3, 0x3, 0x3, 0x0, 0); +static SPACEMIT_CCU_MUX_GATE(uart5_clk, "uart5_clk", uart_parent_names, + CRU_BASE_TYPE_APBC, APBC_UART5_CLK_RST, 4, 3, 0x3, 0x3, 0x0, 0); +static SPACEMIT_CCU_MUX_GATE(uart6_clk, "uart6_clk", uart_parent_names, + CRU_BASE_TYPE_APBC, APBC_UART6_CLK_RST, 4, 3, 0x3, 0x3, 0x0, 0); +static SPACEMIT_CCU_MUX_GATE(uart7_clk, "uart7_clk", uart_parent_names, + CRU_BASE_TYPE_APBC, APBC_UART7_CLK_RST, 4, 3, 0x3, 0x3, 0x0, 0); +static SPACEMIT_CCU_MUX_GATE(uart8_clk, "uart8_clk", uart_parent_names, + CRU_BASE_TYPE_APBC, APBC_UART8_CLK_RST, 4, 3, 0x3, 0x3, 0x0, 0); +static SPACEMIT_CCU_MUX_GATE(uart9_clk, "uart9_clk", uart_parent_names, + CRU_BASE_TYPE_APBC, APBC_UART9_CLK_RST, 4, 3, 0x3, 0x3, 0x0, 0); +static SPACEMIT_CCU_GATE(gpio_clk, "gpio_clk", "vctcxo_24", + CRU_BASE_TYPE_APBC, APBC_GPIO_CLK_RST, 0x3, 0x3, 0x0, 0); +static const char *pwm_parent_names[] = +{ + "pll1_d192_12p8", "clk_32k" +}; +static SPACEMIT_CCU_MUX_GATE(pwm0_clk, "pwm0_clk", pwm_parent_names, + CRU_BASE_TYPE_APBC, APBC_PWM0_CLK_RST, 4, 3, 0x2, 0x2, 0x0, 0); +static SPACEMIT_CCU_MUX_GATE(pwm1_clk, "pwm1_clk", pwm_parent_names, + CRU_BASE_TYPE_APBC, APBC_PWM1_CLK_RST, 4, 3, 0x2, 0x2, 0x0, 0); +static SPACEMIT_CCU_MUX_GATE(pwm2_clk, "pwm2_clk", pwm_parent_names, + CRU_BASE_TYPE_APBC, APBC_PWM2_CLK_RST, 4, 3, 0x2, 0x2, 0x0, 0); +static SPACEMIT_CCU_MUX_GATE(pwm3_clk, "pwm3_clk", pwm_parent_names, + CRU_BASE_TYPE_APBC, APBC_PWM3_CLK_RST, 4, 3, 0x2, 0x2, 0x0, 0); +static SPACEMIT_CCU_MUX_GATE(pwm4_clk, "pwm4_clk", pwm_parent_names, + CRU_BASE_TYPE_APBC, APBC_PWM4_CLK_RST, 4, 3, 0x2, 0x2, 0x0, 0); +static SPACEMIT_CCU_MUX_GATE(pwm5_clk, "pwm5_clk", pwm_parent_names, + CRU_BASE_TYPE_APBC, APBC_PWM5_CLK_RST, 4, 3, 0x2, 0x2, 0x0, 0); +static SPACEMIT_CCU_MUX_GATE(pwm6_clk, "pwm6_clk", pwm_parent_names, + CRU_BASE_TYPE_APBC, APBC_PWM6_CLK_RST, 4, 3, 0x2, 0x2, 0x0, 0); +static SPACEMIT_CCU_MUX_GATE(pwm7_clk, "pwm7_clk", pwm_parent_names, + CRU_BASE_TYPE_APBC, APBC_PWM7_CLK_RST, 4, 3, 0x2, 0x2, 0x0, 0); +static SPACEMIT_CCU_MUX_GATE(pwm8_clk, "pwm8_clk", pwm_parent_names, + CRU_BASE_TYPE_APBC, APBC_PWM8_CLK_RST, 4, 3, 0x2, 0x2, 0x0, 0); +static SPACEMIT_CCU_MUX_GATE(pwm9_clk, "pwm9_clk", pwm_parent_names, + CRU_BASE_TYPE_APBC, APBC_PWM9_CLK_RST, 4, 3, 0x2, 0x2, 0x0, 0); +static SPACEMIT_CCU_MUX_GATE(pwm10_clk, "pwm10_clk", pwm_parent_names, + CRU_BASE_TYPE_APBC, APBC_PWM10_CLK_RST, 4, 3, 0x2, 0x2, 0x0, 0); +static SPACEMIT_CCU_MUX_GATE(pwm11_clk, "pwm11_clk", pwm_parent_names, + CRU_BASE_TYPE_APBC, APBC_PWM11_CLK_RST, 4, 3, 0x2, 0x2, 0x0, 0); +static SPACEMIT_CCU_MUX_GATE(pwm12_clk, "pwm12_clk", pwm_parent_names, + CRU_BASE_TYPE_APBC, APBC_PWM12_CLK_RST, 4, 3, 0x2, 0x2, 0x0, 0); +static SPACEMIT_CCU_MUX_GATE(pwm13_clk, "pwm13_clk", pwm_parent_names, + CRU_BASE_TYPE_APBC, APBC_PWM13_CLK_RST, 4, 3, 0x2, 0x2, 0x0, 0); +static SPACEMIT_CCU_MUX_GATE(pwm14_clk, "pwm14_clk", pwm_parent_names, + CRU_BASE_TYPE_APBC, APBC_PWM14_CLK_RST, 4, 3, 0x2, 0x2, 0x0, 0); +static SPACEMIT_CCU_MUX_GATE(pwm15_clk, "pwm15_clk", pwm_parent_names, + CRU_BASE_TYPE_APBC, APBC_PWM15_CLK_RST, 4, 3, 0x2, 0x2, 0x0, 0); +static SPACEMIT_CCU_MUX_GATE(pwm16_clk, "pwm16_clk", pwm_parent_names, + CRU_BASE_TYPE_APBC, APBC_PWM16_CLK_RST, 4, 3, 0x2, 0x2, 0x0, 0); +static SPACEMIT_CCU_MUX_GATE(pwm17_clk, "pwm17_clk", pwm_parent_names, + CRU_BASE_TYPE_APBC, APBC_PWM17_CLK_RST, 4, 3, 0x2, 0x2, 0x0, 0); +static SPACEMIT_CCU_MUX_GATE(pwm18_clk, "pwm18_clk", pwm_parent_names, + CRU_BASE_TYPE_APBC, APBC_PWM18_CLK_RST, 4, 3, 0x2, 0x2, 0x0, 0); +static SPACEMIT_CCU_MUX_GATE(pwm19_clk, "pwm19_clk", pwm_parent_names, + CRU_BASE_TYPE_APBC, APBC_PWM19_CLK_RST, 4, 3, 0x2, 0x2, 0x0, 0); +static const char *ssp_parent_names[] = +{ + "pll1_d384_6p4", "pll1_d192_12p8", "pll1_d96_25p6", "pll1_d48_51p2", + "pll1_d768_3p2", "pll1_d1536_1p6", "pll1_d3072_0p8", "vctcxo_1" +}; +static SPACEMIT_CCU_MUX_GATE(ssp3_clk, "ssp3_clk", ssp_parent_names, + CRU_BASE_TYPE_APBC, APBC_SSP3_CLK_RST, 4, 3, 0x3, 0x3, 0x0, 0); +static SPACEMIT_CCU_GATE(rtc_clk, "rtc_clk", "clk_32k", + CRU_BASE_TYPE_APBC, APBC_RTC_CLK_RST, 0x83, 0x83, 0x0, 0); +static const char *twsi_parent_names[] = +{ + "pll1_d78_31p5", "pll1_d48_51p2", "pll1_d40_61p44" +}; +static SPACEMIT_CCU_MUX_GATE(twsi0_clk, "twsi0_clk", twsi_parent_names, + CRU_BASE_TYPE_APBC, APBC_TWSI0_CLK_RST, 4, 3, 0x3, 0x3, 0x0, 0); +static SPACEMIT_CCU_MUX_GATE(twsi1_clk, "twsi1_clk", twsi_parent_names, + CRU_BASE_TYPE_APBC, APBC_TWSI1_CLK_RST, 4, 3, 0x3, 0x3, 0x0, 0); +static SPACEMIT_CCU_MUX_GATE(twsi2_clk, "twsi2_clk", twsi_parent_names, + CRU_BASE_TYPE_APBC, APBC_TWSI2_CLK_RST, 4, 3, 0x3, 0x3, 0x0, 0); +static SPACEMIT_CCU_MUX_GATE(twsi4_clk, "twsi4_clk", twsi_parent_names, + CRU_BASE_TYPE_APBC, APBC_TWSI4_CLK_RST, 4, 3, 0x3, 0x3, 0x0, 0); +static SPACEMIT_CCU_MUX_GATE(twsi5_clk, "twsi5_clk", twsi_parent_names, + CRU_BASE_TYPE_APBC, APBC_TWSI5_CLK_RST, 4, 3, 0x3, 0x3, 0x0, 0); +static SPACEMIT_CCU_MUX_GATE(twsi6_clk, "twsi6_clk", twsi_parent_names, + CRU_BASE_TYPE_APBC, APBC_TWSI6_CLK_RST, 4, 3, 0x3, 0x3, 0x0, 0); +static SPACEMIT_CCU_MUX_GATE(twsi7_clk, "twsi7_clk", twsi_parent_names, + CRU_BASE_TYPE_APBC, APBC_TWSI7_CLK_RST, 4, 3, 0x3, 0x3, 0x0, 0); +static SPACEMIT_CCU_MUX_GATE(twsi8_clk, "twsi8_clk", twsi_parent_names, + CRU_BASE_TYPE_APBC, APBC_TWSI8_CLK_RST, 4, 3, 0x7, 0x3, 0x4, 0); +static const char *timer_parent_names[] = +{ + "pll1_d192_12p8", "clk_32k", "pll1_d384_6p4", "vctcxo_3", "vctcxo_1" +}; +static SPACEMIT_CCU_MUX_GATE(timers1_clk, "timers1_clk", timer_parent_names, + CRU_BASE_TYPE_APBC, APBC_TIMERS1_CLK_RST, 4, 3, 0x3, 0x3, 0x0, 0); +static SPACEMIT_CCU_MUX_GATE(timers2_clk, "timers2_clk", timer_parent_names, + CRU_BASE_TYPE_APBC, APBC_TIMERS2_CLK_RST, 4, 3, 0x3, 0x3, 0x0, 0); +static SPACEMIT_CCU_GATE(aib_clk, "aib_clk", "vctcxo_24", + CRU_BASE_TYPE_APBC, APBC_AIB_CLK_RST, 0x3, 0x3, 0x0, 0); +static SPACEMIT_CCU_GATE_NO_PARENT(onewire_clk, "onewire_clk", RT_NULL, + CRU_BASE_TYPE_APBC, APBC_ONEWIRE_CLK_RST, 0x3, 0x3, 0x0, 0); + +static SPACEMIT_CCU_GATE_FACTOR(i2s_sysclk, "i2s_sysclk", "pll1_d8_307p2", + CRU_BASE_TYPE_MPMU, MPMU_ISCCR, RT_BIT(31), RT_BIT(31), 0x0, 200, 1, 0); +static SPACEMIT_CCU_GATE_FACTOR(i2s_bclk, "i2s_bclk", "i2s_sysclk", + CRU_BASE_TYPE_MPMU, MPMU_ISCCR, RT_BIT(29), RT_BIT(29), 0x0, 1, 1, 0); +static const char *sspa_parent_names[] = +{ + "pll1_d384_6p4", "pll1_d192_12p8", "pll1_d96_25p6", + "pll1_d48_51p2", "pll1_d768_3p2", "pll1_d1536_1p6", "pll1_d3072_0p8", "i2s_bclk" +}; +static SPACEMIT_CCU_MUX_GATE(sspa0_clk, "sspa0_clk", sspa_parent_names, + CRU_BASE_TYPE_APBC, APBC_SSPA0_CLK_RST, 4, 3, 0x3, 0x3, 0x0, 0); +static SPACEMIT_CCU_MUX_GATE(sspa1_clk, "sspa1_clk", sspa_parent_names, + CRU_BASE_TYPE_APBC, APBC_SSPA1_CLK_RST, 4, 3, 0x3, 0x3, 0x0, 0); +static SPACEMIT_CCU_GATE_NO_PARENT(dro_clk, "dro_clk", RT_NULL, + CRU_BASE_TYPE_APBC, APBC_DRO_CLK_RST, 0x1, 0x1, 0x0, 0); +static SPACEMIT_CCU_GATE_NO_PARENT(ir_clk, "ir_clk", RT_NULL, + CRU_BASE_TYPE_APBC, APBC_IR_CLK_RST, 0x1, 0x1, 0x0, 0); +static SPACEMIT_CCU_GATE_NO_PARENT(tsen_clk, "tsen_clk", RT_NULL, + CRU_BASE_TYPE_APBC, APBC_TSEN_CLK_RST, 0x3, 0x3, 0x0, 0); +static SPACEMIT_CCU_GATE_NO_PARENT(ipc_ap2aud_clk, "ipc_ap2aud_clk", RT_NULL, + CRU_BASE_TYPE_APBC, APBC_IPC_AP2AUD_CLK_RST, 0x3, 0x3, 0x0, 0); +static const char *can_parent_names[] = +{ + "pll3_20", "pll3_40", "pll3_80" +}; +static SPACEMIT_CCU_MUX_GATE(can0_clk, "can0_clk", can_parent_names, + CRU_BASE_TYPE_APBC, APBC_CAN0_CLK_RST, 4, 3, RT_BIT(1), RT_BIT(1), 0x0, 0); +static SPACEMIT_CCU_GATE_NO_PARENT(can0_bus_clk, "can0_bus_clk", RT_NULL, + CRU_BASE_TYPE_APBC, APBC_CAN0_CLK_RST, RT_BIT(0), RT_BIT(0), 0x0, 0); + +/* MPMU */ +static SPACEMIT_CCU_GATE(wdt_clk, "wdt_clk", "pll1_d96_25p6", + CRU_BASE_TYPE_MPMU, MPMU_WDTPCR, 0x3, 0x3, 0x0, 0); +static SPACEMIT_CCU_GATE_NO_PARENT(ripc_clk, "ripc_clk", RT_NULL, + CRU_BASE_TYPE_MPMU, MPMU_RIPCCR, 0x3, 0x3, 0x0, 0); + +/* APMU */ +static const char *const jpg_parent_names[] = +{ + "pll1_d4_614p4", "pll1_d6_409p6", "pll1_d5_491p52", "pll1_d3_819p2", + "pll1_d2_1228p8", "pll2_d4", "pll2_d3" +}; +static SPACEMIT_CCU_DIV_FC_MUX_GATE(jpg_clk, "jpg_clk", jpg_parent_names, + CRU_BASE_TYPE_APMU, APMU_JPG_CLK_RES_CTRL, + 5, 3, RT_BIT(15), 2, 3, RT_BIT(1), RT_BIT(1), 0x0, 0); +static SPACEMIT_CCU_GATE_NO_PARENT(jpg_4kafbc_clk, "jpg_4kafbc_clk", RT_NULL, + CRU_BASE_TYPE_APMU, APMU_JPG_CLK_RES_CTRL, RT_BIT(16), RT_BIT(16), 0x0, 0); +static SPACEMIT_CCU_GATE_NO_PARENT(jpg_2kafbc_clk, "jpg_2kafbc_clk", RT_NULL, + CRU_BASE_TYPE_APMU, APMU_JPG_CLK_RES_CTRL, RT_BIT(17), RT_BIT(17), 0x0, 0); +static const char *const ccic2phy_parent_names[] = +{ + "pll1_d24_102p4", "pll1_d48_51p2_ap" +}; +static SPACEMIT_CCU_MUX_GATE(ccic2phy_clk, "ccic2phy_clk", ccic2phy_parent_names, + CRU_BASE_TYPE_APMU, APMU_CSI_CCIC2_CLK_RES_CTRL, 7, 1, RT_BIT(5), RT_BIT(5), 0x0, 0); +static const char *const ccic3phy_parent_names[] = +{ + "pll1_d24_102p4", "pll1_d48_51p2_ap" +}; +static SPACEMIT_CCU_MUX_GATE(ccic3phy_clk, "ccic3phy_clk", ccic3phy_parent_names, + CRU_BASE_TYPE_APMU, APMU_CSI_CCIC2_CLK_RES_CTRL, 31, 1, RT_BIT(30), RT_BIT(30), 0x0, 0); +static const char *const csi_parent_names[] = +{ + "pll1_d5_491p52", "pll1_d6_409p6", "pll1_d4_614p4", "pll1_d3_819p2", + "pll2_d2", "pll2_d3", "pll2_d4", "pll1_d2_1228p8" +}; +static SPACEMIT_CCU_DIV_FC_MUX_GATE(csi_clk, "csi_clk", csi_parent_names, + CRU_BASE_TYPE_APMU, APMU_CSI_CCIC2_CLK_RES_CTRL, + 20, 3, RT_BIT(15), 16, 3, RT_BIT(4), RT_BIT(4), 0x0, 0); +static const char *const camm_parent_names[] = +{ + "pll1_d8_307p2", "pll2_d5", "pll1_d6_409p6", "vctcxo_24" +}; +static SPACEMIT_CCU_DIV_MUX_GATE(camm0_clk, "camm0_clk", camm_parent_names, + CRU_BASE_TYPE_APMU, APMU_CSI_CCIC2_CLK_RES_CTRL, + 23, 4, 8, 2, RT_BIT(28), RT_BIT(28), 0x0, 0); +static SPACEMIT_CCU_DIV_MUX_GATE(camm1_clk, "camm1_clk", camm_parent_names, + CRU_BASE_TYPE_APMU, APMU_CSI_CCIC2_CLK_RES_CTRL, + 23, 4, 8, 2, RT_BIT(6), RT_BIT(6), 0x0, 0); +static SPACEMIT_CCU_DIV_MUX_GATE(camm2_clk, "camm2_clk", camm_parent_names, + CRU_BASE_TYPE_APMU, APMU_CSI_CCIC2_CLK_RES_CTRL, + 23, 4, 8, 2, RT_BIT(3), RT_BIT(3), 0x0, 0); +static const char *const isp_cpp_parent_names[] = +{ + "pll1_d8_307p2", "pll1_d6_409p6" +}; +static SPACEMIT_CCU_DIV_MUX_GATE(isp_cpp_clk, "isp_cpp_clk", isp_cpp_parent_names, + CRU_BASE_TYPE_APMU, APMU_ISP_CLK_RES_CTRL, + 24, 2, 26, 1, RT_BIT(28), RT_BIT(28), 0x0, 0); +static const char *const isp_bus_parent_names[] = +{ + "pll1_d6_409p6", "pll1_d5_491p52", "pll1_d8_307p2", "pll1_d10_245p76" +}; +static SPACEMIT_CCU_DIV_FC_MUX_GATE(isp_bus_clk, "isp_bus_clk", isp_bus_parent_names, + CRU_BASE_TYPE_APMU, APMU_ISP_CLK_RES_CTRL, + 18, 3, RT_BIT(23), 21, 2, RT_BIT(17), RT_BIT(17), 0x0, 0); +static const char *const isp_parent_names[] = +{ + "pll1_d6_409p6", "pll1_d5_491p52", "pll1_d4_614p4", "pll1_d8_307p2" +}; +static SPACEMIT_CCU_DIV_FC_MUX_GATE(isp_clk, "isp_clk", isp_parent_names, + CRU_BASE_TYPE_APMU, APMU_ISP_CLK_RES_CTRL, + 4, 3, RT_BIT(7), 8, 2, RT_BIT(1), RT_BIT(1), 0x0, 0); +static const char *const dpumclk_parent_names[] = +{ + "pll1_d6_409p6", "pll1_d5_491p52", "pll1_d4_614p4", "pll1_d8_307p2" +}; +static SPACEMIT_CCU_DIV2_FC_MUX_GATE(dpu_mclk, "dpu_mclk", dpumclk_parent_names, + CRU_BASE_TYPE_APMU, APMU_LCD_CLK_RES_CTRL1, APMU_LCD_CLK_RES_CTRL2, + 1, 4, RT_BIT(29), 5, 3, RT_BIT(0), RT_BIT(0), 0x0, 0); +static const char *const dpuesc_parent_names[] = +{ + "pll1_d48_51p2_ap", "pll1_d52_47p26", "pll1_d96_25p6", "pll1_d32_76p8" +}; +static SPACEMIT_CCU_MUX_GATE(dpu_esc_clk, "dpu_esc_clk", dpuesc_parent_names, + CRU_BASE_TYPE_APMU, APMU_LCD_CLK_RES_CTRL1, 0, 2, RT_BIT(2), RT_BIT(2), 0x0, 0); +static const char *const dpubit_parent_names[] = +{ + "pll1_d3_819p2", "pll2_d2", "pll2_d3", + "pll1_d2_1228p8", "pll2_d4", "pll2_d5", "pll2_d8", "pll2_d8" +}; +static SPACEMIT_CCU_DIV_FC_MUX_GATE(dpu_bit_clk, "dpu_bit_clk", dpubit_parent_names, + CRU_BASE_TYPE_APMU, APMU_LCD_CLK_RES_CTRL1, + 17, 3, RT_BIT(31), 20, 3, RT_BIT(16), RT_BIT(16), 0x0, 0); +static const char *const dpupx_parent_names[] = +{ + "pll1_d6_409p6", "pll1_d5_491p52", "pll1_d4_614p4", "pll1_d8_307p2", "pll2_d7", "pll2_d8" +}; +static SPACEMIT_CCU_DIV2_FC_MUX_GATE(dpu_pxclk, "dpu_pxclk", dpupx_parent_names, + CRU_BASE_TYPE_APMU, APMU_LCD_CLK_RES_CTRL1, APMU_LCD_CLK_RES_CTRL2, + 17, 4, RT_BIT(30), 21, 3, RT_BIT(16), RT_BIT(16), 0x0, 0); +static SPACEMIT_CCU_GATE_NO_PARENT(dpu_hclk, "dpu_hclk", RT_NULL, + CRU_BASE_TYPE_APMU, APMU_LCD_CLK_RES_CTRL1, RT_BIT(5), RT_BIT(5), 0x0, 0); +static const char *const dpu_spi_parent_names[] = +{ + "pll1_d8_307p2", "pll1_d6_409p6", "pll1_d10_245p76", "pll1_d11_223p4", + "pll1_d13_189", "pll1_d23_106p8", "pll2_d3", "pll2_d5" +}; +static SPACEMIT_CCU_DIV_FC_MUX_GATE(dpu_spi_clk, "dpu_spi_clk", dpu_spi_parent_names, + CRU_BASE_TYPE_APMU, APMU_LCD_SPI_CLK_RES_CTRL, + 8, 3, RT_BIT(7), 12, 3, RT_BIT(1), RT_BIT(1), 0x0, 0); +static SPACEMIT_CCU_GATE_NO_PARENT(dpu_spi_hbus_clk, "dpu_spi_hbus_clk", RT_NULL, + CRU_BASE_TYPE_APMU, APMU_LCD_SPI_CLK_RES_CTRL, RT_BIT(3), RT_BIT(3), 0x0, 0); +static SPACEMIT_CCU_GATE_NO_PARENT(dpu_spi_bus_clk, "dpu_spi_bus_clk", RT_NULL, + CRU_BASE_TYPE_APMU, APMU_LCD_SPI_CLK_RES_CTRL, RT_BIT(5), RT_BIT(5), 0x0, 0); +static SPACEMIT_CCU_GATE_NO_PARENT(dpu_spi_aclk, "dpu_spi_aclk", RT_NULL, + CRU_BASE_TYPE_APMU, APMU_LCD_SPI_CLK_RES_CTRL, RT_BIT(6), RT_BIT(6), 0x0, 0); +static const char *const v2d_parent_names[] = +{ + "pll1_d5_491p52", "pll1_d6_409p6", "pll1_d8_307p2", "pll1_d4_614p4", +}; +static SPACEMIT_CCU_DIV_FC_MUX_GATE(v2d_clk, "v2d_clk", v2d_parent_names, + CRU_BASE_TYPE_APMU, APMU_LCD_CLK_RES_CTRL1, + 9, 3, RT_BIT(28), 12, 2, RT_BIT(8), RT_BIT(8), 0x0, 0); +static const char *const ccic_4x_parent_names[] = +{ + "pll1_d5_491p52", "pll1_d6_409p6", "pll1_d4_614p4", "pll1_d3_819p2", + "pll2_d2", "pll2_d3", "pll2_d4", "pll1_d2_1228p8" +}; +static SPACEMIT_CCU_DIV_FC_MUX_GATE(ccic_4x_clk, "ccic_4x_clk", ccic_4x_parent_names, + CRU_BASE_TYPE_APMU, APMU_CCIC_CLK_RES_CTRL, + 18, 3, RT_BIT(15), 23, 2, RT_BIT(4), RT_BIT(4), 0x0, 0); +static const char *const ccic1phy_parent_names[] = +{ + "pll1_d24_102p4", "pll1_d48_51p2_ap" +}; +static SPACEMIT_CCU_MUX_GATE(ccic1phy_clk, "ccic1phy_clk", ccic1phy_parent_names, + CRU_BASE_TYPE_APMU, APMU_CCIC_CLK_RES_CTRL, 7, 1, RT_BIT(5), RT_BIT(5), 0x0, 0); +static SPACEMIT_CCU_GATE_NO_PARENT(sdh_axi_aclk, "sdh_axi_aclk", RT_NULL, + CRU_BASE_TYPE_APMU, APMU_SDH0_CLK_RES_CTRL, RT_BIT(3), RT_BIT(3), 0x0, 0); +static const char *const sdh01_parent_names[] = +{ + "pll1_d6_409p6", "pll1_d4_614p4", "pll2_d8", "pll2_d5", + "pll1_d11_223p4", "pll1_d13_189", "pll1_d23_106p8" +}; + +static SPACEMIT_CCU_DIV_FC_MUX_GATE(sdh0_clk, "sdh0_clk", sdh01_parent_names, + CRU_BASE_TYPE_APMU, APMU_SDH0_CLK_RES_CTRL, + 8, 3, RT_BIT(11), 5, 3, RT_BIT(4), RT_BIT(4), 0x0, 0); +static SPACEMIT_CCU_DIV_FC_MUX_GATE(sdh1_clk, "sdh1_clk", sdh01_parent_names, + CRU_BASE_TYPE_APMU, APMU_SDH1_CLK_RES_CTRL, + 8, 3, RT_BIT(11), 5, 3, RT_BIT(4), RT_BIT(4), 0x0, 0); +static const char *const sdh2_parent_names[] = +{ + "pll1_d6_409p6", "pll1_d4_614p4", "pll2_d8", "pll1_d3_819p2", + "pll1_d11_223p4", "pll1_d13_189", "pll1_d23_106p8" +}; + +static SPACEMIT_CCU_DIV_FC_MUX_GATE(sdh2_clk, "sdh2_clk", sdh2_parent_names, + CRU_BASE_TYPE_APMU, APMU_SDH2_CLK_RES_CTRL, + 8, 3, RT_BIT(11), 5, 3, RT_BIT(4), RT_BIT(4), 0x0, 0); +static SPACEMIT_CCU_GATE_NO_PARENT(usb_axi_clk, "usb_axi_clk", RT_NULL, + CRU_BASE_TYPE_APMU, APMU_USB_CLK_RES_CTRL, RT_BIT(1), RT_BIT(1), 0x0, 0); +static SPACEMIT_CCU_GATE_NO_PARENT(usb_p1_aclk, "usb_p1_aclk", RT_NULL, + CRU_BASE_TYPE_APMU, APMU_USB_CLK_RES_CTRL, RT_BIT(5), RT_BIT(5), 0x0, 0); +static SPACEMIT_CCU_GATE_NO_PARENT(usb30_clk, "usb30_clk", RT_NULL, + CRU_BASE_TYPE_APMU, APMU_USB_CLK_RES_CTRL, RT_BIT(8), RT_BIT(8), 0x0, 0); +static const char *const qspi_parent_names[] = +{ + "pll1_d6_409p6", "pll2_d8", "pll1_d8_307p2", "pll1_d10_245p76", + "pll1_d11_223p4", "pll1_d23_106p8", "pll1_d5_491p52", "pll1_d13_189" +}; +static SPACEMIT_CCU_DIV_MUX_GATE(qspi_clk, "qspi_clk", qspi_parent_names, + CRU_BASE_TYPE_APMU, APMU_QSPI_CLK_RES_CTRL, + 9, 3, 6, 3, RT_BIT(4), RT_BIT(4), 0x0, 0); +static SPACEMIT_CCU_GATE_NO_PARENT(qspi_bus_clk, "qspi_bus_clk", RT_NULL, + CRU_BASE_TYPE_APMU, APMU_QSPI_CLK_RES_CTRL, RT_BIT(3), RT_BIT(3), 0x0, 0); +static SPACEMIT_CCU_GATE_NO_PARENT(dma_clk, "dma_clk", RT_NULL, + CRU_BASE_TYPE_APMU, APMU_DMA_CLK_RES_CTRL, RT_BIT(3), RT_BIT(3), 0x0, 0); +static const char *const aes_parent_names[] = +{ + "pll1_d12_204p8", "pll1_d24_102p4" +}; +static SPACEMIT_CCU_MUX_GATE(aes_clk, "aes_clk", aes_parent_names, + CRU_BASE_TYPE_APMU, APMU_AES_CLK_RES_CTRL, 6, 1, RT_BIT(5), RT_BIT(5), 0x0, 0); +static const char *const vpu_parent_names[] = +{ + "pll1_d4_614p4", "pll1_d5_491p52", "pll1_d3_819p2", "pll1_d6_409p6", + "pll3_d6", "pll2_d3", "pll2_d4", "pll2_d5" +}; +static SPACEMIT_CCU_DIV_FC_MUX_GATE(vpu_clk, "vpu_clk", vpu_parent_names, + CRU_BASE_TYPE_APMU, APMU_VPU_CLK_RES_CTRL, + 13, 3, RT_BIT(21), 10, 3, RT_BIT(3), RT_BIT(3), 0x0, 0); +static const char *const gpu_parent_names[] = +{ + "pll1_d4_614p4", "pll1_d5_491p52", "pll1_d3_819p2", "pll1_d6_409p6", + "pll3_d6", "pll2_d3", "pll2_d4", "pll2_d5" +}; +static SPACEMIT_CCU_DIV_FC_MUX_GATE(gpu_clk, "gpu_clk", gpu_parent_names, + CRU_BASE_TYPE_APMU, APMU_GPU_CLK_RES_CTRL, + 12, 3, RT_BIT(15), 18, 3, RT_BIT(4), RT_BIT(4), 0x0, 0); +static const char *const emmc_parent_names[] = +{ + "pll1_d6_409p6", "pll1_d4_614p4", "pll1_d52_47p26", "pll1_d3_819p2" +}; +static SPACEMIT_CCU_DIV_FC_MUX_GATE(emmc_clk, "emmc_clk", emmc_parent_names, + CRU_BASE_TYPE_APMU, APMU_PMUA_EM_CLK_RES_CTRL, + 8, 3, RT_BIT(11), 6, 2, 0x18, 0x18, 0x0, 0); +static SPACEMIT_CCU_DIV_GATE(emmc_x_clk, "emmc_x_clk", "pll1_d2_1228p8", + CRU_BASE_TYPE_APMU, APMU_PMUA_EM_CLK_RES_CTRL, + 12, 3, RT_BIT(15), RT_BIT(15), 0x0, 0); +static const char *const audio_parent_names[] = +{ + "pll1_aud_245p7", "pll1_d8_307p2", "pll1_d6_409p6" +}; +static SPACEMIT_CCU_DIV_FC_MUX_GATE(audio_clk, "audio_clk", audio_parent_names, + CRU_BASE_TYPE_APMU, APMU_AUDIO_CLK_RES_CTRL, + 4, 3, RT_BIT(15), 7, 3, RT_BIT(12), RT_BIT(12), 0x0, 0); +static const char *const hdmi_parent_names[] = +{ + "pll1_d6_409p6", "pll1_d5_491p52", "pll1_d4_614p4", "pll1_d8_307p2" +}; +static SPACEMIT_CCU_DIV_FC_MUX_GATE(hdmi_mclk, "hdmi_mclk", hdmi_parent_names, + CRU_BASE_TYPE_APMU, APMU_HDMI_CLK_RES_CTRL, + 1, 4, RT_BIT(29), 5, 3, RT_BIT(0), RT_BIT(0), 0x0, 0); +static const char *const cci550_parent_names[] = +{ + "pll1_d5_491p52", "pll1_d4_614p4", "pll1_d3_819p2", "pll2_d3" +}; +static SPACEMIT_CCU_DIV_FC_MUX(cci550_clk, "cci550_clk", cci550_parent_names, + CRU_BASE_TYPE_APMU, APMU_CCI550_CLK_CTRL, 8, 3, RT_BIT(12), 0, 2, 0); +static const char *const pmua_aclk_parent_names[] = +{ + "pll1_d10_245p76", "pll1_d8_307p2" +}; +static SPACEMIT_CCU_DIV_FC_MUX(pmua_aclk, "pmua_aclk", pmua_aclk_parent_names, + CRU_BASE_TYPE_APMU, APMU_ACLK_CLK_CTRL, 1, 2, RT_BIT(4), 0, 1, 0); +static const char *const cpu_c0_hi_parent_names[] = +{ + "pll3_d2", "pll3_d1" +}; +static SPACEMIT_CCU_MUX(cpu_c0_hi_clk, "cpu_c0_hi_clk", cpu_c0_hi_parent_names, + CRU_BASE_TYPE_APMU, APMU_CPU_C0_CLK_CTRL, 13, 1, 0); +static const char *const cpu_c0_parent_names[] = +{ + "pll1_d4_614p4", "pll1_d3_819p2", "pll1_d6_409p6", + "pll1_d5_491p52", "pll1_d2_1228p8", "pll3_d3", "pll2_d3", "cpu_c0_hi_clk" +}; +static SPACEMIT_CCU_MUX_FC(cpu_c0_core_clk, "cpu_c0_core_clk", cpu_c0_parent_names, + CRU_BASE_TYPE_APMU, APMU_CPU_C0_CLK_CTRL, RT_BIT(12), 0, 3, 0); +static SPACEMIT_CCU_DIV(cpu_c0_ace_clk, "cpu_c0_ace_clk", "cpu_c0_core_clk", + CRU_BASE_TYPE_APMU, APMU_CPU_C0_CLK_CTRL, 6, 3, 0); +static SPACEMIT_CCU_DIV(cpu_c0_tcm_clk, "cpu_c0_tcm_clk", "cpu_c0_core_clk", + CRU_BASE_TYPE_APMU, APMU_CPU_C0_CLK_CTRL, 9, 3, 0); +static const char *const cpu_c1_hi_parent_names[] = +{ + "pll3_d2", "pll3_d1" +}; +static SPACEMIT_CCU_MUX(cpu_c1_hi_clk, "cpu_c1_hi_clk", cpu_c1_hi_parent_names, + CRU_BASE_TYPE_APMU, APMU_CPU_C1_CLK_CTRL, 13, 1, 0); +static const char *const cpu_c1_parent_names[] = +{ + "pll1_d4_614p4", "pll1_d3_819p2", "pll1_d6_409p6", + "pll1_d5_491p52", "pll1_d2_1228p8", "pll3_d3", "pll2_d3", "cpu_c1_hi_clk" +}; +static SPACEMIT_CCU_MUX_FC(cpu_c1_pclk, "cpu_c1_pclk", cpu_c1_parent_names, + CRU_BASE_TYPE_APMU, APMU_CPU_C1_CLK_CTRL, RT_BIT(12), 0, 3, 0); +static SPACEMIT_CCU_DIV(cpu_c1_ace_clk, "cpu_c1_ace_clk", "cpu_c1_pclk", + CRU_BASE_TYPE_APMU, APMU_CPU_C1_CLK_CTRL, 6, 3, 0); +static SPACEMIT_CCU_GATE_NO_PARENT(pcie0_clk, "pcie0_clk", RT_NULL, + CRU_BASE_TYPE_APMU, APMU_PCIE_CLK_RES_CTRL_0, 0x7, 0x7, 0x0, 0); +static SPACEMIT_CCU_GATE_NO_PARENT(pcie1_clk, "pcie1_clk", RT_NULL, + CRU_BASE_TYPE_APMU, APMU_PCIE_CLK_RES_CTRL_1, 0x7, 0x7, 0x0, 0); +static SPACEMIT_CCU_GATE_NO_PARENT(pcie2_clk, "pcie2_clk", RT_NULL, + CRU_BASE_TYPE_APMU, APMU_PCIE_CLK_RES_CTRL_2, 0x7, 0x7, 0x0, 0); +static SPACEMIT_CCU_GATE_NO_PARENT(emac0_bus_clk, "emac0_bus_clk", RT_NULL, + CRU_BASE_TYPE_APMU, APMU_EMAC0_CLK_RES_CTRL, RT_BIT(0), RT_BIT(0), 0x0, 0); +static SPACEMIT_CCU_GATE(emac0_ptp_clk, "emac0_ptp_clk", "pll2_d6", + CRU_BASE_TYPE_APMU, APMU_EMAC0_CLK_RES_CTRL, RT_BIT(15), RT_BIT(15), 0x0, 0); +static SPACEMIT_CCU_GATE_NO_PARENT(emac1_bus_clk, "emac1_bus_clk", RT_NULL, + CRU_BASE_TYPE_APMU, APMU_EMAC1_CLK_RES_CTRL, RT_BIT(0), RT_BIT(0), 0x0, 0); +static SPACEMIT_CCU_GATE(emac1_ptp_clk, "emac1_ptp_clk", "pll2_d6", + CRU_BASE_TYPE_APMU, APMU_EMAC1_CLK_RES_CTRL, RT_BIT(15), RT_BIT(15), 0x0, 0); + +/* APBC2 */ +static const char *const uart1_sec_parent_names[] = +{ + "pll1_m3d128_57p6", "slow_uart1_14p74", "slow_uart2_48" +}; +static SPACEMIT_CCU_MUX_GATE(uart1_sec_clk, "uart1_sec_clk", uart1_sec_parent_names, + CRU_BASE_TYPE_APBC2, APBC2_UART1_CLK_RST, 4, 3, 0x3, 0x3, 0x0, 0); + +static const char *ssp2_sec_parent_names[] = +{ + "pll1_d384_6p4", "pll1_d192_12p8", "pll1_d96_25p6", + "pll1_d48_51p2", "pll1_d768_3p2", "pll1_d1536_1p6", "pll1_d3072_0p8" +}; +static SPACEMIT_CCU_MUX_GATE(ssp2_sec_clk, "ssp2_sec_clk", ssp2_sec_parent_names, + CRU_BASE_TYPE_APBC2, APBC2_SSP2_CLK_RST, 4, 3, 0x3, 0x3, 0x0, 0); +static const char *twsi3_sec_parent_names[] = +{ + "pll1_d78_31p5", "pll1_d48_51p2", "pll1_d40_61p44" +}; +static SPACEMIT_CCU_MUX_GATE(twsi3_sec_clk, "twsi3_sec_clk", twsi3_sec_parent_names, + CRU_BASE_TYPE_APBC2, APBC2_TWSI3_CLK_RST, 4, 3, 0x3, 0x3, 0x0, 0); +static SPACEMIT_CCU_GATE(rtc_sec_clk, "rtc_sec_clk", "clk_32k", + CRU_BASE_TYPE_APBC2, APBC2_RTC_CLK_RST, 0x83, 0x83, 0x0, 0); +static const char *timer_sec_parent_names[] = +{ + "pll1_d192_12p8", "clk_32k", "pll1_d384_6p4", "vctcxo_3", "vctcxo_1" +}; +static SPACEMIT_CCU_MUX_GATE(timers0_sec_clk, "timers0_sec_clk", timer_sec_parent_names, + CRU_BASE_TYPE_APBC2, APBC2_TIMERS0_CLK_RST, 4, 3, 0x3, 0x3, 0x0, 0); +static const char *kpc_sec_parent_names[] = +{ + "pll1_d192_12p8", "clk_32k", "pll1_d384_6p4", "vctcxo_3", "vctcxo_1" +}; +static SPACEMIT_CCU_MUX_GATE(kpc_sec_clk, "kpc_sec_clk", kpc_sec_parent_names, + CRU_BASE_TYPE_APBC2, APBC2_KPC_CLK_RST, 4, 3, 0x3, 0x3, 0x0, 0); +static SPACEMIT_CCU_GATE(gpio_sec_clk, "gpio_sec_clk", "vctcxo_24", + CRU_BASE_TYPE_APBC2, APBC2_GPIO_CLK_RST, 0x3, 0x3, 0x0, 0); + +static const char *const apb_parent_names[] = +{ + "pll1_d96_25p6", "pll1_d48_51p2", "pll1_d96_25p6", "pll1_d24_102p4" +}; +static SPACEMIT_CCU_MUX(apb_clk, "apb_clk", apb_parent_names, + CRU_BASE_TYPE_MPMU, MPMU_APBCSCR, 0, 2, 0); +/* RCPU */ +static const char *rhdmi_audio_parent_names[] = +{ + "pll1_aud_24p5", "pll1_aud_245p7" +}; +static SPACEMIT_CCU_DIV_MUX_GATE(rhdmi_audio_clk, "rhdmi_audio_clk", rhdmi_audio_parent_names, + CRU_BASE_TYPE_RCPU, RCPU_HDMI_CLK_RST, 4, 11, 16, 2, 0x6, 0x6, 0x0, 0); + +static const char *rcan_parent_names[] = +{ + "pll3_20", "pll3_40", "pll3_80" +}; +static SPACEMIT_CCU_DIV_MUX_GATE(rcan_clk, "rcan_clk", rcan_parent_names, + CRU_BASE_TYPE_RCPU, RCPU_CAN_CLK_RST, 8, 11, 4, 2, RT_BIT(1), RT_BIT(1), 0x0, 0); +static SPACEMIT_CCU_GATE_NO_PARENT(rcan_bus_clk, "rcan_bus_clk", RT_NULL, + CRU_BASE_TYPE_RCPU, RCPU_CAN_CLK_RST, RT_BIT(2), RT_BIT(2), 0x0, 0); +/* RCPU2 */ +static const char *rpwm_parent_names[] = +{ + "pll1_aud_245p7", "pll1_aud_24p5" +}; +static SPACEMIT_CCU_DIV_MUX_GATE(rpwm0_clk, "rpwm0_clk", rpwm_parent_names, + CRU_BASE_TYPE_RCPU2, RCPU2_PWM0_CLK_RST, 8, 11, 4, 2, RT_BIT(1), RT_BIT(1), 0x0, 0); +static SPACEMIT_CCU_DIV_MUX_GATE(rpwm1_clk, "rpwm1_clk", rpwm_parent_names, + CRU_BASE_TYPE_RCPU2, RCPU2_PWM1_CLK_RST, 8, 11, 4, 2, RT_BIT(1), RT_BIT(1), 0x0, 0); +static SPACEMIT_CCU_DIV_MUX_GATE(rpwm2_clk, "rpwm2_clk", rpwm_parent_names, + CRU_BASE_TYPE_RCPU2, RCPU2_PWM2_CLK_RST, 8, 11, 4, 2, RT_BIT(1), RT_BIT(1), 0x0, 0); +static SPACEMIT_CCU_DIV_MUX_GATE(rpwm3_clk, "rpwm3_clk", rpwm_parent_names, + CRU_BASE_TYPE_RCPU2, RCPU2_PWM3_CLK_RST, 8, 11, 4, 2, RT_BIT(1), RT_BIT(1), 0x0, 0); +static SPACEMIT_CCU_DIV_MUX_GATE(rpwm4_clk, "rpwm4_clk", rpwm_parent_names, + CRU_BASE_TYPE_RCPU2, RCPU2_PWM4_CLK_RST, 8, 11, 4, 2, RT_BIT(1), RT_BIT(1), 0x0, 0); +static SPACEMIT_CCU_DIV_MUX_GATE(rpwm5_clk, "rpwm5_clk", rpwm_parent_names, + CRU_BASE_TYPE_RCPU2, RCPU2_PWM5_CLK_RST, 8, 11, 4, 2, RT_BIT(1), RT_BIT(1), 0x0, 0); +static SPACEMIT_CCU_DIV_MUX_GATE(rpwm6_clk, "rpwm6_clk", rpwm_parent_names, + CRU_BASE_TYPE_RCPU2, RCPU2_PWM6_CLK_RST, 8, 11, 4, 2, RT_BIT(1), RT_BIT(1), 0x0, 0); +static SPACEMIT_CCU_DIV_MUX_GATE(rpwm7_clk, "rpwm7_clk", rpwm_parent_names, + CRU_BASE_TYPE_RCPU2, RCPU2_PWM7_CLK_RST, 8, 11, 4, 2, RT_BIT(1), RT_BIT(1), 0x0, 0); +static SPACEMIT_CCU_DIV_MUX_GATE(rpwm8_clk, "rpwm8_clk", rpwm_parent_names, + CRU_BASE_TYPE_RCPU2, RCPU2_PWM8_CLK_RST, 8, 11, 4, 2, RT_BIT(1), RT_BIT(1), 0x0, 0); +static SPACEMIT_CCU_DIV_MUX_GATE(rpwm9_clk, "rpwm9_clk", rpwm_parent_names, + CRU_BASE_TYPE_RCPU2, RCPU2_PWM9_CLK_RST, 8, 11, 4, 2, RT_BIT(1), RT_BIT(1), 0x0, 0); + +static const char *ri2c_parent_names[] = +{ + "pll1_d40_61p44", "pll1_d96_25p6", "pll1_d192_12p8", "vctcxo_3" +}; +static SPACEMIT_CCU_DIV_MUX_GATE(ri2c0_clk, "ri2c0_clk", ri2c_parent_names, + CRU_BASE_TYPE_RCPU, RCPU_I2C0_CLK_RST, 8, 11, 4, 2, 0x6, 0x6, 0x0, 0); + +static const char *rssp0_parent_names[] = +{ + "pll1_d40_61p44", "pll1_d96_25p6", "pll1_d192_12p8", "vctcxo_3" +}; +static SPACEMIT_CCU_DIV_MUX_GATE(rssp0_clk, "rssp0_clk", rssp0_parent_names, + CRU_BASE_TYPE_RCPU, RCPU_SSP0_CLK_RST, 8, 11, 4, 2, 0x6, 0x6, 0x0, 0); +static SPACEMIT_CCU_GATE_NO_PARENT(rir_clk, "rir_clk", RT_NULL, + CRU_BASE_TYPE_RCPU, RCPU_IR_CLK_RST, RT_BIT(2), RT_BIT(2), 0x0, 0); +static const char *ruart0_parent_names[] = +{ + "pll1_aud_24p5", "pll1_aud_245p7", "vctcxo_24", "vctcxo_3" +}; +static SPACEMIT_CCU_DIV_MUX_GATE(ruart0_clk, "ruart0_clk", ruart0_parent_names, + CRU_BASE_TYPE_RCPU, RCPU_UART0_CLK_RST, 8, 11, 4, 2, 0x6, 0x6, 0x0, 0); +static const char *ruart1_parent_names[] = +{ + "pll1_aud_24p5", "pll1_aud_245p7", "vctcxo_24", "vctcxo_3" +}; +static SPACEMIT_CCU_DIV_MUX_GATE(ruart1_clk, "ruart1_clk", ruart1_parent_names, + CRU_BASE_TYPE_RCPU, RCPU_UART1_CLK_RST, 8, 11, 4, 2, 0x6, 0x6, 0x0, 0); + +static SPACEMIT_CCU_DIV_FLAG(audio_apb_clk, "audio_apb_clk", "audio_clk", + CRU_BASE_TYPE_AUDPMU, AUDPMU_AUDIO_BUS_CLK_CTRL, + 4, 3, CLK_DIVIDER_POWER_OF_TWO | CLK_DIVIDER_ALLOW_ZERO, 0); + +static SPACEMIT_CCU_DIV_FLAG(audio_axi_clk, "audio_axi_clk", "audio_clk", + CRU_BASE_TYPE_AUDPMU, AUDPMU_AUDIO_BUS_CLK_CTRL, + 0, 2, CLK_DIVIDER_POWER_OF_TWO | CLK_DIVIDER_ALLOW_ZERO, 0); + +static const rt_uint32_t bootup_enable_clk_table[] = +{ + CLK_PLL1_307P2, + CLK_PLL1_409P6, + CLK_PLL1_491, + CLK_PLL1_614, + CLK_PLL1_819, + CLK_PLL1_1228, + CLK_PLL1_245P76, + CLK_PLL1_51P2, + CLK_PLL1_51P2_AP, + CLK_PLL1_25P6, + CLK_PLL3_D1, + CLK_PLL3_D2, + CLK_PLL3_D3, + CLK_PLL2_D3, + CLK_APB, + CLK_PMUA_ACLK, + CLK_DMA, +}; + +static const rt_ubase_t bootup_set_rate_clk_table[] = +{ + CLK_PM_MN_SRC, 614400000, + CLK_PM_MN2_SRC, 600000000, +}; + +static struct rt_clk_cell *spacemit_k1x_ccu_cell[] = +{ + [CLK_PLL2] = &pll2.common.cell, + [CLK_PLL3] = &pll3.common.cell, + [CLK_PLL1_D2] = &pll1_d2.common.cell, + [CLK_PLL1_D3] = &pll1_d3.common.cell, + [CLK_PLL1_D4] = &pll1_d4.common.cell, + [CLK_PLL1_D5] = &pll1_d5.common.cell, + [CLK_PLL1_D6] = &pll1_d6.common.cell, + [CLK_PLL1_D7] = &pll1_d7.common.cell, + [CLK_PLL1_D8] = &pll1_d8.common.cell, + [CLK_PLL1_D11] = &pll1_d11_223p4.common.cell, + [CLK_PLL1_D13] = &pll1_d13_189.common.cell, + [CLK_PLL1_D23] = &pll1_d23_106p8.common.cell, + [CLK_PLL1_D64] = &pll1_d64_38p4.common.cell, + [CLK_PLL1_D10_AUD] = &pll1_aud_245p7.common.cell, + [CLK_PLL1_D100_AUD] = &pll1_aud_24p5.common.cell, + [CLK_PLL2_D1] = &pll2_d1.common.cell, + [CLK_PLL2_D2] = &pll2_d2.common.cell, + [CLK_PLL2_D3] = &pll2_d3.common.cell, + [CLK_PLL2_D4] = &pll2_d4.common.cell, + [CLK_PLL2_D5] = &pll2_d5.common.cell, + [CLK_PLL2_D6] = &pll2_d6.common.cell, + [CLK_PLL2_D7] = &pll2_d7.common.cell, + [CLK_PLL2_D8] = &pll2_d8.common.cell, + [CLK_PLL3_D1] = &pll3_d1.common.cell, + [CLK_PLL3_D2] = &pll3_d2.common.cell, + [CLK_PLL3_D3] = &pll3_d3.common.cell, + [CLK_PLL3_D4] = &pll3_d4.common.cell, + [CLK_PLL3_D5] = &pll3_d5.common.cell, + [CLK_PLL3_D6] = &pll3_d6.common.cell, + [CLK_PLL3_D7] = &pll3_d7.common.cell, + [CLK_PLL3_D8] = &pll3_d8.common.cell, + [CLK_PLL3_80] = &pll3_80.common.cell, + [CLK_PLL3_40] = &pll3_40.common.cell, + [CLK_PLL3_20] = &pll3_20.common.cell, + [CLK_PLL1_307P2] = &pll1_d8_307p2.common.cell, + [CLK_PLL1_76P8] = &pll1_d32_76p8.common.cell, + [CLK_PLL1_61P44] = &pll1_d40_61p44.common.cell, + [CLK_PLL1_153P6] = &pll1_d16_153p6.common.cell, + [CLK_PLL1_102P4] = &pll1_d24_102p4.common.cell, + [CLK_PLL1_51P2] = &pll1_d48_51p2.common.cell, + [CLK_PLL1_51P2_AP] = &pll1_d48_51p2_ap.common.cell, + [CLK_PLL1_57P6] = &pll1_m3d128_57p6.common.cell, + [CLK_PLL1_25P6] = &pll1_d96_25p6.common.cell, + [CLK_PLL1_12P8] = &pll1_d192_12p8.common.cell, + [CLK_PLL1_12P8_WDT] = &pll1_d192_12p8_wdt.common.cell, + [CLK_PLL1_6P4] = &pll1_d384_6p4.common.cell, + [CLK_PLL1_3P2] = &pll1_d768_3p2.common.cell, + [CLK_PLL1_1P6] = &pll1_d1536_1p6.common.cell, + [CLK_PLL1_0P8] = &pll1_d3072_0p8.common.cell, + [CLK_PLL1_351] = &pll1_d7_351p08.common.cell, + [CLK_PLL1_409P6] = &pll1_d6_409p6.common.cell, + [CLK_PLL1_204P8] = &pll1_d12_204p8.common.cell, + [CLK_PLL1_491] = &pll1_d5_491p52.common.cell, + [CLK_PLL1_245P76] = &pll1_d10_245p76.common.cell, + [CLK_PLL1_614] = &pll1_d4_614p4.common.cell, + [CLK_PLL1_47P26] = &pll1_d52_47p26.common.cell, + [CLK_PLL1_31P5] = &pll1_d78_31p5.common.cell, + [CLK_PLL1_819] = &pll1_d3_819p2.common.cell, + [CLK_PLL1_1228] = &pll1_d2_1228p8.common.cell, + [CLK_SLOW_UART1] = &slow_uart1_14p74.common.cell, + [CLK_SLOW_UART2] = &slow_uart2_48.common.cell, + [CLK_UART1] = &uart1_clk.common.cell, + [CLK_UART2] = &uart2_clk.common.cell, + [CLK_UART3] = &uart3_clk.common.cell, + [CLK_UART4] = &uart4_clk.common.cell, + [CLK_UART5] = &uart5_clk.common.cell, + [CLK_UART6] = &uart6_clk.common.cell, + [CLK_UART7] = &uart7_clk.common.cell, + [CLK_UART8] = &uart8_clk.common.cell, + [CLK_UART9] = &uart9_clk.common.cell, + [CLK_GPIO] = &gpio_clk.common.cell, + [CLK_PWM0] = &pwm0_clk.common.cell, + [CLK_PWM1] = &pwm1_clk.common.cell, + [CLK_PWM2] = &pwm2_clk.common.cell, + [CLK_PWM3] = &pwm3_clk.common.cell, + [CLK_PWM4] = &pwm4_clk.common.cell, + [CLK_PWM5] = &pwm5_clk.common.cell, + [CLK_PWM6] = &pwm6_clk.common.cell, + [CLK_PWM7] = &pwm7_clk.common.cell, + [CLK_PWM8] = &pwm8_clk.common.cell, + [CLK_PWM9] = &pwm9_clk.common.cell, + [CLK_PWM10] = &pwm10_clk.common.cell, + [CLK_PWM11] = &pwm11_clk.common.cell, + [CLK_PWM12] = &pwm12_clk.common.cell, + [CLK_PWM13] = &pwm13_clk.common.cell, + [CLK_PWM14] = &pwm14_clk.common.cell, + [CLK_PWM15] = &pwm15_clk.common.cell, + [CLK_PWM16] = &pwm16_clk.common.cell, + [CLK_PWM17] = &pwm17_clk.common.cell, + [CLK_PWM18] = &pwm18_clk.common.cell, + [CLK_PWM19] = &pwm19_clk.common.cell, + [CLK_SSP3] = &ssp3_clk.common.cell, + [CLK_RTC] = &rtc_clk.common.cell, + [CLK_TWSI0] = &twsi0_clk.common.cell, + [CLK_TWSI1] = &twsi1_clk.common.cell, + [CLK_TWSI2] = &twsi2_clk.common.cell, + [CLK_TWSI4] = &twsi4_clk.common.cell, + [CLK_TWSI5] = &twsi5_clk.common.cell, + [CLK_TWSI6] = &twsi6_clk.common.cell, + [CLK_TWSI7] = &twsi7_clk.common.cell, + [CLK_TWSI8] = &twsi8_clk.common.cell, + [CLK_TIMERS1] = &timers1_clk.common.cell, + [CLK_TIMERS2] = &timers2_clk.common.cell, + [CLK_AIB] = &aib_clk.common.cell, + [CLK_ONEWIRE] = &onewire_clk.common.cell, + [CLK_SSPA0] = &sspa0_clk.common.cell, + [CLK_SSPA1] = &sspa1_clk.common.cell, + [CLK_DRO] = &dro_clk.common.cell, + [CLK_IR] = &ir_clk.common.cell, + [CLK_TSEN] = &tsen_clk.common.cell, + [CLK_IPC_AP2AUD] = &ipc_ap2aud_clk.common.cell, + [CLK_CAN0] = &can0_clk.common.cell, + [CLK_CAN0_BUS] = &can0_bus_clk.common.cell, + [CLK_WDT] = &wdt_clk.common.cell, + [CLK_RIPC] = &ripc_clk.common.cell, + [CLK_JPG] = &jpg_clk.common.cell, + [CLK_JPF_4KAFBC] = &jpg_4kafbc_clk.common.cell, + [CLK_JPF_2KAFBC] = &jpg_2kafbc_clk.common.cell, + [CLK_CCIC2PHY] = &ccic2phy_clk.common.cell, + [CLK_CCIC3PHY] = &ccic3phy_clk.common.cell, + [CLK_CSI] = &csi_clk.common.cell, + [CLK_CAMM0] = &camm0_clk.common.cell, + [CLK_CAMM1] = &camm1_clk.common.cell, + [CLK_CAMM2] = &camm2_clk.common.cell, + [CLK_ISP_CPP] = &isp_cpp_clk.common.cell, + [CLK_ISP_BUS] = &isp_bus_clk.common.cell, + [CLK_ISP] = &isp_clk.common.cell, + [CLK_DPU_MCLK] = &dpu_mclk.common.cell, + [CLK_DPU_ESC] = &dpu_esc_clk.common.cell, + [CLK_DPU_BIT] = &dpu_bit_clk.common.cell, + [CLK_DPU_PXCLK] = &dpu_pxclk.common.cell, + [CLK_DPU_HCLK] = &dpu_hclk.common.cell, + [CLK_DPU_SPI] = &dpu_spi_clk.common.cell, + [CLK_DPU_SPI_HBUS] = &dpu_spi_hbus_clk.common.cell, + [CLK_DPU_SPIBUS] = &dpu_spi_bus_clk.common.cell, + [CLK_SPU_SPI_ACLK] = &dpu_spi_aclk.common.cell, + [CLK_V2D] = &v2d_clk.common.cell, + [CLK_CCIC_4X] = &ccic_4x_clk.common.cell, + [CLK_CCIC1PHY] = &ccic1phy_clk.common.cell, + [CLK_SDH_AXI] = &sdh_axi_aclk.common.cell, + [CLK_SDH0] = &sdh0_clk.common.cell, + [CLK_SDH1] = &sdh1_clk.common.cell, + [CLK_SDH2] = &sdh2_clk.common.cell, + [CLK_USB_P1] = &usb_p1_aclk.common.cell, + [CLK_USB_AXI] = &usb_axi_clk.common.cell, + [CLK_USB30] = &usb30_clk.common.cell, + [CLK_QSPI] = &qspi_clk.common.cell, + [CLK_QSPI_BUS] = &qspi_bus_clk.common.cell, + [CLK_DMA] = &dma_clk.common.cell, + [CLK_AES] = &aes_clk.common.cell, + [CLK_VPU] = &vpu_clk.common.cell, + [CLK_GPU] = &gpu_clk.common.cell, + [CLK_EMMC] = &emmc_clk.common.cell, + [CLK_EMMC_X] = &emmc_x_clk.common.cell, + [CLK_AUDIO] = &audio_clk.common.cell, + [CLK_HDMI] = &hdmi_mclk.common.cell, + [CLK_CCI550] = &cci550_clk.common.cell, + [CLK_PMUA_ACLK] = &pmua_aclk.common.cell, + [CLK_CPU_C0_HI] = &cpu_c0_hi_clk.common.cell, + [CLK_CPU_C0_CORE] = &cpu_c0_core_clk.common.cell, + [CLK_CPU_C0_ACE] = &cpu_c0_ace_clk.common.cell, + [CLK_CPU_C0_TCM] = &cpu_c0_tcm_clk.common.cell, + [CLK_CPU_C1_HI] = &cpu_c1_hi_clk.common.cell, + [CLK_CPU_C1_CORE] = &cpu_c1_pclk.common.cell, + [CLK_CPU_C1_ACE] = &cpu_c1_ace_clk.common.cell, + [CLK_PCIE0] = &pcie0_clk.common.cell, + [CLK_PCIE1] = &pcie1_clk.common.cell, + [CLK_PCIE2] = &pcie2_clk.common.cell, + [CLK_EMAC0_BUS] = &emac0_bus_clk.common.cell, + [CLK_EMAC0_PTP] = &emac0_ptp_clk.common.cell, + [CLK_EMAC1_BUS] = &emac1_bus_clk.common.cell, + [CLK_EMAC1_PTP] = &emac1_ptp_clk.common.cell, + [CLK_SEC_UART1] = &uart1_sec_clk.common.cell, + [CLK_SEC_SSP2] = &ssp2_sec_clk.common.cell, + [CLK_SEC_TWSI3] = &twsi3_sec_clk.common.cell, + [CLK_SEC_RTC] = &rtc_sec_clk.common.cell, + [CLK_SEC_TIMERS0] = &timers0_sec_clk.common.cell, + [CLK_SEC_KPC] = &kpc_sec_clk.common.cell, + [CLK_SEC_GPIO] = &gpio_sec_clk.common.cell, + [CLK_APB] = &apb_clk.common.cell, + [CLK_SLOW_UART] = &slow_uart.common.cell, + [CLK_I2S_SYSCLK] = &i2s_sysclk.common.cell, + [CLK_I2S_BCLK] = &i2s_bclk.common.cell, + [CLK_RCPU_HDMIAUDIO] = &rhdmi_audio_clk.common.cell, + [CLK_RCPU_CAN] = &rcan_clk.common.cell, + [CLK_RCPU_CAN_BUS] = &rcan_bus_clk.common.cell, + [CLK_RCPU_I2C0] = &ri2c0_clk.common.cell, + [CLK_RCPU_SSP0] = &rssp0_clk.common.cell, + [CLK_RCPU_IR] = &rir_clk.common.cell, + [CLK_RCPU_UART0] = &ruart0_clk.common.cell, + [CLK_RCPU_UART1] = &ruart1_clk.common.cell, + [CLK_DPLL1] = &dpll1.common.cell, + [CLK_DPLL2] = &dpll2.common.cell, + [CLK_DFC_LVL0] = &dfc_lvl0.common.cell, + [CLK_DFC_LVL1] = &dfc_lvl1.common.cell, + [CLK_DFC_LVL2] = &dfc_lvl2.common.cell, + [CLK_DFC_LVL3] = &dfc_lvl3.common.cell, + [CLK_DFC_LVL4] = &dfc_lvl4.common.cell, + [CLK_DFC_LVL5] = &dfc_lvl5.common.cell, + [CLK_DFC_LVL6] = &dfc_lvl6.common.cell, + [CLK_DFC_LVL7] = &dfc_lvl7.common.cell, + [CLK_DDR] = &ddr.common.cell, + [CLK_RCPU2_PWM0] = &rpwm0_clk.common.cell, + [CLK_RCPU2_PWM1] = &rpwm1_clk.common.cell, + [CLK_RCPU2_PWM2] = &rpwm2_clk.common.cell, + [CLK_RCPU2_PWM3] = &rpwm3_clk.common.cell, + [CLK_RCPU2_PWM4] = &rpwm4_clk.common.cell, + [CLK_RCPU2_PWM5] = &rpwm5_clk.common.cell, + [CLK_RCPU2_PWM6] = &rpwm6_clk.common.cell, + [CLK_RCPU2_PWM7] = &rpwm7_clk.common.cell, + [CLK_RCPU2_PWM8] = &rpwm8_clk.common.cell, + [CLK_RCPU2_PWM9] = &rpwm9_clk.common.cell, + [CLK_AUDIO_APB] = &audio_apb_clk.common.cell, + [CLK_AUDIO_AXI] = &audio_axi_clk.common.cell, + [CLK_PM_MN_SRC] = &mn_src_clk.common.cell, + [CLK_PM_MN] = &mn_clk.common.cell, + [CLK_PM_MN2_SRC] = &mn2_src_clk.common.cell, + [CLK_PM_MN2] = &mn2_clk.common.cell, +}; + +static rt_err_t spacemit_k1x_ccu_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + int reg_count; + struct ccu_common *common; + struct rt_clk *clk; + struct rt_clk_cell *cell; + struct rt_device *dev = &pdev->parent; + struct k1x_clk *kclk = rt_calloc(1, sizeof(*kclk)); + + if (!kclk) + { + return -RT_ENOMEM; + } + + reg_count = rt_dm_dev_get_address_count(dev); + + for (int i = 0; i < reg_count; ++i) + { + kclk->mmio[i] = rt_dm_dev_iomap(dev, i); + + if (!kclk->mmio[i]) + { + err = -RT_EIO; + goto _fail; + } + } + + for (int i = 0; i < RT_ARRAY_SIZE(spacemit_k1x_ccu_cell); ++i) + { + if (!(cell = spacemit_k1x_ccu_cell[i])) + { + continue; + } + + common = cell_to_ccu_common(cell); + + common->lock = &k1_cru_lock; + + if (common->base_type < reg_count) + { + common->base = kclk->mmio[common->base_type]; + } + else + { + common->base = kclk->apbc_base; + } + + if (common->is_pll) + { + struct ccu_pll *pll = rt_container_of(common, struct ccu_pll, common); + + pll->pll.lock_base = kclk->mpmu_base; + } + } + + kclk->parent.dev = dev; + kclk->parent.cells = spacemit_k1x_ccu_cell; + kclk->parent.cells_nr = RT_ARRAY_SIZE(spacemit_k1x_ccu_cell); + + if ((err = rt_clk_register(&kclk->parent))) + { + goto _fail; + } + + /* Enable some clocks */ + for (int i = 0; i < RT_ARRAY_SIZE(bootup_enable_clk_table); ++i) + { + cell = spacemit_k1x_ccu_cell[bootup_enable_clk_table[i]]; + + if (cell && (clk = rt_clk_cell_get_clk(cell, RT_NULL))) + { + rt_clk_prepare_enable(clk); + } + } + + /* Init some clocks' rate */ + for (int i = 0; i < RT_ARRAY_SIZE(bootup_set_rate_clk_table); ++i) + { + cell = spacemit_k1x_ccu_cell[bootup_set_rate_clk_table[i++]]; + + if (cell && (clk = rt_clk_cell_get_clk(cell, RT_NULL))) + { + rt_clk_set_rate(clk, bootup_set_rate_clk_table[i]); + } + } + + return RT_EOK; + +_fail: + for (int i = 0; i < CRU_BASE_TYPE_AUDC; ++i) + { + if (kclk->mmio[i]) + { + rt_iounmap(kclk->mmio[i]); + } + } + + rt_free(kclk); + + return err; +} + +static const struct rt_ofw_node_id spacemit_k1x_ccu_ofw_ids[] = +{ + { .compatible = "spacemit,k1x-clock" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver spacemit_k1x_ccu_driver = +{ + .name = "clk-spacemit-k1x", + .ids = spacemit_k1x_ccu_ofw_ids, + + .probe = spacemit_k1x_ccu_probe, +}; + +static int spacemit_k1x_ccu_register(void) +{ + rt_platform_driver_register(&spacemit_k1x_ccu_driver); + + return 0; +} +INIT_SUBSYS_EXPORT(spacemit_k1x_ccu_register); diff --git a/bsp/spacemit/dm/clk/ccu.h b/bsp/spacemit/dm/clk/ccu.h new file mode 100644 index 000000000000..6aba95c70eb1 --- /dev/null +++ b/bsp/spacemit/dm/clk/ccu.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#ifndef __CCU_H__ +#define __CCU_H__ + +#include +#include + +#define CLK_DIVIDER_POWER_OF_TWO RT_BIT(1) +#define CLK_DIVIDER_ALLOW_ZERO RT_BIT(2) + +enum +{ + CLK_DIV_TYPE_1REG_NOFC_V1 = 0, + CLK_DIV_TYPE_1REG_FC_V2, + CLK_DIV_TYPE_2REG_NOFC_V3, + CLK_DIV_TYPE_2REG_FC_V4, + CLK_DIV_TYPE_1REG_FC_DIV_V5, + CLK_DIV_TYPE_1REG_FC_MUX_V6, +}; + +struct ccu_common +{ + void *base; + + rt_bool_t is_pll; + rt_uint32_t base_type; + + rt_uint32_t reg_type; + rt_uint32_t reg_ctrl; + rt_uint32_t reg_sel; + rt_uint32_t reg_xtc; + rt_uint32_t fc; + + struct rt_spinlock *lock; + + rt_ubase_t rate; + + struct rt_clk_cell cell; +}; + +#define cell_to_ccu_common(cell) rt_container_of(cell, struct ccu_common, cell); + +#endif /* __CCU_H__ */ diff --git a/bsp/spacemit/dm/clk/ccu_ddn.c b/bsp/spacemit/dm/clk/ccu_ddn.c new file mode 100644 index 000000000000..1ff0b0c38bae --- /dev/null +++ b/bsp/spacemit/dm/clk/ccu_ddn.c @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#include "ccu_ddn.h" + +#define DBG_TAG "clk.ccu.ddn" +#define DBG_LVL DBG_INFO +#include + +/* + * It is M/N clock + * + * Fout from synthesizer can be given from two equations: + * numerator/denominator = Fin / (Fout * factor) + */ + +static void ccu_ddn_disable(struct rt_clk_cell *cell) +{ + rt_uint32_t reg; + rt_ubase_t level; + struct ccu_ddn *ddn = cell_to_ccu_ddn(cell); + struct ccu_common *common = &ddn->common; + + if (!ddn->gate) + { + return; + } + + level = rt_spin_lock_irqsave(common->lock); + + reg = HWREG32(common->base + common->reg_sel); + HWREG32(common->base + common->reg_sel) = reg & ~ddn->gate; + + rt_spin_unlock_irqrestore(common->lock, level); +} + +static rt_err_t ccu_ddn_enable(struct rt_clk_cell *cell) +{ + rt_uint32_t reg; + rt_ubase_t level; + struct ccu_ddn *ddn = cell_to_ccu_ddn(cell); + struct ccu_common *common = &ddn->common; + + if (!ddn->gate) + { + return RT_EOK; + } + + level = rt_spin_lock_irqsave(common->lock); + + reg = HWREG32(common->base + common->reg_sel); + HWREG32(common->base + common->reg_sel) = reg | ddn->gate; + + rt_spin_unlock_irqrestore(common->lock, level); + + return RT_EOK; +} + +static rt_bool_t ccu_ddn_is_enabled(struct rt_clk_cell *cell) +{ + struct ccu_ddn *ddn = cell_to_ccu_ddn(cell); + struct ccu_common *common = &ddn->common; + + if (!ddn->gate) + { + return RT_TRUE; + } + + return HWREG32(common->base + common->reg_sel) & ddn->gate; +} + +static rt_ubase_t ccu_ddn_recalc_rate(struct rt_clk_cell *cell, rt_ubase_t parent_rate) +{ + rt_ubase_t rate; + rt_uint32_t val, num, den; + struct ccu_ddn *ddn = cell_to_ccu_ddn(cell); + struct ccu_ddn_config *params = &ddn->ddn; + + val = HWREG32(ddn->common.base + ddn->common.reg_ctrl); + + /* Calculate numerator */ + num = (val >> params->info->num_shift) & params->info->num_mask; + + /* Calculate denominator */ + den = (val >> params->info->den_shift) & params->info->den_mask; + + if (!den) + { + return 0; + } + + rate = (((parent_rate / 10000) * den) / (num * params->info->factor)) * 10000; + + return rate; +} + +static rt_base_t ccu_ddn_round_rate(struct rt_clk_cell *cell, rt_ubase_t drate, rt_ubase_t *prate) +{ + int i; + rt_ubase_t result, rate = 0, prev_rate; + struct ccu_ddn *ddn = cell_to_ccu_ddn(cell); + struct ccu_ddn_config *params = &ddn->ddn; + + for (i = 0; i < params->tbl_size; ++i) + { + prev_rate = rate; + rate = (((*prate / 10000) * params->tbl[i].den) / + (params->tbl[i].num * params->info->factor)) * 10000; + + if (rate > drate) + { + break; + } + } + + if (i == 0 || i == params->tbl_size) + { + result = rate; + } + else + { + if (drate - prev_rate > rate - drate) + { + result = rate; + } + else + { + result = prev_rate; + } + } + + return result; +} + +/* Configures new clock rate */ +static rt_err_t ccu_ddn_set_rate(struct rt_clk_cell *cell, rt_ubase_t drate, rt_ubase_t prate) +{ + int i; + rt_ubase_t val, rate = 0, level; + struct ccu_ddn *ddn = cell_to_ccu_ddn(cell); + struct ccu_common *common = &ddn->common; + struct ccu_ddn_config *params = &ddn->ddn; + + for (i = 0; i < params->tbl_size; ++i) + { + rate = (((prate / 10000) * params->tbl[i].den) / + (params->tbl[i].num * params->info->factor)) * 10000; + + if (rate > drate) + { + break; + } + } + + if (i > 0) + { + --i; + } + + if (ddn->common.lock) + { + level = rt_spin_lock_irqsave(common->lock); + } + + val = HWREG32(ddn->common.base + ddn->common.reg_ctrl); + + val &= ~(params->info->num_mask << params->info->num_shift); + val |= (params->tbl[i].num & params->info->num_mask) << params->info->num_shift; + + val &= ~(params->info->den_mask << params->info->den_shift); + val |= (params->tbl[i].den & params->info->den_mask) << params->info->den_shift; + + HWREG32(ddn->common.base + ddn->common.reg_ctrl) = val; + + if (ddn->common.lock) + { + rt_spin_unlock_irqrestore(common->lock, level); + } + + return RT_EOK; +} + +const struct rt_clk_ops ccu_ddn_ops = +{ + .disable = ccu_ddn_disable, + .enable = ccu_ddn_enable, + .is_enabled = ccu_ddn_is_enabled, + .recalc_rate = ccu_ddn_recalc_rate, + .round_rate = ccu_ddn_round_rate, + .set_rate = ccu_ddn_set_rate, +}; diff --git a/bsp/spacemit/dm/clk/ccu_ddn.h b/bsp/spacemit/dm/clk/ccu_ddn.h new file mode 100644 index 000000000000..c0f5a7f755b7 --- /dev/null +++ b/bsp/spacemit/dm/clk/ccu_ddn.h @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#ifndef __CCU_DDN_H__ +#define __CCU_DDN_H__ + +#include "ccu.h" + +struct ccu_ddn_tbl +{ + rt_uint32_t num; + rt_uint32_t den; +}; + +struct ccu_ddn_info +{ + rt_uint32_t factor; + rt_uint32_t num_mask; + rt_uint32_t den_mask; + rt_uint32_t num_shift; + rt_uint32_t den_shift; +}; + +struct ccu_ddn_config +{ + rt_uint32_t tbl_size; + struct ccu_ddn_tbl *tbl; + struct ccu_ddn_info *info; +}; + +struct ccu_ddn +{ + struct ccu_common common; + struct ccu_ddn_config ddn; + rt_uint32_t gate; +}; + +#define PLL_DDN_TBL(_num, _den) \ +{ \ + .num = (_num), \ + .den = (_den), \ +} + +#define _SPACEMIT_CCU_DDN_CONFIG(_info, _table, _size) \ +{ \ + .info = (struct ccu_ddn_info *)_info, \ + .tbl = (struct ccu_ddn_tbl *)_table, \ + .tbl_size = _size, \ +} + +#define SPACEMIT_CCU_DDN(_struct, _name, _parent, _info, _table, \ + _size, _base_type, _reg_ctrl, _flags) \ +struct ccu_ddn _struct = \ +{ \ + .ddn = _SPACEMIT_CCU_DDN_CONFIG(_info, _table, _size), \ + .common = \ + { \ + .reg_ctrl = _reg_ctrl, \ + .base_type = _base_type, \ + .cell.name = _name, \ + .cell.parent_name = _parent, \ + .cell.parents_nr = 1, \ + .cell.ops = &ccu_ddn_ops, \ + .cell.flags = _flags, \ + }, \ +} + +#define SPACEMIT_CCU_DDN_GATE(_struct, _name, _parent, _info, _table, _size, \ + _base_type, _reg_ddn, _reg_gate, _gate_mask, _flags) \ +struct ccu_ddn _struct = \ +{ \ + .gate = _gate_mask, \ + .ddn = _SPACEMIT_CCU_DDN_CONFIG(_info, _table, _size), \ + .common = \ + { \ + .reg_ctrl = _reg_ddn, \ + .reg_sel = _reg_gate, \ + .base_type = _base_type, \ + .cell.name = _name, \ + .cell.parent_name = _parent, \ + .cell.parents_nr = 1, \ + .cell.ops = &ccu_ddn_ops, \ + .cell.flags = _flags, \ + } \ +} + +extern const struct rt_clk_ops ccu_ddn_ops; + +rt_inline struct ccu_ddn *cell_to_ccu_ddn(struct rt_clk_cell *cell) +{ + struct ccu_common *common = cell_to_ccu_common(cell); + + return rt_container_of(common, struct ccu_ddn, common); +} + +#endif /* __CCU_DDN_H__ */ diff --git a/bsp/spacemit/dm/clk/ccu_ddr.c b/bsp/spacemit/dm/clk/ccu_ddr.c new file mode 100644 index 000000000000..4401fa5eb0f4 --- /dev/null +++ b/bsp/spacemit/dm/clk/ccu_ddr.c @@ -0,0 +1,298 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#include "ccu_ddr.h" + +#define DBG_TAG "clk.ccu.ddr" +#define DBG_LVL DBG_INFO +#include + +#define PMU_AP_IMR 0x098 +#define AP_DCLK_FC_DONE_INT_MSK RT_BIT(15) +#define DCLK_FC_DONE_INT_MSK RT_BIT(4) + +#define PMU_AP_ISR 0x0a0 +#define AP_DCLK_FC_DONE_INT_STS RT_BIT(15) +#define DCLK_FC_DONE_INT_STS RT_BIT(4) +#define AP_FC_STS RT_BIT(1) + +#define DFC_AP 0x180 +#define DFC_FREQ_LV 0x1 +#define DFC_REQ RT_BIT(0) + +#define DFC_STATUS 0x188 +#define DFC_CAUSE_SHIFT 0x7 +#define DFC_STS RT_BIT(0) + +/* Enable/disable ddr frequency change done interrupt */ +static void ccu_ddr_enable_dfc_int(struct ccu_common *common, rt_bool_t enable) +{ + rt_uint32_t val; + rt_ubase_t level; + + level = rt_spin_lock_irqsave(common->lock); + + val = HWREG32(common->base + PMU_AP_IMR); + if (enable) + { + val |= AP_DCLK_FC_DONE_INT_MSK; + } + else + { + val &= ~AP_DCLK_FC_DONE_INT_MSK; + } + HWREG32(common->base + PMU_AP_IMR) = val; + + rt_spin_unlock_irqrestore(common->lock, level); +} + +/* clear ddr frequency change done interrupt status*/ +static void ccu_ddr_clear_dfc_int_status(struct ccu_common *common) +{ + rt_uint32_t val; + rt_ubase_t level; + + level = rt_spin_lock_irqsave(common->lock); + + val = HWREG32(common->base + PMU_AP_ISR); + val &= ~(AP_DCLK_FC_DONE_INT_STS | AP_FC_STS); + HWREG32(common->base + PMU_AP_ISR) = val; + + rt_spin_unlock_irqrestore(common->lock, level); +} + +static rt_err_t ccu_ddr_wait_freq_change_done(struct ccu_common *common) +{ + int timeout = 100; + + while (--timeout) + { + rt_hw_us_delay(10); + + if (HWREG32(common->base + PMU_AP_ISR) & AP_DCLK_FC_DONE_INT_STS) + { + break; + } + } + + if (!timeout) + { + LOG_E("%s:%s timeout, can not wait dfc done interrupt", __func__, common->cell.name); + return -RT_EBUSY; + } + + return RT_EOK; +} + +static rt_err_t ccu_ddr_freq_chg(struct ccu_common *common, + struct ccu_mux_config *mux, rt_uint8_t level_no) +{ + rt_ubase_t level; + rt_uint32_t reg, timeout; + + if (level_no > MAX_FREQ_LV) + { + LOG_E("%s:%s invalid %d freq level", __func__, common->cell.name, level_no); + return -RT_EINVAL; + } + + /* Check if dfc in progress */ + timeout = 1000; + while (--timeout) + { + if (!(HWREG32(common->base + DFC_STATUS) & DFC_STS)) + { + break; + } + rt_hw_us_delay(10); + } + + if (!timeout) + { + LOG_E("%s:%s another dfc is in pregress. status: %#x", + __func__, common->cell.name, HWREG32(common->base + DFC_STATUS)); + return -RT_EBUSY; + } + + level = rt_spin_lock_irqsave(common->lock); + + reg = HWREG32(common->base + common->reg_sel); + reg &= ~RT_GENMASK(mux->width + mux->shift - 1, mux->shift); + HWREG32(common->base + common->reg_sel) = reg | (level_no << mux->shift) | common->fc; + + rt_spin_unlock_irqrestore(common->lock, level); + + timeout = 1000; + while (--timeout) + { + rt_hw_us_delay(10); + + if (!(HWREG32(common->base + DFC_STATUS) & DFC_STS)) + { + break; + } + } + + if (!timeout) + { + LOG_E("%s dfc error! status: %#x", common->cell.name, HWREG32(common->base + DFC_STATUS)); + return -RT_EBUSY; + } + + return RT_EOK; +} + +static rt_ubase_t ccu_ddr_calc_best_rate(struct rt_clk_cell *cell, + rt_ubase_t rate, rt_uint32_t *mux_val) +{ + rt_ubase_t parent_rate = 0, best_rate = 0; + struct rt_clk_cell *parent; + + for (int i = 0; i < cell->parents_nr; ++i) + { + parent = rt_clk_cell_get_parent_by_index(cell, i); + + if (!parent) + { + continue; + } + + parent_rate = rt_clk_cell_get_rate(parent); + + if (rt_abs(parent_rate - rate) < rt_abs(best_rate - rate)) + { + best_rate = parent_rate; + *mux_val = i; + } + } + + return best_rate; +} + +static rt_ubase_t ccu_ddr_recalc_rate(struct rt_clk_cell *cell, rt_ubase_t parent_rate) +{ + return parent_rate; +} + +static rt_base_t ccu_ddr_round_rate(struct rt_clk_cell *cell, rt_ubase_t drate, rt_ubase_t *prate) +{ + return drate; +} + +static rt_err_t ccu_ddr_set_rate(struct rt_clk_cell *cell, rt_ubase_t rate, rt_ubase_t parent_rate) +{ + rt_uint32_t cur_mux, mux_val = 0, reg = 0; + struct ccu_ddr *ddr = cell_to_ccu_ddr(cell); + struct ccu_common *common = &ddr->common; + struct ccu_mux_config *mux = ddr->mux ? : RT_NULL; + + if (!mux) + { + return RT_EOK; + } + + ccu_ddr_calc_best_rate(cell, rate, &mux_val); + + reg = HWREG32(common->base + common->reg_sel); + + if (mux) + { + cur_mux = reg >> mux->shift; + cur_mux &= (1 << mux->width) - 1; + + if (cur_mux != mux_val) + { + rt_clk_cell_set_parent(cell, rt_clk_cell_get_parent_by_index(cell, mux_val)); + } + } + + return RT_EOK; +} + +static rt_err_t ccu_ddr_set_parent(struct rt_clk_cell *cell, rt_uint8_t idx) +{ + rt_err_t err; + struct ccu_ddr *ddr = cell_to_ccu_ddr(cell); + struct ccu_common *common = &ddr->common; + struct ccu_mux_config *mux = ddr->mux; + + if (!mux) + { + return RT_EOK; + } + + if (mux->table) + { + idx = mux->table[idx]; + } + + /* Request change begin */ + ccu_ddr_enable_dfc_int(common, RT_TRUE); + + /* Change parent*/ + if ((err = ccu_ddr_freq_chg(common, mux, idx))) + { + LOG_E("%s:%s ddr_freq_chg fail", __func__, common->cell.name); + return err; + } + + /* Wait for frequency change done */ + if ((err = ccu_ddr_wait_freq_change_done(common))) + { + LOG_E("%s: %s timeout", __func__, "wait_freq_change_done"); + return err; + } + + ccu_ddr_clear_dfc_int_status(common); + ccu_ddr_enable_dfc_int(common, RT_FALSE); + + return RT_EOK; +} + +static rt_uint8_t ccu_ddr_get_parent(struct rt_clk_cell *cell) +{ + rt_uint32_t reg; + rt_uint8_t parent; + struct ccu_ddr *ddr = cell_to_ccu_ddr(cell); + struct ccu_common *common = &ddr->common; + struct ccu_mux_config *mux = ddr->mux; + + if (!mux) + { + return 0; + } + + reg = HWREG32(common->base + common->reg_sel); + + parent = reg >> mux->shift; + parent &= (1 << mux->width) - 1; + + if (mux->table) + { + for (int i = 0; i < common->cell.parents_nr; ++i) + { + if (mux->table[i] == parent) + { + return i; + } + } + } + + return parent; +} + +const struct rt_clk_ops ccu_ddr_ops = +{ + .recalc_rate = ccu_ddr_recalc_rate, + .round_rate = ccu_ddr_round_rate, + .set_rate = ccu_ddr_set_rate, + .set_parent = ccu_ddr_set_parent, + .get_parent = ccu_ddr_get_parent, +}; diff --git a/bsp/spacemit/dm/clk/ccu_ddr.h b/bsp/spacemit/dm/clk/ccu_ddr.h new file mode 100644 index 000000000000..f11dce6de44f --- /dev/null +++ b/bsp/spacemit/dm/clk/ccu_ddr.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#ifndef __CCU_DDR_H__ +#define __CCU_DDR_H__ + +#include "ccu.h" +#include "ccu_mix.h" + +struct ccu_ddr +{ + struct ccu_common common; + struct ccu_mux_config *mux; +}; + +#define MAX_FREQ_LV 7 /* level 0~7 */ + +#define SPACEMIT_CCU_DDR_FC(_struct, _name, _parents, _base_type, \ + _reg, _fc, _shift, _width, _flags) \ +struct ccu_ddr _struct = \ +{ \ + .mux = CCU_MUX_INIT(_shift, _width, RT_NULL), \ + .common = \ + { \ + .reg_sel = _reg, \ + .fc = _fc, \ + .base_type = _base_type, \ + .cell.name = _name, \ + .cell.parent_names = _parents, \ + .cell.parents_nr = RT_ARRAY_SIZE(_parents), \ + .cell.ops = &ccu_ddr_ops, \ + .cell.flags = _flags, \ + }, \ +} + +extern const struct rt_clk_ops ccu_ddr_ops; + +rt_inline struct ccu_ddr *cell_to_ccu_ddr(struct rt_clk_cell *cell) +{ + struct ccu_common *common = cell_to_ccu_common(cell); + + return rt_container_of(common, struct ccu_ddr, common); +} + +#endif /* __CCU_DDR_H__ */ diff --git a/bsp/spacemit/dm/clk/ccu_dpll.c b/bsp/spacemit/dm/clk/ccu_dpll.c new file mode 100644 index 000000000000..80cc0ba74060 --- /dev/null +++ b/bsp/spacemit/dm/clk/ccu_dpll.c @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#include "ccu_dpll.h" + +#define DBG_TAG "clk.ccu.dpll" +#define DBG_LVL DBG_INFO +#include + +#define DPLL_MIN_FREQ 1700000000 +#define DPLL_MAX_FREQ 3400000000 + +#define pll_readl(reg) HWREG32(reg) +#define pll_readl_pll_swcr1(p) pll_readl(p.base + p.reg_ctrl) +#define pll_readl_pll_swcr2(p) pll_readl(p.base + p.reg_sel) + +#define pll_writel(val, reg) HWREG32(reg) = val +#define pll_writel_pll_swcr1(val, p) pll_writel(val, p.base + p.reg_ctrl) +#define pll_writel_pll_swcr2(val, p) pll_writel(val, p.base + p.reg_sel) + +/* Unified dpllx_swcr1 for dpll1~2 */ +union dpllx_swcr1 +{ + struct + { + rt_uint32_t reg0:8; + rt_uint32_t reg1:8; + rt_uint32_t reg2:8; + rt_uint32_t reg3:8; + } b; + rt_uint32_t v; +}; + +/* Unified dpllx_swcr2 for dpll1~2 */ +union dpllx_swcr2 +{ + struct + { + rt_uint32_t reg4:8; + rt_uint32_t reg5:8; + rt_uint32_t reg6:8; + rt_uint32_t reg7:8; + } b; + rt_uint32_t v; +}; + +/* Frequency unit Mhz, return pll vco freq */ +static rt_ubase_t __get_vco_freq_raw(struct rt_clk_cell *cell) +{ + rt_uint32_t reg0, reg1, reg2, reg3, reg4, reg5, reg6, reg7, size; + union dpllx_swcr1 swcr1; + union dpllx_swcr2 swcr2; + struct ccu_dpll_rate_tbl *freq_pll_regs_table; + struct ccu_dpll *p = cell_to_ccu_dpll(cell); + + swcr1.v = pll_readl_pll_swcr1(p->common); + swcr2.v = pll_readl_pll_swcr2(p->common); + + reg0 = swcr1.b.reg0; + reg1 = swcr1.b.reg1; + reg2 = swcr1.b.reg2; + reg3 = swcr1.b.reg3; + reg4 = swcr2.b.reg4; + reg5 = swcr2.b.reg5; + reg6 = swcr2.b.reg6; + reg7 = swcr2.b.reg7; + + freq_pll_regs_table = p->dpll.rate_tbl; + size = p->dpll.tbl_size; + + for (int i = 0; i < size; ++i) + { + struct ccu_dpll_rate_tbl *item = &freq_pll_regs_table[i]; + + if (item->reg0 == reg0 && + item->reg1 == reg1 && + item->reg2 == reg2 && + item->reg3 == reg3 && + item->reg4 == reg4 && + item->reg5 == reg5 && + item->reg6 == reg6 && + item->reg7 == reg7) + { + return item->rate; + } + } + + LOG_E("Unknown rate for clock %s", cell->name); + + return 0; +} + +static rt_ubase_t ccu_dpll_recalc_rate(struct rt_clk_cell *cell, rt_ubase_t parent_rate) +{ + return __get_vco_freq_raw(cell); +} + +static rt_base_t ccu_dpll_round_rate(struct rt_clk_cell *cell, rt_ubase_t rate, rt_ubase_t *prate) +{ + rt_ubase_t max_rate = 0; + struct ccu_dpll *p = cell_to_ccu_dpll(cell); + struct ccu_dpll_config *params = &p->dpll; + + if (rate > DPLL_MAX_FREQ || rate < DPLL_MIN_FREQ) + { + LOG_E("%s %lu rate out of range", cell->name, rate); + return -RT_EINVAL; + } + + if (params->rate_tbl) + { + for (int i = 0; i < params->tbl_size; ++i) + { + struct ccu_dpll_rate_tbl *item = ¶ms->rate_tbl[i]; + + if (item->rate <= rate) + { + if (max_rate < item->rate) + { + max_rate = item->rate; + } + } + } + } + else + { + LOG_E("%s don't find freq table for pll", cell->name); + } + + return max_rate; +} + +const struct rt_clk_ops ccu_dpll_ops = +{ + .recalc_rate = ccu_dpll_recalc_rate, + .round_rate = ccu_dpll_round_rate, +}; diff --git a/bsp/spacemit/dm/clk/ccu_dpll.h b/bsp/spacemit/dm/clk/ccu_dpll.h new file mode 100644 index 000000000000..7fc6014e5880 --- /dev/null +++ b/bsp/spacemit/dm/clk/ccu_dpll.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#ifndef __CCU_DPLL_H__ +#define __CCU_DPLL_H__ + +#include "ccu.h" + +struct ccu_dpll_rate_tbl +{ + rt_uint64_t rate; + rt_uint32_t reg0; + rt_uint32_t reg1; + rt_uint32_t reg2; + rt_uint32_t reg3; + rt_uint32_t reg4; + rt_uint32_t reg5; + rt_uint32_t reg6; + rt_uint32_t reg7; +}; + +struct ccu_dpll_config +{ + rt_uint32_t tbl_size; + struct ccu_dpll_rate_tbl *rate_tbl; +}; + +struct ccu_dpll +{ + struct ccu_common common; + struct ccu_dpll_config dpll; +}; + +#define DPLL_RATE(_rate, _reg0, _reg1, _reg2, _reg3, _reg4, _reg5, _reg6, _reg7) \ +{ \ + .rate = (_rate), \ + .reg0 = (_reg0), \ + .reg1 = (_reg1), \ + .reg2 = (_reg2), \ + .reg3 = (_reg3), \ + .reg4 = (_reg4), \ + .reg5 = (_reg5), \ + .reg6 = (_reg6), \ + .reg7 = (_reg7), \ +} + +#define _SPACEMIT_CCU_DPLL_CONFIG(_table, _size) \ +{ \ + .rate_tbl = (struct ccu_dpll_rate_tbl *)_table, \ + .tbl_size = _size, \ +} + +#define SPACEMIT_CCU_DPLL(_struct, _name, _table, _size, \ + _base_type, _reg_ctrl, _reg_sel, _is_pll, _flags) \ +struct ccu_dpll _struct = \ +{ \ + .dpll = _SPACEMIT_CCU_DPLL_CONFIG(_table, _size), \ + .common = \ + { \ + .reg_ctrl = _reg_ctrl, \ + .reg_sel = _reg_sel, \ + .base_type = _base_type, \ + .is_pll = RT_FALSE, \ + .cell.name = _name, \ + .cell.ops = &ccu_dpll_ops, \ + .cell.flags = _flags, \ + }, \ +} + +extern const struct rt_clk_ops ccu_dpll_ops; + +rt_inline struct ccu_dpll *cell_to_ccu_dpll(struct rt_clk_cell *cell) +{ + struct ccu_common *common = cell_to_ccu_common(cell); + + return rt_container_of(common, struct ccu_dpll, common); +} + +#endif /* __CCU_DPLL_H__ */ diff --git a/bsp/spacemit/dm/clk/ccu_mix.c b/bsp/spacemit/dm/clk/ccu_mix.c new file mode 100644 index 000000000000..9cc6a85511e6 --- /dev/null +++ b/bsp/spacemit/dm/clk/ccu_mix.c @@ -0,0 +1,712 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#include "ccu_mix.h" + +#define DBG_TAG "clk.ccu.mix" +#define DBG_LVL DBG_INFO +#include + +#define TIMEOUT_LIMIT 20000 /* Max timeout 10000us */ + +static int twsi8_reg_val = 0x04; +static const char *tswi8_clk_name = "twsi8_clk"; + +static void ccu_mix_disable(struct rt_clk_cell *cell) +{ + rt_uint32_t tmp; + rt_ubase_t level, rate; + struct ccu_mix *mix = cell_to_ccu_mix(cell); + struct ccu_common *common = &mix->common; + struct ccu_gate_config *gate = mix->gate; + + if (!gate) + { + return; + } + + if (!rt_strcmp(cell->name, tswi8_clk_name)) + { + twsi8_reg_val &= ~gate->gate_mask; + twsi8_reg_val |= gate->val_disable; + tmp = twsi8_reg_val; + + if (common->reg_type == CLK_DIV_TYPE_2REG_NOFC_V3 || + common->reg_type == CLK_DIV_TYPE_2REG_FC_V4) + { + HWREG32(common->base + common->reg_sel) = tmp; + } + else + { + HWREG32(common->base + common->reg_ctrl) = tmp; + } + + return; + } + + if (common->lock) + { + level = rt_spin_lock_irqsave(common->lock); + } + + if (common->reg_type == CLK_DIV_TYPE_2REG_NOFC_V3 || + common->reg_type == CLK_DIV_TYPE_2REG_FC_V4) + { + tmp = HWREG32(common->base + common->reg_sel); + } + else + { + tmp = HWREG32(common->base + common->reg_ctrl); + } + + tmp &= ~gate->gate_mask; + tmp |= gate->val_disable; + + if (common->reg_type == CLK_DIV_TYPE_2REG_NOFC_V3 || + common->reg_type == CLK_DIV_TYPE_2REG_FC_V4) + { + HWREG32(common->base + common->reg_sel) = tmp; + } + else + { + HWREG32(common->base + common->reg_ctrl) = tmp; + } + + if (common->lock) + { + rt_spin_unlock_irqrestore(common->lock, level); + } + + if (gate->flags & SPACEMIT_CLK_GATE_NEED_DELAY) + { + rate = rt_clk_cell_get_rate(cell); + + if (rate == 0) + { + LOG_E("%s clock rate is 0", cell->name); + } + else + { + /* Need delay 2M cycles. */ + rt_hw_us_delay(RT_DIV_ROUND_UP(2000000, rate)); + } + } +} + +static rt_err_t ccu_mix_enable(struct rt_clk_cell *cell) +{ + rt_ubase_t level, rate; + rt_uint32_t tmp, val = 0, timeout_power = 1; + struct ccu_mix *mix = cell_to_ccu_mix(cell); + struct ccu_common *common = &mix->common; + struct ccu_gate_config *gate = mix->gate; + + if (!gate) + { + return RT_EOK; + } + + if (!rt_strcmp(cell->name, tswi8_clk_name)) + { + twsi8_reg_val &= ~gate->gate_mask; + twsi8_reg_val |= gate->val_enable; + tmp = twsi8_reg_val; + + if (common->reg_type == CLK_DIV_TYPE_2REG_NOFC_V3 || + common->reg_type == CLK_DIV_TYPE_2REG_FC_V4) + { + HWREG32(common->base + common->reg_sel) = tmp; + } + else + { + HWREG32(common->base + common->reg_ctrl) = tmp; + } + + return RT_EOK; + } + + if (common->lock) + { + level = rt_spin_lock_irqsave(common->lock); + } + + if (common->reg_type == CLK_DIV_TYPE_2REG_NOFC_V3 || + common->reg_type == CLK_DIV_TYPE_2REG_FC_V4) + { + tmp = HWREG32(common->base + common->reg_sel); + } + else + { + tmp = HWREG32(common->base + common->reg_ctrl); + } + + tmp &= ~gate->gate_mask; + tmp |= gate->val_enable; + + if (common->reg_type == CLK_DIV_TYPE_2REG_NOFC_V3 || + common->reg_type == CLK_DIV_TYPE_2REG_FC_V4) + { + HWREG32(common->base + common->reg_sel) = tmp; + } + else + { + HWREG32(common->base + common->reg_ctrl) = tmp; + } + + if (common->reg_type == CLK_DIV_TYPE_2REG_NOFC_V3 || + common->reg_type == CLK_DIV_TYPE_2REG_FC_V4) + { + val = HWREG32(common->base + common->reg_sel); + } + else + { + val = HWREG32(common->base + common->reg_ctrl); + } + + if (common->lock) + { + rt_spin_unlock_irqrestore(common->lock, level); + } + + while ((val & gate->gate_mask) != gate->val_enable && timeout_power < TIMEOUT_LIMIT) + { + rt_hw_us_delay(timeout_power); + + if (common->reg_type == CLK_DIV_TYPE_2REG_NOFC_V3 || + common->reg_type == CLK_DIV_TYPE_2REG_FC_V4) + { + val = HWREG32(common->base + common->reg_sel); + } + else + { + val = HWREG32(common->base + common->reg_ctrl); + } + + timeout_power *= 10; + } + + if (timeout_power > 1) + { + if (val == tmp) + { + LOG_E("%s write clk_gate timeout occur, read pass after %d us delay", + cell->name, timeout_power); + } + else + { + LOG_E("%s write clk_gate timeout after %d us", cell->name, timeout_power); + } + } + + if (gate->flags & SPACEMIT_CLK_GATE_NEED_DELAY) + { + rate = rt_clk_cell_get_rate(cell); + + if (rate == 0) + { + LOG_E("%s clock rate is 0", cell->name); + } + else + { + /* Need delay 2M cycles. */ + rt_hw_us_delay(RT_DIV_ROUND_UP(2000000, rate)); + } + } + + return RT_EOK; +} + +static rt_bool_t ccu_mix_is_enabled(struct rt_clk_cell *cell) +{ + rt_uint32_t tmp; + rt_ubase_t level; + struct ccu_mix *mix = cell_to_ccu_mix(cell); + struct ccu_common *common = &mix->common; + struct ccu_gate_config *gate = mix->gate; + + if (!gate) + { + return RT_TRUE; + } + + if (!rt_strcmp(cell->name, tswi8_clk_name)) + { + return (twsi8_reg_val & gate->gate_mask) == gate->val_enable; + } + + if (common->lock) + { + level = rt_spin_lock_irqsave(common->lock); + } + + if (common->reg_type == CLK_DIV_TYPE_2REG_NOFC_V3 || + common->reg_type == CLK_DIV_TYPE_2REG_FC_V4) + { + tmp = HWREG32(common->base + common->reg_sel); + } + else + { + tmp = HWREG32(common->base + common->reg_ctrl); + } + + if (common->lock) + { + rt_spin_unlock_irqrestore(common->lock, level); + } + + return (tmp & gate->gate_mask) == gate->val_enable; +} + +static rt_ubase_t ccu_mix_recalc_rate(struct rt_clk_cell *cell, rt_ubase_t parent_rate) +{ + rt_ubase_t val; + rt_uint32_t reg, div_val = 0; + struct ccu_mix *mix = cell_to_ccu_mix(cell); + struct ccu_common *common = &mix->common; + struct ccu_div_config *div = mix->div; + struct ccu_mux_config *mux = mix->mux ? mix->mux : RT_NULL; + + if (!div) + { + if (mux && common->rate && common->rate != parent_rate) + { + parent_rate = common->rate; + } + + if (mix->factor) + { + val = parent_rate * mix->factor->mul / mix->factor->div; + } + else + { + val = parent_rate; + } + + goto _end; + } + + if (common->reg_type == CLK_DIV_TYPE_2REG_NOFC_V3 || + common->reg_type == CLK_DIV_TYPE_2REG_FC_V4) + { + reg = HWREG32(common->base + common->reg_sel); + } + else + { + reg = HWREG32(common->base + common->reg_ctrl); + } + + val = reg >> div->shift; + val &= (1 << div->width) - 1; + + if (div->clk_flags & CLK_DIVIDER_POWER_OF_TWO) + { + div_val = 1 << val; + } + else if (div->table) + { + const struct ccu_div_table *clkt; + + for (clkt = div->table; clkt->div; ++clkt) + { + if (clkt->val == val) + { + div_val = clkt->div; + break; + } + } + } + else + { + div_val = val + 1; + } + + if (!div_val) + { + val = parent_rate; + } + else + { + val = RT_DIV_ROUND_UP_ULL((rt_uint64_t)parent_rate, div_val); + } + +_end: + common->rate = val; + + return val; +} + +static rt_base_t ccu_mix_round_rate(struct rt_clk_cell *cell, rt_ubase_t drate, rt_ubase_t *prate) +{ + return drate; +} + +static rt_err_t ccu_mix_trigger_fc(struct rt_clk_cell *cell) +{ + rt_ubase_t val = 0; + rt_err_t err = RT_EOK; + rt_uint32_t timeout = 50; + struct ccu_mix *mix = cell_to_ccu_mix(cell); + struct ccu_common *common = &mix->common; + + if (common->reg_type == CLK_DIV_TYPE_1REG_FC_V2 || + common->reg_type == CLK_DIV_TYPE_2REG_FC_V4 || + common->reg_type == CLK_DIV_TYPE_1REG_FC_DIV_V5 || + common->reg_type == CLK_DIV_TYPE_1REG_FC_MUX_V6) + { + timeout = 50; + val = HWREG32(common->base + common->reg_ctrl); + val |= common->fc; + HWREG32(common->base + common->reg_ctrl) = val; + + do { + val = HWREG32(common->base + common->reg_ctrl); + --timeout; + + if (!(val & common->fc)) + { + break; + } + } while (timeout); + + if (timeout == 0) + { + timeout = 5000; + + do { + val = HWREG32(common->base + common->reg_ctrl); + --timeout; + + if (!(val & common->fc)) + { + break; + } + } while (timeout); + + if (timeout == 0) + { + err = -RT_ETIMEOUT; + } + } + } + + return err; +} + +static rt_ubase_t ccu_mix_calc_best_rate(struct rt_clk_cell *cell, + rt_ubase_t rate, rt_uint32_t *mux_val, rt_uint32_t *div_val) +{ + rt_uint32_t div_max; + rt_ubase_t parent_rate = 0, best_rate = 0; + struct rt_clk_cell *parent; + struct ccu_mix *mix = cell_to_ccu_mix(cell); + struct ccu_div_config *div = mix->div? mix->div: RT_NULL; + + for (int i = 0; i < cell->parents_nr; ++i) + { + parent = rt_clk_cell_get_parent_by_index(cell, i); + + if (!parent) + { + continue; + } + + parent_rate = rt_clk_cell_get_rate(parent); + + if (div) + { + div_max = 1 << div->width; + } + else + { + div_max = 1; + } + + for (int j = 1; j <= div_max; ++j) + { + if (div && div->clk_flags & CLK_DIVIDER_POWER_OF_TWO) + { + int d; + + if (div->clk_flags & CLK_DIVIDER_ALLOW_ZERO) + { + d = j - 1; + } + + if (rt_abs(parent_rate / RT_BIT(d) - rate) < rt_abs(best_rate - rate)) + { + best_rate = RT_DIV_ROUND_UP_ULL(parent_rate, RT_BIT(d)); + *mux_val = i; + *div_val = d; + } + + continue; + } + + if (rt_abs(parent_rate / j - rate) < rt_abs(best_rate - rate)) + { + best_rate = RT_DIV_ROUND_UP_ULL(parent_rate, j); + *mux_val = i; + *div_val = j - 1; + } + } + } + + return best_rate; +} + +static rt_err_t ccu_mix_set_rate(struct rt_clk_cell *cell, rt_ubase_t rate, rt_ubase_t parent_rate) +{ + rt_err_t err = RT_EOK; + rt_ubase_t level, best_rate; + rt_uint32_t cur_mux, cur_div, mux_val = 0, div_val = 0, reg = 0; + struct ccu_mix *mix = cell_to_ccu_mix(cell); + struct ccu_common *common = &mix->common; + struct ccu_div_config *div = mix->div? mix->div: RT_NULL; + struct ccu_mux_config *mux = mix->mux? mix->mux: RT_NULL; + + if (!div && !mux) + { + return RT_EOK; + } + + best_rate = ccu_mix_calc_best_rate(cell, rate, &mux_val, &div_val); + common->rate = best_rate; + + if (!rt_strcmp(cell->name, tswi8_clk_name)) + { + if (mux) + { + cur_mux = twsi8_reg_val >> mux->shift; + cur_mux &= (1 << mux->width) - 1; + + if (cur_mux != mux_val) + { + rt_clk_cell_set_parent(cell, rt_clk_cell_get_parent_by_index(cell, mux_val)); + } + } + + return RT_EOK; + } + + if (common->reg_type == CLK_DIV_TYPE_2REG_NOFC_V3 || + common->reg_type == CLK_DIV_TYPE_2REG_FC_V4) + { + reg = HWREG32(common->base + common->reg_sel); + } + else + { + reg = HWREG32(common->base + common->reg_ctrl); + } + + if (mux) + { + cur_mux = reg >> mux->shift; + cur_mux &= (1 << mux->width) - 1; + + if (cur_mux != mux_val) + { + rt_clk_cell_set_parent(cell, rt_clk_cell_get_parent_by_index(cell, mux_val)); + } + } + + if (div) + { + cur_div = reg >> div->shift; + cur_div &= (1 << div->width) - 1; + + if (cur_div == div_val) + { + return RT_EOK; + } + } + else + { + return RT_EOK; + } + + level = rt_spin_lock_irqsave(common->lock); + + if (common->reg_type == CLK_DIV_TYPE_2REG_NOFC_V3 || + common->reg_type == CLK_DIV_TYPE_2REG_FC_V4) + { + reg = HWREG32(common->base + common->reg_sel); + } + else + { + reg = HWREG32(common->base + common->reg_ctrl); + } + + reg &= ~RT_GENMASK(div->width + div->shift - 1, div->shift); + + if (common->reg_type == CLK_DIV_TYPE_2REG_NOFC_V3 || + common->reg_type == CLK_DIV_TYPE_2REG_FC_V4) + { + HWREG32(common->base + common->reg_sel) = reg | (div_val << div->shift); + } + else + { + HWREG32(common->base + common->reg_ctrl) = reg | (div_val << div->shift); + } + + if (common->reg_type == CLK_DIV_TYPE_1REG_FC_V2 || + common->reg_type == CLK_DIV_TYPE_2REG_FC_V4 || + common->reg_type == CLK_DIV_TYPE_1REG_FC_DIV_V5) + { + err = ccu_mix_trigger_fc(cell); + } + + rt_spin_unlock_irqrestore(common->lock, level); + + if (err) + { + LOG_E("%s:%s timeout", __func__, cell->name); + } + + return RT_EOK; +} + +static rt_err_t ccu_mix_set_parent(struct rt_clk_cell *cell, rt_uint8_t idx) +{ + rt_ubase_t level; + rt_uint32_t reg = 0; + rt_err_t err = RT_EOK; + struct ccu_mix *mix = cell_to_ccu_mix(cell); + struct ccu_common *common = &mix->common; + struct ccu_mux_config *mux = mix->mux; + + if (!mux) + { + return RT_EOK; + } + + if (mux->table) + { + idx = mux->table[idx]; + } + + if (!rt_strcmp(cell->name, tswi8_clk_name)) + { + twsi8_reg_val &= ~RT_GENMASK(mux->width + mux->shift - 1, mux->shift); + twsi8_reg_val |= (idx << mux->shift); + reg = twsi8_reg_val; + + if (common->reg_type == CLK_DIV_TYPE_2REG_NOFC_V3 || + common->reg_type == CLK_DIV_TYPE_2REG_FC_V4) + { + HWREG32(common->base + common->reg_sel) = reg; + } + else + { + HWREG32(common->base + common->reg_ctrl) = reg; + } + + return RT_EOK; + } + + level = rt_spin_lock_irqsave(common->lock); + + if (common->reg_type == CLK_DIV_TYPE_2REG_NOFC_V3 || + common->reg_type == CLK_DIV_TYPE_2REG_FC_V4) + { + reg = HWREG32(common->base + common->reg_sel); + } + else + { + reg = HWREG32(common->base + common->reg_ctrl); + } + + reg &= ~RT_GENMASK(mux->width + mux->shift - 1, mux->shift); + + if (common->reg_type == CLK_DIV_TYPE_2REG_NOFC_V3 || + common->reg_type == CLK_DIV_TYPE_2REG_FC_V4) + { + HWREG32(common->base + common->reg_sel) = reg | (idx << mux->shift); + } + else + { + HWREG32(common->base + common->reg_ctrl) = reg | (idx << mux->shift); + } + + if (common->reg_type == CLK_DIV_TYPE_1REG_FC_V2 || + common->reg_type == CLK_DIV_TYPE_2REG_FC_V4 || + common->reg_type == CLK_DIV_TYPE_1REG_FC_MUX_V6) + { + err = ccu_mix_trigger_fc(cell); + } + + rt_spin_unlock_irqrestore(common->lock, level); + + if (err) + { + LOG_E("%s:%s timeout", __func__, cell->name); + } + + return RT_EOK; +} + +static rt_uint8_t ccu_mix_get_parent(struct rt_clk_cell *cell) +{ + rt_uint32_t reg; + rt_uint8_t parent; + struct ccu_mix *mix = cell_to_ccu_mix(cell); + struct ccu_common *common = &mix->common; + struct ccu_mux_config *mux = mix->mux; + + if (!mux) + { + return 0; + } + + if (!rt_strcmp(cell->name, tswi8_clk_name)) + { + parent = twsi8_reg_val >> mux->shift; + parent &= (1 << mux->width) - 1; + + return parent; + } + + if (common->reg_type == CLK_DIV_TYPE_2REG_NOFC_V3 || + common->reg_type == CLK_DIV_TYPE_2REG_FC_V4) + { + reg = HWREG32(common->base + common->reg_sel); + } + else + { + reg = HWREG32(common->base + common->reg_ctrl); + } + + parent = reg >> mux->shift; + parent &= (1 << mux->width) - 1; + + if (mux->table) + { + for (int i = 0; i < cell->parents_nr; ++i) + { + if (mux->table[i] == parent) + { + return i; + } + } + } + + return parent; +} + +const struct rt_clk_ops ccu_mix_ops = +{ + .disable = ccu_mix_disable, + .enable = ccu_mix_enable, + .is_enabled = ccu_mix_is_enabled, + .recalc_rate = ccu_mix_recalc_rate, + .round_rate = ccu_mix_round_rate, + .set_rate = ccu_mix_set_rate, + .set_parent = ccu_mix_set_parent, + .get_parent = ccu_mix_get_parent, +}; diff --git a/bsp/spacemit/dm/clk/ccu_mix.h b/bsp/spacemit/dm/clk/ccu_mix.h new file mode 100644 index 000000000000..88c0c9cacc2d --- /dev/null +++ b/bsp/spacemit/dm/clk/ccu_mix.h @@ -0,0 +1,422 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#ifndef __CCU_MIX_H__ +#define __CCU_MIX_H__ + +#include "ccu.h" + +struct ccu_gate_config +{ + rt_uint32_t gate_mask; + rt_uint32_t val_enable; + rt_uint32_t val_disable; +#define SPACEMIT_CLK_GATE_NEED_DELAY RT_BIT(0) + rt_uint32_t flags; +}; + +struct ccu_factor_config +{ + rt_uint32_t div; + rt_uint32_t mul; +}; + +struct ccu_mux_config +{ + rt_uint8_t shift; + rt_uint8_t width; + const rt_uint8_t *table; +}; + +struct ccu_div_table +{ + rt_uint32_t val; + rt_uint32_t div; +}; + +struct ccu_div_config +{ + rt_uint8_t shift; + rt_uint8_t width; + rt_uint32_t max; + rt_uint32_t offset; + rt_uint32_t clk_flags; + struct ccu_div_table *table; +}; + +struct ccu_mix +{ + struct ccu_common common; + struct ccu_gate_config *gate; + struct ccu_factor_config *factor; + struct ccu_div_config *div; + struct ccu_mux_config *mux; +}; + +#define CCU_GATE_INIT(_gate_mask, _val_enable, _val_disable, _flags) \ +(&(struct ccu_gate_config) \ +{ \ + .gate_mask = _gate_mask, \ + .val_enable = _val_enable, \ + .val_disable = _val_disable, \ + .flags = _flags, \ +}) + +#define CCU_FACTOR_INIT(_div, _mul) \ +(&(struct ccu_factor_config)\ +{ \ + .div = _div, \ + .mul = _mul, \ +}) + +#define CCU_MUX_INIT(_shift, _width, _table) \ +(&(struct ccu_mux_config) \ +{ \ + .shift = _shift, \ + .width = _width, \ + .table = _table, \ +}) + +#define CCU_DIV_INIT(_shift, _width, _table, _clk_flags) \ +(&(struct ccu_div_config) \ +{ \ + .shift = _shift, \ + .width = _width, \ + .table = _table, \ + .clk_flags = _clk_flags, \ +}) + +#define SPACEMIT_CCU_GATE(_struct, _name, _parent, _base_type, _reg, \ + _gate_mask, _val_enable, _val_disable, _flags) \ +struct ccu_mix _struct = \ +{ \ + .gate = CCU_GATE_INIT(_gate_mask, _val_enable, _val_disable, 0), \ + .common = \ + { \ + .reg_ctrl = _reg, \ + .base_type = _base_type, \ + .cell.name = _name, \ + .cell.parent_name = _parent, \ + .cell.parents_nr = 1, \ + .cell.ops = &ccu_mix_ops, \ + .cell.flags = _flags, \ + }, \ +} + +#define SPACEMIT_CCU_GATE_NO_PARENT(_struct, _name, _parent, _base_type, _reg, \ + _gate_mask, _val_enable, _val_disable, _flags) \ +struct ccu_mix _struct = \ +{ \ + .gate = CCU_GATE_INIT(_gate_mask, _val_enable, _val_disable, 0), \ + .common = \ + { \ + .reg_ctrl = _reg, \ + .base_type = _base_type, \ + .cell.name = _name, \ + .cell.parent_name = _parent, \ + .cell.parents_nr = 1, \ + .cell.ops = &ccu_mix_ops, \ + .cell.flags = _flags, \ + }, \ +} + +#define SPACEMIT_CCU_FACTOR(_struct, _name, _parent, _div, _mul) \ +struct ccu_mix _struct = \ +{ \ + .factor = CCU_FACTOR_INIT(_div, _mul), \ + .common = \ + { \ + .cell.name = _name, \ + .cell.parent_name = _parent, \ + .cell.parents_nr = 1, \ + .cell.ops = &ccu_mix_ops, \ + }, \ +} + +#define SPACEMIT_CCU_MUX(_struct, _name, _parents, _base_type, _reg, \ + _shift, _width, _flags) \ +struct ccu_mix _struct = \ +{ \ + .mux = CCU_MUX_INIT(_shift, _width, RT_NULL),\ + .common = \ + { \ + .reg_ctrl = _reg, \ + .base_type = _base_type, \ + .cell.name = _name, \ + .cell.parent_names = _parents, \ + .cell.parents_nr = RT_ARRAY_SIZE(_parents), \ + .cell.ops = &ccu_mix_ops, \ + .cell.flags = _flags, \ + } \ +} + +#define SPACEMIT_CCU_DIV(_struct, _name, _parent, _base_type, _reg, \ + _shift, _width, _flags) \ +struct ccu_mix _struct = \ +{ \ + .div = CCU_DIV_INIT(_shift, _width, RT_NULL, 0), \ + .common = \ + { \ + .reg_ctrl = _reg, \ + .base_type = _base_type, \ + .cell.name = _name, \ + .cell.parent_name = _parent, \ + .cell.parents_nr = 1, \ + .cell.ops = &ccu_mix_ops, \ + .cell.flags = _flags, \ + } \ +} + +#define SPACEMIT_CCU_DIV_FLAG(_struct, _name, _parent, _base_type, _reg, \ + _shift, _width, _div_flags, _flags) \ +struct ccu_mix _struct = \ +{ \ + .div = CCU_DIV_INIT(_shift, _width, RT_NULL, _div_flags), \ + .common = \ + { \ + .reg_ctrl = _reg, \ + .base_type = _base_type, \ + .cell.name = _name, \ + .cell.parent_name = _parent, \ + .cell.parents_nr = 1, \ + .cell.ops = &ccu_mix_ops, \ + .cell.flags = _flags, \ + } \ +} + +#define SPACEMIT_CCU_GATE_FACTOR(_struct, _name, _parent, _base_type, _reg, \ + _gate_mask, _val_enable, _val_disable, _div, _mul, _flags) \ +struct ccu_mix _struct = \ +{ \ + .gate = CCU_GATE_INIT(_gate_mask, _val_enable, _val_disable, 0), \ + .factor = CCU_FACTOR_INIT(_div, _mul), \ + .common = \ + { \ + .reg_ctrl = _reg, \ + .base_type = _base_type, \ + .cell.name = _name, \ + .cell.parent_name = _parent, \ + .cell.parents_nr = 1, \ + .cell.ops = &ccu_mix_ops, \ + .cell.flags = _flags, \ + } \ +} + +#define SPACEMIT_CCU_MUX_GATE(_struct, _name, _parents, _base_type, _reg, \ + _shift, _width, _gate_mask, _val_enable, _val_disable, _flags) \ +struct ccu_mix _struct = \ +{ \ + .gate = CCU_GATE_INIT(_gate_mask, _val_enable, _val_disable, 0), \ + .mux = CCU_MUX_INIT(_shift, _width, RT_NULL), \ + .common = \ + { \ + .reg_ctrl = _reg, \ + .base_type = _base_type, \ + .cell.name = _name, \ + .cell.parent_names = _parents, \ + .cell.parents_nr = RT_ARRAY_SIZE(_parents), \ + .cell.ops = &ccu_mix_ops, \ + .cell.flags = _flags, \ + } \ +} + +#define SPACEMIT_CCU_DIV_GATE(_struct, _name, _parent, _base_type, _reg, \ + _shift, _width, _gate_mask, _val_enable, _val_disable, _flags) \ +struct ccu_mix _struct = \ +{ \ + .gate = CCU_GATE_INIT(_gate_mask, _val_enable, _val_disable, 0), \ + .div = CCU_DIV_INIT(_shift, _width, RT_NULL, 0), \ + .common = \ + { \ + .reg_ctrl = _reg, \ + .base_type = _base_type, \ + .cell.name = _name, \ + .cell.parent_name = _parent, \ + .cell.parents_nr = 1, \ + .cell.ops = &ccu_mix_ops, \ + .cell.flags = _flags, \ + } \ +} + +#define SPACEMIT_CCU_DIV_MUX_GATE(_struct, _name, _parents, _base_type, _reg_ctrl, \ + _mshift, _mwidth, _muxshift, _muxwidth, \ + _gate_mask, _val_enable, _val_disable, _flags) \ +struct ccu_mix _struct = \ +{ \ + .gate = CCU_GATE_INIT(_gate_mask, _val_enable, _val_disable, 0), \ + .div = CCU_DIV_INIT(_mshift, _mwidth, RT_NULL, 0), \ + .mux = CCU_MUX_INIT(_muxshift, _muxwidth, RT_NULL), \ + .common = \ + { \ + .reg_ctrl = _reg_ctrl, \ + .base_type = _base_type, \ + .cell.name = _name, \ + .cell.parent_names = _parents, \ + .cell.parents_nr = RT_ARRAY_SIZE(_parents), \ + .cell.ops = &ccu_mix_ops, \ + .cell.flags = _flags, \ + }, \ +} + +#define SPACEMIT_CCU_DIV2_FC_MUX_GATE(_struct, _name, _parents, _base_type, _reg_ctrl, _reg_sel, \ + _mshift, _mwidth, _fc, _muxshift, _muxwidth, _gate_mask, \ + _val_enable, _val_disable, _flags) \ +struct ccu_mix _struct = \ +{ \ + .gate = CCU_GATE_INIT(_gate_mask, _val_enable, _val_disable, 0), \ + .div = CCU_DIV_INIT(_mshift, _mwidth, RT_NULL, 0), \ + .mux = CCU_MUX_INIT(_muxshift, _muxwidth, RT_NULL), \ + .common = \ + { \ + .reg_type = CLK_DIV_TYPE_2REG_FC_V4, \ + .reg_ctrl = _reg_ctrl, \ + .reg_sel = _reg_sel, \ + .fc = _fc, \ + .base_type = _base_type, \ + .cell.name = _name, \ + .cell.parent_names = _parents, \ + .cell.parents_nr = RT_ARRAY_SIZE(_parents), \ + .cell.ops = &ccu_mix_ops, \ + .cell.flags = _flags, \ + }, \ +} + + +#define SPACEMIT_CCU_DIV_FC_MUX_GATE(_struct, _name, _parents, _base_type, _reg_ctrl, \ + _mshift, _mwidth, _fc, _muxshift, _muxwidth, _gate_mask, \ + _val_enable, _val_disable, _flags) \ +struct ccu_mix _struct = \ +{ \ + .gate = CCU_GATE_INIT(_gate_mask, _val_enable, _val_disable, 0), \ + .div = CCU_DIV_INIT(_mshift, _mwidth, RT_NULL, 0), \ + .mux = CCU_MUX_INIT(_muxshift, _muxwidth, RT_NULL), \ + .common = \ + { \ + .reg_type = CLK_DIV_TYPE_1REG_FC_V2, \ + .reg_ctrl = _reg_ctrl, \ + .fc = _fc, \ + .base_type = _base_type, \ + .cell.name = _name, \ + .cell.parent_names = _parents, \ + .cell.parents_nr = RT_ARRAY_SIZE(_parents), \ + .cell.ops = &ccu_mix_ops, \ + .cell.flags = _flags, \ + }, \ +} + +#define SPACEMIT_CCU_DIV_MFC_MUX_GATE(_struct, _name, _parents, _base_type, _reg_ctrl, \ + _mshift, _mwidth, _fc, _muxshift, _muxwidth, _gate_mask, \ + _val_enable, _val_disable, _flags) \ +struct ccu_mix _struct = \ +{ \ + .gate = CCU_GATE_INIT(_gate_mask, _val_enable, _val_disable, 0), \ + .div = CCU_DIV_INIT(_mshift, _mwidth, RT_NULL, 0), \ + .mux = CCU_MUX_INIT(_muxshift, _muxwidth, RT_NULL), \ + .common = \ + { \ + .reg_type = CLK_DIV_TYPE_1REG_FC_MUX_V6, \ + .reg_ctrl = _reg_ctrl, \ + .fc = _fc, \ + .base_type = _base_type, \ + .cell.name = _name, \ + .cell.parent_names = _parents, \ + .cell.parents_nr = RT_ARRAY_SIZE(_parents), \ + .cell.ops = &ccu_mix_ops, \ + .cell.flags = _flags, \ + }, \ +} + +#define SPACEMIT_CCU_DIV_FC_WITH_GATE(_struct, _name, _parent, _base_type, _reg_ctrl, \ + _mshift, _mwidth, _fc, _gate_mask, _val_enable, _val_disable, _flags) \ +struct ccu_mix _struct = \ +{ \ + .gate = CCU_GATE_INIT(_gate_mask, _val_enable, _val_disable, 0), \ + .div = CCU_DIV_INIT(_mshift, _mwidth, RT_NULL, 0), \ + .common = \ + { \ + .reg_type = CLK_DIV_TYPE_1REG_FC_V2, \ + .reg_ctrl = _reg_ctrl, \ + .fc = _fc, \ + .base_type = _base_type, \ + .cell.name = _name, \ + .cell.parent_name = _parent, \ + .cell.parents_nr = 1, \ + .cell.ops = &ccu_mix_ops, \ + .cell.flags = _flags, \ + }, \ +} + +#define SPACEMIT_CCU_DIV_MUX(_struct, _name, _parents, _base_type, _reg_ctrl, \ + _mshift, _mwidth, _muxshift, _muxwidth, _flags) \ +struct ccu_mix _struct = \ +{ \ + .div = CCU_DIV_INIT(_mshift, _mwidth, RT_NULL, 0), \ + .mux = CCU_MUX_INIT(_muxshift, _muxwidth, RT_NULL), \ + .common = \ + { \ + .reg_ctrl = _reg_ctrl, \ + .base_type = _base_type, \ + .cell.name = _name, \ + .cell.parent_names = _parents, \ + .cell.parents_nr = RT_ARRAY_SIZE(_parents), \ + .cell.ops = &ccu_mix_ops, \ + .cell.flags = _flags, \ + }, \ +} + +#define SPACEMIT_CCU_DIV_FC_MUX(_struct, _name, _parents, _base_type, _reg_ctrl, \ + _mshift, _mwidth, _fc, _muxshift, _muxwidth, _flags) \ +struct ccu_mix _struct = \ +{ \ + .div = CCU_DIV_INIT(_mshift, _mwidth, RT_NULL, 0), \ + .mux = CCU_MUX_INIT(_muxshift, _muxwidth, RT_NULL), \ + .common = \ + { \ + .reg_type = CLK_DIV_TYPE_1REG_FC_V2, \ + .reg_ctrl = _reg_ctrl, \ + .fc = _fc, \ + .base_type = _base_type, \ + .cell.name = _name, \ + .cell.parent_names = _parents, \ + .cell.parents_nr = RT_ARRAY_SIZE(_parents), \ + .cell.ops = &ccu_mix_ops, \ + .cell.flags = _flags, \ + }, \ +} + +#define SPACEMIT_CCU_MUX_FC(_struct, _name, _parents, _base_type, _reg_ctrl, \ + _fc, _muxshift, _muxwidth, _flags) \ +struct ccu_mix _struct = \ +{ \ + .mux = CCU_MUX_INIT(_muxshift, _muxwidth, RT_NULL), \ + .common = \ + { \ + .reg_type = CLK_DIV_TYPE_1REG_FC_V2, \ + .reg_ctrl = _reg_ctrl, \ + .fc = _fc, \ + .base_type = _base_type, \ + .cell.name = _name, \ + .cell.parent_names = _parents, \ + .cell.parents_nr = RT_ARRAY_SIZE(_parents), \ + .cell.ops = &ccu_mix_ops, \ + .cell.flags = _flags, \ + }, \ +} + +extern const struct rt_clk_ops ccu_mix_ops; + +rt_inline struct ccu_mix *cell_to_ccu_mix(struct rt_clk_cell *cell) +{ + struct ccu_common *common = cell_to_ccu_common(cell); + + return rt_container_of(common, struct ccu_mix, common); +} + +#endif /* __CCU_MIX_H__ */ diff --git a/bsp/spacemit/dm/clk/ccu_pll.c b/bsp/spacemit/dm/clk/ccu_pll.c new file mode 100644 index 000000000000..a1b0270fb3ca --- /dev/null +++ b/bsp/spacemit/dm/clk/ccu_pll.c @@ -0,0 +1,321 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#include "ccu_pll.h" + +#define DBG_TAG "clk.ccu.pll" +#define DBG_LVL DBG_INFO +#include + +#define PLL_MIN_FREQ 600000000 +#define PLL_MAX_FREQ 3400000000 +#define PLL_DELAYTIME 590 /* 590 * 5us */ + +#define pll_readl(reg) HWREG32(reg) +#define pll_readl_pll_swcr1(p) pll_readl(p.base + p.reg_ctrl) +#define pll_readl_pll_swcr2(p) pll_readl(p.base + p.reg_sel) +#define pll_readl_pll_swcr3(p) pll_readl(p.base + p.reg_xtc) + +#define pll_writel(val, reg) HWREG32(reg) = val; +#define pll_writel_pll_swcr1(val, p) pll_writel(val, p.base + p.reg_ctrl) +#define pll_writel_pll_swcr2(val, p) pll_writel(val, p.base + p.reg_sel) +#define pll_writel_pll_swcr3(val, p) pll_writel(val, p.base + p.reg_xtc) + +/* Unified pllx_swcr1 for pll1~3 */ +union pllx_swcr1 +{ + struct + { + rt_uint32_t reg5:8; + rt_uint32_t reg6:8; + rt_uint32_t reg7:8; + rt_uint32_t reg8:8; + } b; + rt_uint32_t v; +}; + +/* Unified pllx_swcr2 for pll1~3 */ +union pllx_swcr2 +{ + struct + { + rt_uint32_t div1_en:1; + rt_uint32_t div2_en:1; + rt_uint32_t div3_en:1; + rt_uint32_t div4_en:1; + rt_uint32_t div5_en:1; + rt_uint32_t div6_en:1; + rt_uint32_t div7_en:1; + rt_uint32_t div8_en:1; + rt_uint32_t reserved1:4; + rt_uint32_t atest_en:1; + rt_uint32_t cktest_en:1; + rt_uint32_t dtest_en:1; + rt_uint32_t rdo:2; + rt_uint32_t mon_cfg:4; + rt_uint32_t reserved2:11; + } b; + rt_uint32_t v; +}; + +/* Unified pllx_swcr3 for pll1~3 */ +union pllx_swcr3 +{ + struct + { + rt_uint32_t div_frc:24; + rt_uint32_t div_int:7; + rt_uint32_t pll_en:1; + } b; + rt_uint32_t v; +}; + +static rt_bool_t ccu_pll_is_enabled(struct rt_clk_cell *cell) +{ + rt_bool_t enabled; + union pllx_swcr3 swcr3; + struct ccu_pll *p = cell_to_ccu_pll(cell); + + swcr3.v = pll_readl_pll_swcr3(p->common); + enabled = !!swcr3.b.pll_en; + + return enabled; +} + +/* Frequency unit Mhz, return pll vco freq */ +static rt_ubase_t __get_vco_freq(struct rt_clk_cell *cell) +{ + rt_uint32_t div_int, div_frc, reg5, reg6, reg7, reg8, size; + union pllx_swcr1 swcr1; + union pllx_swcr3 swcr3; + struct ccu_pll_rate_tbl *freq_pll_regs_table; + struct ccu_pll *p = cell_to_ccu_pll(cell); + + swcr1.v = pll_readl_pll_swcr1(p->common); + swcr3.v = pll_readl_pll_swcr3(p->common); + + reg5 = swcr1.b.reg5; + reg6 = swcr1.b.reg6; + reg7 = swcr1.b.reg7; + reg8 = swcr1.b.reg8; + + div_int = swcr3.b.div_int; + div_frc = swcr3.b.div_frc; + + freq_pll_regs_table = p->pll.rate_tbl; + size = p->pll.tbl_size; + + for (int i = 0; i < size; ++i) + { + struct ccu_pll_rate_tbl *item = &freq_pll_regs_table[i]; + + if (item->reg5 == reg5 && item->reg6 == reg6 && + item->reg7 == reg7 && item->reg8 == reg8 && + item->div_int == div_int && item->div_frac == div_frc) + { + return item->rate; + } + } + + LOG_E("Unknown rate for clock %s", cell->name); + + return 0; +} + +static rt_err_t ccu_pll_enable(struct rt_clk_cell *cell) +{ + rt_ubase_t level; + rt_uint32_t delaytime = PLL_DELAYTIME; + union pllx_swcr3 swcr3; + struct ccu_pll *p = cell_to_ccu_pll(cell); + + if (ccu_pll_is_enabled(cell)) + { + return RT_EOK; + } + + level = rt_spin_lock_irqsave(p->common.lock); + + swcr3.v = pll_readl_pll_swcr3(p->common); + swcr3.b.pll_en = 1; + pll_writel_pll_swcr3(swcr3.v, p->common); + + rt_spin_unlock_irqrestore(p->common.lock, level); + + /* Check lock status */ + rt_hw_us_delay(50); + + while ((!(HWREG32(p->pll.lock_base + p->pll.reg_lock) & p->pll.lock_enable_bit)) && delaytime) + { + rt_hw_us_delay(5); + --delaytime; + } + + if (!delaytime) + { + LOG_E("%s enabling didn't get stable within 3000us", cell->name); + } + + return RT_EOK; +} + +static void ccu_pll_disable(struct rt_clk_cell *cell) +{ + rt_ubase_t level; + union pllx_swcr3 swcr3; + struct ccu_pll *p = cell_to_ccu_pll(cell); + + level = rt_spin_lock_irqsave(p->common.lock); + + swcr3.v = pll_readl_pll_swcr3(p->common); + swcr3.b.pll_en = 0; + pll_writel_pll_swcr3(swcr3.v, p->common); + + rt_spin_unlock_irqrestore(p->common.lock, level); +} + +static rt_ubase_t ccu_pll_recalc_rate(struct rt_clk_cell *cell, rt_ubase_t parent_rate) +{ + return __get_vco_freq(cell); +} + +static rt_base_t ccu_pll_round_rate(struct rt_clk_cell *cell, rt_ubase_t drate, rt_ubase_t *prate) +{ + rt_ubase_t max_rate = 0; + struct ccu_pll *p = cell_to_ccu_pll(cell); + struct ccu_pll_config *params = &p->pll; + + if (drate > PLL_MAX_FREQ || drate < PLL_MIN_FREQ) + { + LOG_E("%s %lu rate out of range", cell->name, drate); + return -RT_EINVAL; + } + + if (params->rate_tbl) + { + for (int i = 0; i < params->tbl_size; ++i) + { + struct ccu_pll_rate_tbl *item = ¶ms->rate_tbl[i]; + + if (item->rate <= drate) + { + if (max_rate < item->rate) + { + max_rate = item->rate; + } + } + } + } + else + { + LOG_E("%s don't find freq table for pll", cell->name); + } + + return max_rate; +} + +/* + * PLL rate change requires sequence: + * clock off -> change rate setting -> clock on + * This function doesn't really change rate, but cache the config + */ +static rt_err_t ccu_pll_set_rate(struct rt_clk_cell *cell, rt_ubase_t rate, rt_ubase_t parent_rate) +{ + rt_uint32_t div_int, div_frc, reg5 = 0, reg6 = 0, reg7 = 0, reg8 = 0; + rt_bool_t found = RT_FALSE, pll_enabled = RT_FALSE; + rt_ubase_t level; + union pllx_swcr1 swcr1; + union pllx_swcr3 swcr3; + struct ccu_pll *p = cell_to_ccu_pll(cell); + struct ccu_pll_config *params = &p->pll; + + if (ccu_pll_is_enabled(cell)) + { + pll_enabled = RT_TRUE; + ccu_pll_disable(cell); + } + + __get_vco_freq(cell); + + /* Setp 1: calculate fbd frcd kvco and band */ + if (params->rate_tbl) + { + for (int i = 0; i < params->tbl_size; ++i) + { + struct ccu_pll_rate_tbl *item = ¶ms->rate_tbl[i]; + + if (rate == item->rate) + { + found = RT_TRUE; + + reg5 = item->reg5; + reg6 = item->reg6; + reg7 = item->reg7; + reg8 = item->reg8; + div_int = item->div_int; + div_frc = item->div_frac; + + break; + } + } + + if (!found) + { + return -RT_EINVAL; + } + } + else + { + LOG_E("%s don't find freq table for pll", cell->name); + + if (pll_enabled) + { + ccu_pll_enable(cell); + } + + return -RT_EINVAL; + } + + level = rt_spin_lock_irqsave(p->common.lock); + + /* Setp 2: set pll kvco/band and fbd/frcd setting */ + swcr1.v = pll_readl_pll_swcr1(p->common); + swcr1.b.reg5 = reg5; + swcr1.b.reg6 = reg6; + swcr1.b.reg7 = reg7; + swcr1.b.reg8 = reg8; + pll_writel_pll_swcr1(swcr1.v, p->common); + + swcr3.v = pll_readl_pll_swcr3(p->common); + swcr3.b.div_int = div_int; + swcr3.b.div_frc = div_frc; + pll_writel_pll_swcr3(swcr3.v, p->common); + + rt_spin_unlock_irqrestore(p->common.lock, level); + + if (pll_enabled) + { + ccu_pll_enable(cell); + } + + LOG_D("%s: %s rate %lu->%lu", __func__, clk->name, old_rate, new_rate); + + return RT_EOK; +} + +const struct rt_clk_ops ccu_pll_ops = +{ + .enable = ccu_pll_enable, + .disable = ccu_pll_disable, + .is_enabled = ccu_pll_is_enabled, + .recalc_rate = ccu_pll_recalc_rate, + .round_rate = ccu_pll_round_rate, + .set_rate = ccu_pll_set_rate, +}; diff --git a/bsp/spacemit/dm/clk/ccu_pll.h b/bsp/spacemit/dm/clk/ccu_pll.h new file mode 100644 index 000000000000..531a9363198e --- /dev/null +++ b/bsp/spacemit/dm/clk/ccu_pll.h @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#ifndef __CCU_PLL_H__ +#define __CCU_PLL_H__ + +#include "ccu.h" + +struct ccu_pll_rate_tbl +{ + rt_uint64_t rate; + rt_uint32_t reg5; + rt_uint32_t reg6; + rt_uint32_t reg7; + rt_uint32_t reg8; + rt_uint32_t div_int; + rt_uint32_t div_frac; +}; + +struct ccu_pll_config +{ + rt_uint32_t tbl_size; + struct ccu_pll_rate_tbl *rate_tbl; + + void *lock_base; + rt_uint32_t reg_lock; + rt_uint32_t lock_enable_bit; +}; + +struct ccu_pll +{ + struct ccu_common common; + struct ccu_pll_config pll; +}; + +#define PLL_RATE(_rate, _reg5, _reg6, _reg7, _reg8, _div_int, _div_frac) \ +{ \ + .rate = (_rate), \ + .reg5 = (_reg5), \ + .reg6 = (_reg6), \ + .reg7 = (_reg7), \ + .reg8 = (_reg8), \ + .div_int = (_div_int), \ + .div_frac = (_div_frac), \ +} + +#define _SPACEMIT_CCU_PLL_CONFIG(_table, _size, _reg_lock, _lock_enable_bit) \ +{ \ + .rate_tbl = (struct ccu_pll_rate_tbl *)_table, \ + .tbl_size = _size, \ + .reg_lock = _reg_lock, \ + .lock_enable_bit = _lock_enable_bit, \ +} + +#define SPACEMIT_CCU_PLL(_struct, _name, _table, _size, _base_type, \ + _reg_ctrl, _reg_sel, _reg_xtc, \ + _reg_lock, _lock_enable_bit, _is_pll, _flags) \ +struct ccu_pll _struct = \ +{ \ + .pll = _SPACEMIT_CCU_PLL_CONFIG(_table, _size, _reg_lock, _lock_enable_bit), \ + .common = \ + { \ + .reg_ctrl = _reg_ctrl, \ + .reg_sel = _reg_sel, \ + .reg_xtc = _reg_xtc, \ + .base_type = _base_type, \ + .is_pll = _is_pll, \ + .cell.name = _name, \ + .cell.ops = &ccu_pll_ops, \ + .cell.flags = _flags, \ + }, \ +} + +extern const struct rt_clk_ops ccu_pll_ops; + +rt_inline struct ccu_pll *cell_to_ccu_pll(struct rt_clk_cell *cell) +{ + struct ccu_common *common = cell_to_ccu_common(cell); + + return rt_container_of(common, struct ccu_pll, common); +} + +#endif /* __CCU_PLL_H__ */ diff --git a/bsp/spacemit/dm/clock_time/Kconfig b/bsp/spacemit/dm/clock_time/Kconfig new file mode 100644 index 000000000000..aff885faa4c0 --- /dev/null +++ b/bsp/spacemit/dm/clock_time/Kconfig @@ -0,0 +1,3 @@ +config RT_CLOCK_TIME_SPACEMIT_K1X + bool "Spacemit k1x Timer" + default n diff --git a/bsp/spacemit/dm/clock_time/SConscript b/bsp/spacemit/dm/clock_time/SConscript new file mode 100644 index 000000000000..427251006439 --- /dev/null +++ b/bsp/spacemit/dm/clock_time/SConscript @@ -0,0 +1,12 @@ +from building import * + +cwd = GetCurrentDir() +src = [] +CPPPATH = [cwd + '/../include'] + +if GetDepend(['RT_CLOCK_TIME_SPACEMIT_K1X']): + src += ['clock_time-k1x.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/spacemit/dm/clock_time/clock_time-k1x.c b/bsp/spacemit/dm/clock_time/clock_time-k1x.c new file mode 100644 index 000000000000..f61f45983f1b --- /dev/null +++ b/bsp/spacemit/dm/clock_time/clock_time-k1x.c @@ -0,0 +1,667 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#include +#include +#include +#include + +#define DBG_TAG "clock_timer.k1x" +#define DBG_LVL DBG_INFO +#include + +#define TMR_CCR 0x000c +#define TMR_TN_MM(n, m) (0x0010 + ((n) << 4) + ((m) << 2)) +#define TMR_CR(n) (0x0090 + ((n) << 2)) +#define TMR_SR(n) (0x0080 + ((n) << 2)) +#define TMR_IER(n) (0x0060 + ((n) << 2)) +#define TMR_PLVR(n) (0x0040 + ((n) << 2)) +#define TMR_PLCR(n) (0x0050 + ((n) << 2)) +#define TMR_WMER 0x0068 +#define TMR_WMR 0x006c +#define TMR_WVR 0x00cc +#define TMR_WSR 0x00c0 +#define TMR_ICR(n) (0x0070 + ((n) << 2)) +#define TMR_WICR 0x00c4 +#define TMR_CER 0x0000 +#define TMR_CMR 0x0004 +#define TMR_WCR 0x00c8 +#define TMR_WFAR 0x00b0 +#define TMR_WSAR 0x00b4 +#define TMR_CRSR 0x0008 + +#define TMR_CCR_CS_0(x) (((x) & 0x3) << 0) +#define TMR_CCR_CS_1(x) (((x) & 0x3) << 2) +#define TMR_CCR_CS_2(x) (((x) & 0x3) << 5) + +#define MAX_DELTA 0xfffffffe +#define MIN_DELTA 5 + +#define SPACEMIT_MAX_COUNTER 3 +#define SPACEMIT_MAX_TIMER 3 + +#define TMR_CER_COUNTER(cid) (1 << (cid)) +#define SPACEMIT_ALL_COUNTERS ((1 << SPACEMIT_MAX_COUNTER) - 1) + +#define SPACEMIT_TIMER_ALL_CPU 0xffffffff + +#define CLOCK_32KHZ 32768 + +struct spacemit_timer; + +struct spacemit_timer_counter +{ + struct rt_clock_timer_device parent; + struct rt_clock_timer_info info; + + struct spacemit_timer *timer; + + int irq; + rt_uint32_t cid; + rt_uint32_t cycle; + rt_uint32_t freq; +}; + +#define raw_to_spacemit_timer_counter(raw) rt_container_of(raw, struct spacemit_timer_counter, parent) + +struct spacemit_timer +{ + void *base; + struct rt_clk *clk; + struct rt_reset_control *rstc; + + rt_uint32_t tid; + rt_uint32_t freq; + rt_uint32_t fc_freq; + rt_uint32_t apb_freq; + rt_uint32_t loop_delay_fastclk; + + struct spacemit_timer_counter counter[SPACEMIT_MAX_COUNTER]; + struct rt_spinlock tm_lock; +}; + +static rt_err_t timer_counter_switch_clock(struct spacemit_timer *timer, rt_uint32_t freq); + +static void timer_write_check(struct spacemit_timer *timer, + rt_uint32_t reg, rt_uint32_t val, rt_uint32_t mask, + rt_bool_t clr, rt_bool_t clk_switch) +{ + int loop = 3, retry = 100; + rt_uint32_t t_read, t_check = clr ? !val : val; + +_retry: + HWREG32(timer->base + reg) = val; + + if (clk_switch) + { + timer_counter_switch_clock(timer, timer->fc_freq); + } + + t_read = HWREG32(timer->base + reg); + + while (((t_read & mask) != (t_check & mask)) && loop) + { + /* Avoid trying frequently to worsen bus contention */ + rt_hw_us_delay(30); + + t_read = HWREG32(timer->base + reg); + --loop; + + if (!loop) + { + loop = 3; + + if (--retry) + { + goto _retry; + } + else + { + return; + } + } + } +} + +static rt_err_t timer_counter_switch_clock(struct spacemit_timer *timer, rt_uint32_t freq) +{ + rt_uint32_t ccr, val, mask; + + ccr = HWREG32(timer->base + TMR_CCR); + + switch (timer->tid) + { + case 0: + mask = TMR_CCR_CS_0(3); + break; + case 1: + mask = TMR_CCR_CS_1(3); + break; + case 2: + mask = TMR_CCR_CS_2(3); + break; + default: + return -RT_EINVAL; + } + + ccr &= ~mask; + + if (freq == timer->fc_freq) + { + val = 0; + } + else if (freq == CLOCK_32KHZ) + { + val = 1; + } + else + { + LOG_E("Timer %d: invalid clock rate %u", timer->tid, freq); + return -RT_EINVAL; + } + + switch (timer->tid) + { + case 0: + ccr |= TMR_CCR_CS_0(val); + break; + case 1: + ccr |= TMR_CCR_CS_1(val); + break; + case 2: + ccr |= TMR_CCR_CS_2(val); + break; + } + + timer_write_check(timer, TMR_CCR, ccr, mask, RT_FALSE, RT_FALSE); + + return RT_EOK; +} + +static void timer_counter_disable(struct spacemit_timer_counter *cnt) +{ + rt_uint32_t cer; + rt_bool_t clk_switch = RT_FALSE; + struct spacemit_timer *timer = cnt->timer; + + if (cnt->freq != timer->fc_freq) + { + clk_switch = RT_TRUE; + } + + /* Disable counter */ + cer = HWREG32(timer->base + TMR_CER); + timer_write_check(timer, TMR_CER, (cer & ~(1 << cnt->cid)), (1 << cnt->cid), RT_FALSE, clk_switch); +} + +static void timer_counter_enable(struct spacemit_timer_counter *cnt) +{ + rt_uint32_t cer; + struct spacemit_timer *timer = cnt->timer; + + /* Switch to original clock */ + if (cnt->freq != timer->fc_freq) + { + timer_counter_switch_clock(timer, cnt->freq); + } + + /* Enable timer */ + cer = HWREG32(timer->base + TMR_CER); + + timer_write_check(timer, TMR_CER, (cer | (1 << cnt->cid)), (1 << cnt->cid), RT_FALSE, RT_FALSE); +} + +static void spacemit_timer_init(struct rt_clock_timer_device *timer_dev, rt_uint32_t state) +{ + RT_UNUSED(timer_dev); + RT_UNUSED(state); +} + +static rt_err_t spacemit_timer_start(struct rt_clock_timer_device *timer_dev, + rt_uint32_t cycle, rt_clock_timer_mode_t mode) +{ + rt_ubase_t level; + struct spacemit_timer_counter *cnt = raw_to_spacemit_timer_counter(timer_dev); + + if (mode != CLOCK_TIMER_MODE_ONESHOT) + { + return -RT_ENOSYS; + } + + level = rt_spin_lock_irqsave(&cnt->timer->tm_lock); + + /* If the timer counter is enabled, first disable it. */ + if (HWREG32(cnt->timer->base + TMR_CER) & (1 << cnt->cid)) + { + timer_counter_disable(cnt); + } + + /* Setup new counter value */ + timer_write_check(cnt->timer, TMR_TN_MM(cnt->cid, 0), (cycle - 1), (rt_uint32_t)(-1), RT_FALSE, RT_FALSE); + + /* enable the matching interrupt */ + timer_write_check(cnt->timer, TMR_IER(cnt->cid), 0x1, 0x1, RT_FALSE, RT_FALSE); + + timer_counter_enable(cnt); + + cnt->cycle = cycle; + + rt_spin_unlock_irqrestore(&cnt->timer->tm_lock, level); + + return RT_EOK; +} + +static void spacemit_timer_stop(struct rt_clock_timer_device *timer_dev) +{ + rt_ubase_t level; + struct spacemit_timer_counter *cnt = raw_to_spacemit_timer_counter(timer_dev); + + level = rt_spin_lock_irqsave(&cnt->timer->tm_lock); + + timer_counter_disable(cnt); + + rt_spin_unlock_irqrestore(&cnt->timer->tm_lock, level); +} + +static rt_err_t spacemit_timer_ctrl(struct rt_clock_timer_device *timer_dev, + rt_uint32_t cmd, void *args) +{ + rt_ubase_t level; + rt_err_t err = RT_EOK; + struct spacemit_timer_counter *cnt = raw_to_spacemit_timer_counter(timer_dev); + + switch (cmd) + { + case CLOCK_TIMER_CTRL_FREQ_SET: + if (!args) + { + err = -RT_EINVAL; + break; + } + + level = rt_spin_lock_irqsave(&cnt->timer->tm_lock); + err = timer_counter_switch_clock(cnt->timer, *(rt_int32_t *)args); + if (!err) + { + cnt->freq = *(rt_int32_t *)args; + } + rt_spin_unlock_irqrestore(&cnt->timer->tm_lock, level); + break; + + case CLOCK_TIMER_CTRL_STOP: + spacemit_timer_stop(timer_dev); + break; + + case CLOCK_TIMER_CTRL_INFO_GET: + if (args) + { + rt_memcpy(args, &cnt->info, sizeof(cnt->info)); + } + else + { + err = -RT_EINVAL; + } + break; + + case CLOCK_TIMER_CTRL_MODE_SET: + err = spacemit_timer_start(timer_dev, cnt->cycle, + (rt_clock_timer_mode_t)(rt_ubase_t)args); + break; + + default: + err = -RT_EINVAL; + break; + } + + return err; +} + +const static struct rt_clock_timer_ops spacemit_timer_ops = +{ + .init = spacemit_timer_init, + .start = spacemit_timer_start, + .stop = spacemit_timer_stop, + .control = spacemit_timer_ctrl, +}; + +static void spacemit_timer_isr(int irqno, void *param) +{ + rt_ubase_t level; + struct spacemit_timer_counter *cnt = param; + + level = rt_spin_lock_irqsave(&cnt->timer->tm_lock); + + /* We only use match #0 for the counter. */ + if (HWREG32(cnt->timer->base + TMR_SR(cnt->cid)) & 0x1) + { + timer_counter_disable(cnt); + + /* Disable the interrupt. */ + timer_write_check(cnt->timer, TMR_IER(cnt->cid), 0, 0x7, RT_FALSE, RT_FALSE); + /* Clear interrupt status */ + timer_write_check(cnt->timer, TMR_ICR(cnt->cid), 0x1, 0x7, RT_TRUE, RT_FALSE); + + rt_spin_unlock_irqrestore(&cnt->timer->tm_lock, level); + + rt_clock_timer_isr(&cnt->parent); + + return; + } + + rt_spin_unlock_irqrestore(&cnt->timer->tm_lock, level); +} + +static void spacemit_timer_free(struct spacemit_timer *timer) +{ + if (timer->base) + { + rt_iounmap(timer->base); + } + + if (!rt_is_err_or_null(timer->clk)) + { + rt_clk_put(timer->clk); + } + + rt_free(timer); +} + +static rt_err_t spacemit_timer_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + const char *dev_name; + rt_uint32_t val, delay; + struct rt_device *dev = &pdev->parent; + struct rt_ofw_node *np = dev->ofw_node, *child_np; + struct spacemit_timer *timer = rt_calloc(1, sizeof(*timer)); + + if (!timer) + { + return -RT_ENOMEM; + } + + timer->base = rt_dm_dev_iomap(dev, 0); + + if (!timer->base) + { + err = -RT_EIO; + goto _fail; + } + + if (rt_is_err(timer->clk = rt_clk_get_by_index(dev, 0))) + { + err = rt_ptr_err(timer->clk); + goto _fail; + } + + if (rt_is_err(timer->rstc = rt_reset_control_get_by_index(dev, 0))) + { + err = rt_ptr_err(timer->rstc); + goto _fail; + } + + if ((err = rt_dm_dev_prop_read_u32(dev, "spacemit,timer-id", &timer->tid))) + { + goto _fail; + } + + if (timer->tid >= SPACEMIT_MAX_TIMER) + { + err = -RT_EFULL; + goto _fail; + } + + /* Timer's fast clock and apb frequency */ + if ((err = rt_dm_dev_prop_read_u32(dev, "spacemit,timer-fastclk-frequency", &timer->fc_freq))) + { + goto _fail; + } + + if ((err = rt_dm_dev_prop_read_u32(dev, "spacemit,timer-apb-frequency", &timer->apb_freq))) + { + goto _fail; + } + + if ((err = rt_dm_dev_prop_read_u32(dev, "spacemit,timer-frequency", &timer->freq))) + { + goto _fail; + } + + /* + * Need use loop for more safe register's accessing, + * so at here dynamically calculate the loop time. + */ + if (!timer->fc_freq || !timer->apb_freq) + { + err = -RT_EINVAL; + goto _fail; + } + + if ((err = rt_clk_prepare_enable(timer->clk))) + { + goto _fail; + } + + if ((err = rt_clk_set_rate(timer->clk, timer->fc_freq))) + { + goto _fail; + } + + rt_reset_control_deassert(timer->rstc); + + /* + * The calculation formula for the loop cycle is: + * + * (1) need wait for 2 timer's clock cycle: + * 1 2 + * ------- x 2 = ------- + * fc_freq fc_freqtimer_counter_enable(evt); + * + * (2) convert to apb clock cycle: + * 2 1 apb_freq * 2 + * ------- / -------- = ---------------- + * fc_freq apb_freq fc_freq + * + * (3) every apb register's accessing will take 8 apb clock cycle, + * also consider add extral one more time for safe way; + * so finally need loop times for the apb register accessing: + * + * (apb_freq * 2) + * ------------------ / 8 + 1 + * fc_freq + */ + delay = ((timer->apb_freq * 2) / timer->fc_freq / 8) + 1; + timer->loop_delay_fastclk = delay; + + rt_spin_lock_init(&timer->tm_lock); + + /* Switch to fastclk before disable all counters. */ + timer_counter_switch_clock(timer, timer->fc_freq); + + /* Disalbe all counters */ + val = HWREG32(timer->base + TMR_CER) & ~SPACEMIT_ALL_COUNTERS; + HWREG32(timer->base + TMR_CER) = val; + + /* Disable matching interrupt */ + HWREG32(timer->base + TMR_IER(0)) = 0x0; + HWREG32(timer->base + TMR_IER(1)) = 0x0; + HWREG32(timer->base + TMR_IER(2)) = 0x0; + + while (delay--) + { + /* Clear pending interrupt status */ + HWREG32(timer->base + TMR_ICR(0)) = 0x1; + HWREG32(timer->base + TMR_ICR(1)) = 0x1; + HWREG32(timer->base + TMR_ICR(2)) = 0x1; + HWREG32(timer->base + TMR_CER) = val; + } + + rt_ofw_foreach_available_child_node(np, child_np) + { + rt_uint32_t cpu, ratio; + struct spacemit_timer_counter *cnt; + + if (!rt_ofw_node_is_compatible(child_np, "spacemit,timer-match")) + { + continue; + } + + if (rt_ofw_prop_read_u32(child_np, "spacemit,timer-counter-id", &val)) + { + continue; + } + + if (val >= SPACEMIT_MAX_TIMER) + { + LOG_W("Found a counter %s with id = %d > %d", + rt_ofw_node_full_name(child_np), val, SPACEMIT_MAX_TIMER); + continue; + } + + cnt = &timer->counter[val]; + cnt->cid = val; + cnt->freq = timer->freq; + + if (cnt->timer) + { + LOG_W("Found a repeat counter %s with id = %d", + rt_ofw_node_full_name(child_np), cnt->cid); + continue; + } + + if (cnt->timer) + { + LOG_W("Found a repeat counter %s with id = %d", + rt_ofw_node_full_name(child_np), cnt->cid); + continue; + } + + if (rt_ofw_prop_read_bool(child_np, "spacemit,timer-broadcast")) + { + cpu = SPACEMIT_TIMER_ALL_CPU; + } + else + { + cpu = rt_hw_cpu_id(); + rt_ofw_prop_read_u32(child_np, "spacemit,timer-counter-cpu", &cpu); + } + + if ((cnt->irq = rt_ofw_get_irq(child_np, 0)) < 0) + { + continue; + } + + /* Hareware init */ + if (timer_counter_switch_clock(timer, cnt->freq)) + { + continue; + } + + ratio = timer->fc_freq / timer->freq; + delay = timer->loop_delay_fastclk * ratio; + + /* Set timer to free-running mode */ + val = HWREG32(timer->base + TMR_CMR) | TMR_CER_COUNTER(cnt->cid); + HWREG32(timer->base + TMR_CMR) = val; + + /* Free-running */ + HWREG32(timer->base + TMR_PLCR(cnt->cid)) = 0x0; + /* Clear status */ + HWREG32(timer->base + TMR_ICR(cnt->cid)) = 0x7; + + /* Enable counter */ + val = HWREG32(timer->base + TMR_CER) | TMR_CER_COUNTER(cnt->cid); + HWREG32(timer->base + TMR_CER) = val; + + while (delay--) + { + HWREG32(timer->base + TMR_CER) = val; + } + + cnt->timer = timer; + + cnt->parent.ops = &spacemit_timer_ops; + cnt->parent.info = &cnt->info; + cnt->parent.freq = cnt->freq; + + cnt->info.maxfreq = cnt->freq; + cnt->info.minfreq = cnt->freq; + cnt->info.maxcnt = 0xffffffff; + cnt->info.cntmode = CLOCK_TIMER_CNTMODE_UP; + + rt_dm_dev_set_name_auto(&cnt->parent.parent, "timer"); + dev_name = rt_dm_dev_get_name(&cnt->parent.parent); + + rt_hw_interrupt_install(cnt->irq, spacemit_timer_isr, cnt, dev_name); + rt_hw_interrupt_umask(cnt->irq); + + if (cpu != SPACEMIT_TIMER_ALL_CPU) + { + RT_IRQ_AFFINITY_DECLARE(affinity) = { 0 }; + + RT_IRQ_AFFINITY_SET(affinity, cpu); + + rt_pic_irq_set_affinity(cnt->irq, affinity); + } + + rt_clock_timer_register(&cnt->parent, dev_name, RT_NULL); + } + + dev->user_data = timer; + + return RT_EOK; + +_fail: + spacemit_timer_free(timer); + + return err; +} + +static rt_err_t spacemit_timer_remove(struct rt_platform_device *pdev) +{ + struct spacemit_timer *timer = pdev->parent.user_data; + + for (int i = 0; i < SPACEMIT_MAX_TIMER; ++i) + { + struct spacemit_timer_counter *cnt = &timer->counter[i]; + + if (!cnt->timer) + { + continue; + } + + spacemit_timer_stop(&cnt->parent); + + rt_hw_interrupt_mask(cnt->irq); + rt_pic_detach_irq(cnt->irq, cnt); + + rt_device_unregister(&cnt->parent.parent); + } + + spacemit_timer_free(timer); + + return RT_EOK; +} + +static const struct rt_ofw_node_id spacemit_timer_ofw_ids[] = +{ + { .compatible = "spacemit,soc-timer" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver spacemit_timer_driver = +{ + .name = "clock_timer-spacemit", + .ids = spacemit_timer_ofw_ids, + + .probe = spacemit_timer_probe, + .remove = spacemit_timer_remove, +}; +RT_PLATFORM_DRIVER_EXPORT(spacemit_timer_driver); diff --git a/bsp/spacemit/dm/dma/Kconfig b/bsp/spacemit/dm/dma/Kconfig new file mode 100644 index 000000000000..da72fad16b7c --- /dev/null +++ b/bsp/spacemit/dm/dma/Kconfig @@ -0,0 +1,8 @@ +config RT_DMA_MMP_PDMA + bool "Spacemit K1X MMP PDMA" + default n + +config RT_DMA_MMP_PDMA_SUPPORT_64BIT + bool "Support 64bit" + depends on RT_DMA_MMP_PDMA + default n diff --git a/bsp/spacemit/dm/dma/SConscript b/bsp/spacemit/dm/dma/SConscript new file mode 100644 index 000000000000..e8fd891561a8 --- /dev/null +++ b/bsp/spacemit/dm/dma/SConscript @@ -0,0 +1,13 @@ +from building import * + +group = [] +src = [] +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../include'] + +if GetDepend(['RT_DMA_MMP_PDMA']): + src += ['dma-mmp-pdma.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/spacemit/dm/dma/dma-mmp-pdma.c b/bsp/spacemit/dm/dma/dma-mmp-pdma.c new file mode 100644 index 000000000000..19cccc8757de --- /dev/null +++ b/bsp/spacemit/dm/dma/dma-mmp-pdma.c @@ -0,0 +1,994 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#include +#include +#include + +#define DBG_TAG "dma.mmp-pdma" +#define DBG_LVL DBG_INFO +#include + +#include + +#define DDADRH(n) (0x0300 + ((n) << 4)) +#define DSADRH(n) (0x0304 + ((n) << 4)) +#define DTADRH(n) (0x0308 + ((n) << 4)) +#define DCSR_LPAEEN RT_BIT(21) /* Long Physical Address Extension enable */ +#define DRCMR_INVALID 100 /* Max DMA request number + 1 */ +#define DCMD_BURST64 (4 << 16) /* 64 byte burst */ + +#define DCSR 0x0000 +#define DALGN 0x00a0 +#define DINT 0x00f0 +#define DDADR 0x0200 +#define DSADR(n) (0x0204 + ((n) << 4)) +#define DTADR(n) (0x0208 + ((n) << 4)) +#define DCMD 0x020c + +#define DCSR_RUN RT_BIT(31) /* Run Bit (read / write) */ +#define DCSR_NODESC RT_BIT(30) /* No-Descriptor Fetch (read / write) */ +#define DCSR_STOPIRQEN RT_BIT(29) /* Stop Interrupt Enable (read / write) */ +#define DCSR_REQPEND RT_BIT(8) /* Request Pending (read-only) */ +#define DCSR_STOPSTATE RT_BIT(3) /* Stop State (read-only) */ +#define DCSR_ENDINTR RT_BIT(2) /* End Interrupt (read / write) */ +#define DCSR_STARTINTR RT_BIT(1) /* Start Interrupt (read / write) */ +#define DCSR_BUSERR RT_BIT(0) /* Bus Error Interrupt (read / write) */ + +#define DCSR_EORIRQEN RT_BIT(28) /* End of Receive Interrupt Enable (R/W) */ +#define DCSR_EORJMPEN RT_BIT(27) /* Jump to next descriptor on EOR */ +#define DCSR_EORSTOPEN RT_BIT(26) /* STOP on an EOR */ +#define DCSR_SETCMPST RT_BIT(25) /* Set Descriptor Compare Status */ +#define DCSR_CLRCMPST RT_BIT(24) /* Clear Descriptor Compare Status */ +#define DCSR_CMPST RT_BIT(10) /* The Descriptor Compare Status */ +#define DCSR_EORINTR RT_BIT(9) /* The end of Receive */ + +#define DRCMR(n) ((((n) < 64) ? 0x0100 : 0x1100) + (((n) & 0x3f) << 2)) +#define DRCMR_MAPVLD RT_BIT(7) /* Map Valid (read / write) */ +#define DRCMR_CHLNUM 0x1f /* mask for Channel Number (read / write) */ + +#define DDADR_DESCADDR 0xfffffff0 /* Address of next descriptor (mask) */ +#define DDADR_STOP RT_BIT(0) /* Stop (read / write) */ + +#define DCMD_INCSRCADDR RT_BIT(31) /* Source Address Increment Setting. */ +#define DCMD_INCTRGADDR RT_BIT(30) /* Target Address Increment Setting. */ +#define DCMD_FLOWSRC RT_BIT(29) /* Flow Control by the source. */ +#define DCMD_FLOWTRG RT_BIT(28) /* Flow Control by the target. */ +#define DCMD_STARTIRQEN RT_BIT(22) /* Start Interrupt Enable */ +#define DCMD_ENDIRQEN RT_BIT(21) /* End Interrupt Enable */ +#define DCMD_ENDIAN RT_BIT(18) /* Device Endian-ness. */ +#define DCMD_BURST8 (1 << 16) /* 8 byte burst */ +#define DCMD_BURST16 (2 << 16) /* 16 byte burst */ +#define DCMD_BURST32 (3 << 16) /* 32 byte burst */ +#define DCMD_WIDTH1 (1 << 14) /* 1 byte width */ +#define DCMD_WIDTH2 (2 << 14) /* 2 byte width (HalfWord) */ +#define DCMD_WIDTH4 (3 << 14) /* 4 byte width (Word) */ +#define DCMD_LENGTH 0x01fff /* length mask (max = 8K - 1) */ + +#define DEFAULT_MAX_BURST_SIZE 32 +#define INVALID_BURST_SETTING -1 + +#define PDMA_MAX_DESC_BYTES DCMD_LENGTH + +#ifdef RT_DMA_MMP_PDMA_SUPPORT_64BIT +struct mmp_pdma_desc_hw +{ + rt_uint32_t ddadr; /* Points to the next descriptor + flags */ + rt_uint32_t dsadr; /* DSADR value for the current transfer */ + rt_uint32_t dtadr; /* DTADR value for the current transfer */ + rt_uint32_t dcmd; /* DCMD value for the current transfer */ + rt_uint32_t ddadrh; /* Points to the next descriptor + flags */ + rt_uint32_t dsadrh; /* DSADR value for the current transfer */ + rt_uint32_t dtadrh; /* DTADR value for the current transfer */ + rt_uint32_t rsvd; /* DCMD value for the current transfer */ +} rt_align(64); +#else +struct mmp_pdma_desc_hw +{ + rt_uint32_t ddadr; /* Points to the next descriptor + flags */ + rt_uint32_t dsadr; /* DSADR value for the current transfer */ + rt_uint32_t dtadr; /* DTADR value for the current transfer */ + rt_uint32_t dcmd; /* DCMD value for the current transfer */ +} rt_align(32); +#endif + +struct mmp_pdma_chan +{ + struct rt_dma_chan parent; + + rt_size_t desc_nr; + rt_ubase_t desc_dma; + struct mmp_pdma_desc_hw *desc; + + rt_uint32_t dcmd; + rt_uint32_t drcmr; + rt_uint32_t dev_addr; + + rt_size_t size; + rt_uint32_t bytes_residue; + rt_bool_t byte_align; + rt_bool_t pausing; + enum rt_dma_transfer_direction dir; +}; + +struct reserved_chan +{ + rt_uint32_t chan_id; + rt_uint32_t drcmr; +}; + +struct mmp_pdma_device +{ + struct rt_dma_controller parent; + + struct rt_clk *clk; + struct rt_reset_control *rstc; + + int irq; + void *base; + + rt_uint32_t max_burst_size; + + rt_uint32_t dma_channels; + struct mmp_pdma_chan *chan; + + rt_uint32_t reserved_channels_nr; + struct reserved_chan *reserved_channels; + + struct mmp_pdma_phy *phy; +}; +#define raw_to_mmp_pdma_device(raw) rt_container_of(raw, struct mmp_pdma_device, parent) +#define raw_to_mmp_pdma_device_chan(raw) rt_container_of(raw, struct mmp_pdma_chan, parent) + +static int get_max_burst_setting(rt_uint32_t max_burst_size) +{ + switch (max_burst_size) + { + case 8: + return DCMD_BURST8; + case 16: + return DCMD_BURST16; + case 32: + return DCMD_BURST32; + case 64: + return DCMD_BURST64; + default: + return INVALID_BURST_SETTING; + } +} + +static void enable_chan(struct mmp_pdma_chan *chan) +{ + int idx; + rt_uint32_t reg, dalgn, dcsr; + struct mmp_pdma_device *pdma = raw_to_mmp_pdma_device(chan->parent.ctrl); + + idx = chan - pdma->chan; + + if (chan->drcmr >= 0) + { + reg = DRCMR(chan->drcmr); + HWREG32(pdma->base + reg) = DRCMR_MAPVLD | idx; + } + + dalgn = HWREG32(pdma->base + DALGN); + if (chan->byte_align) + { + dalgn |= 1 << idx; + } + else + { + dalgn &= ~(1 << idx); + } + HWREG32(pdma->base + DALGN) = dalgn; + + reg = (idx << 2) + DCSR; + + dcsr = HWREG32(pdma->base + reg); + dcsr |= DCSR_RUN | DCSR_EORIRQEN | DCSR_EORSTOPEN; +#ifdef RT_DMA_MMP_PDMA_SUPPORT_64BIT + /* Use long descriptor mode: set DCSR_LPAEEN bit */ + dcsr |= DCSR_LPAEEN; +#endif + HWREG32(pdma->base + reg) = dcsr; +} + +static void disable_chan(struct mmp_pdma_chan *chan) +{ + int idx; + rt_uint32_t reg, dcsr, cnt = 1000; + struct mmp_pdma_device *pdma = raw_to_mmp_pdma_device(chan->parent.ctrl); + + idx = chan - pdma->chan; + + reg = (idx << 2) + DCSR; + + dcsr = HWREG32(pdma->base + reg); + dcsr &= ~(DCSR_RUN | DCSR_EORIRQEN | DCSR_EORSTOPEN); +#ifdef RT_DMA_MMP_PDMA_SUPPORT_64BIT + /* Use long descriptor mode: set DCSR_LPAEEN bit */ + dcsr &= ~DCSR_LPAEEN; +#endif + HWREG32(pdma->base + reg) = dcsr; + + /* Ensure dma is stopped. */ + dcsr = HWREG32(pdma->base + reg); + while (!(dcsr & (0x1 << 3)) && --cnt) + { + rt_hw_us_delay(10); + dcsr = HWREG32(pdma->base + reg); + } +} + +static void mmp_pdma_config_write(struct mmp_pdma_chan *chan, + struct rt_dma_slave_config *cfg, + enum rt_dma_transfer_direction direction) +{ + rt_uint32_t maxburst = 0, addr = 0; + enum rt_dma_slave_buswidth width = RT_DMA_SLAVE_BUSWIDTH_UNDEFINED; + + if (direction == RT_DMA_DEV_TO_MEM) + { + chan->dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC; + maxburst = cfg->src_maxburst; + width = cfg->src_addr_width; + addr = cfg->src_addr; + } + else if (direction == RT_DMA_MEM_TO_DEV) + { + chan->dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG; + maxburst = cfg->dst_maxburst; + width = cfg->dst_addr_width; + addr = cfg->dst_addr; + } + + if (width == RT_DMA_SLAVE_BUSWIDTH_1_BYTE) + { + chan->dcmd |= DCMD_WIDTH1; + } + else if (width == RT_DMA_SLAVE_BUSWIDTH_2_BYTES) + { + chan->dcmd |= DCMD_WIDTH2; + } + else if (width == RT_DMA_SLAVE_BUSWIDTH_4_BYTES) + { + chan->dcmd |= DCMD_WIDTH4; + } + + if (maxburst == 8) + { + chan->dcmd |= DCMD_BURST8; + } + else if (maxburst == 16) + { + chan->dcmd |= DCMD_BURST16; + } + else if (maxburst == 32) + { + chan->dcmd |= DCMD_BURST32; + } + + chan->dir = direction; + chan->dev_addr = addr; +} + +static struct rt_dma_chan *mmp_pdma_request_chan(struct rt_dma_controller *ctrl, + struct rt_device *slave, void *fw_data) +{ + int drcmr; + struct mmp_pdma_chan *chan = RT_NULL; + struct mmp_pdma_device *pdma = raw_to_mmp_pdma_device(ctrl); + struct rt_ofw_cell_args *args = fw_data; + rt_bool_t matched_reserved = RT_FALSE; + + drcmr = args ? args->args[0] : -1; + + if (drcmr >= 0) + { + for (int i = 0; i < pdma->reserved_channels_nr; ++i) + { + int chan_id = pdma->reserved_channels[i].chan_id; + + if (pdma->reserved_channels[i].drcmr == drcmr && + chan_id >= 0 && chan_id < pdma->dma_channels) + { + matched_reserved = RT_TRUE; + + if (!pdma->chan[chan_id].desc) + { + chan = &pdma->chan[chan_id]; + } + + goto _found_reserved; + } + } + } + +_found_reserved: + if (matched_reserved && !chan) + { + return rt_err_ptr(-RT_EBUSY); + } + + for (int i = 0; i < pdma->dma_channels; ++i) + { + rt_bool_t reserved = RT_FALSE; + + if (chan) + { + break; + } + + if (!pdma->chan[i].desc) + { + for (int j = 0; j < pdma->reserved_channels_nr; ++j) + { + if (pdma->reserved_channels[j].chan_id == i) + { + reserved = RT_TRUE; + break; + } + } + + if (reserved) + { + continue; + } + + chan = &pdma->chan[i]; + break; + } + } + + if (!chan) + { + return rt_err_ptr(-RT_EBUSY); + } + + chan->drcmr = drcmr; + chan->pausing = RT_FALSE; + chan->desc_nr = ARCH_PAGE_SIZE / sizeof(*chan->desc); + chan->desc = rt_dma_alloc_coherent(slave, ARCH_PAGE_SIZE, &chan->desc_dma); + + if (!chan->desc) + { + return rt_err_ptr(-RT_ENOMEM); + } + + return &chan->parent; +} + +static rt_err_t mmp_pdma_release_chan(struct rt_dma_chan *raw_chan) +{ + struct mmp_pdma_chan *chan = raw_to_mmp_pdma_device_chan(raw_chan); + + rt_dma_free_coherent(raw_chan->slave, ARCH_PAGE_SIZE, chan->desc, chan->desc_dma); + chan->desc = RT_NULL; + + return RT_EOK; +} + +static rt_err_t mmp_pdma_start(struct rt_dma_chan *raw_chan) +{ + struct mmp_pdma_chan *chan = raw_to_mmp_pdma_device_chan(raw_chan); + + if (!chan->pausing) + { + int idx; + rt_uint32_t reg; + struct mmp_pdma_device *pdma = raw_to_mmp_pdma_device(chan->parent.ctrl); + + idx = chan - pdma->chan; + reg = (idx << 4) + DDADR; + + HWREG32(pdma->base + reg) = chan->desc_dma & 0xffffffff; + #ifdef RT_DMA_MMP_PDMA_SUPPORT_64BIT + /* Config higher bits for desc address */ + HWREG32(pdma->base + DDADRH(idx)) = (rt_uint32_t)(chan->desc_dma >> 32); + #endif + } + + enable_chan(chan); + chan->bytes_residue = 0; + chan->pausing = RT_FALSE; + + return RT_EOK; +} + +static rt_err_t mmp_pdma_pause(struct rt_dma_chan *raw_chan) +{ + struct mmp_pdma_chan *chan = raw_to_mmp_pdma_device_chan(raw_chan); + + disable_chan(chan); + chan->pausing = RT_TRUE; + + return RT_EOK; +} + +static rt_err_t mmp_pdma_stop(struct rt_dma_chan *raw_chan) +{ + rt_uint32_t reg; + struct mmp_pdma_chan *chan = raw_to_mmp_pdma_device_chan(raw_chan); + struct mmp_pdma_device *pdma = raw_to_mmp_pdma_device(raw_chan->ctrl); + + disable_chan(chan); + + if (chan->drcmr >= 0) + { + /* Clear the channel mapping in DRCMR */ + reg = DRCMR(chan->drcmr); + HWREG32(pdma->base + reg) = 0; + } + + chan->bytes_residue = 0; + chan->pausing = RT_FALSE; + + return RT_EOK; +} + +static rt_err_t mmp_pdma_config(struct rt_dma_chan *raw_chan, + struct rt_dma_slave_config *conf) +{ + if (conf->src_addr_width == RT_DMA_SLAVE_BUSWIDTH_UNDEFINED) + { + conf->src_addr_width = RT_DMA_SLAVE_BUSWIDTH_4_BYTES; + } + if (conf->dst_addr_width == RT_DMA_SLAVE_BUSWIDTH_UNDEFINED) + { + conf->dst_addr_width = RT_DMA_SLAVE_BUSWIDTH_4_BYTES; + } + + return RT_EOK; +} + +static rt_err_t mmp_pdma_prep_memcpy(struct rt_dma_chan *raw_chan, + rt_ubase_t dma_addr_src, rt_ubase_t dma_addr_dst, rt_size_t len) +{ + int idx; + rt_size_t copy = 0; + rt_ubase_t desc_dma; + struct mmp_pdma_desc_hw *desc, *prev_desc; + struct mmp_pdma_chan *chan = raw_to_mmp_pdma_device_chan(raw_chan); + struct mmp_pdma_device *pdma = raw_to_mmp_pdma_device(raw_chan->ctrl); + + if (len > chan->desc_nr * PDMA_MAX_DESC_BYTES) + { + return -RT_EEMPTY; + } + + chan->byte_align = RT_FALSE; + + if (!chan->dir) + { + chan->dir = RT_DMA_MEM_TO_MEM; + chan->dcmd = DCMD_INCTRGADDR | DCMD_INCSRCADDR | get_max_burst_setting(pdma->max_burst_size); + } + + chan->size = len; + + for (idx = 0, desc_dma = chan->desc_dma; len; ++idx, desc_dma += sizeof(*desc)) + { + copy = rt_min_t(rt_size_t, len, PDMA_MAX_DESC_BYTES); + + if ((dma_addr_src & 0x7) || (dma_addr_dst & 0x7)) + { + chan->byte_align = RT_TRUE; + } + + desc = &chan->desc[idx]; + desc->dcmd = chan->dcmd | (DCMD_LENGTH & copy); + + /* + * Check whether descriptor/source-addr/target-addr is in + * region higher than 4G. If so, set related higher bits to 1. + */ + if (chan->dir == RT_DMA_MEM_TO_DEV) + { + desc->dsadr = dma_addr_src & 0xffffffff; + desc->dtadr = dma_addr_dst; + #ifdef RT_DMA_MMP_PDMA_SUPPORT_64BIT + desc->dsadrh = dma_addr_src >> 32; + desc->dtadrh = 0; + #endif + } + else if (chan->dir == RT_DMA_DEV_TO_MEM) + { + desc->dsadr = dma_addr_src; + desc->dtadr = dma_addr_dst & 0xffffffff; + #ifdef RT_DMA_MMP_PDMA_SUPPORT_64BIT + desc->dsadrh = 0; + desc->dtadrh = dma_addr_dst >> 32; + #endif + } + else if (chan->dir == RT_DMA_MEM_TO_MEM) + { + desc->dsadr = dma_addr_src & 0xffffffff; + desc->dtadr = dma_addr_dst & 0xffffffff; + #ifdef RT_DMA_MMP_PDMA_SUPPORT_64BIT + desc->dsadrh = dma_addr_src >> 32; + desc->dtadrh = dma_addr_dst >> 32; + #endif + } + + len -= copy; + + if (chan->dir == RT_DMA_MEM_TO_DEV) + { + dma_addr_src += copy; + } + else if (chan->dir == RT_DMA_DEV_TO_MEM) + { + dma_addr_dst += copy; + } + else if (chan->dir == RT_DMA_MEM_TO_MEM) + { + dma_addr_src += copy; + dma_addr_dst += copy; + } + + if (idx) + { + prev_desc = &chan->desc[idx - 1]; + + prev_desc->ddadr = desc_dma; + #ifdef RT_DMA_MMP_PDMA_SUPPORT_64BIT + prev_desc->ddadrh = desc_dma >> 32; + #endif + } + } + + prev_desc = &chan->desc[idx - 1]; + + prev_desc->ddadr = DDADR_STOP; + prev_desc->dcmd |= DCMD_ENDIRQEN; + + return RT_EOK; +} + +static rt_err_t mmp_pdma_prep_cyclic(struct rt_dma_chan *raw_chan, + rt_ubase_t dma_buf_addr, rt_size_t buf_len, rt_size_t period_len, + enum rt_dma_transfer_direction dir) +{ + int idx; + rt_ubase_t desc_dma; + rt_ubase_t dma_addr_src, dma_addr_dst; +#ifdef RT_DMA_MMP_PDMA_SUPPORT_64BIT + rt_ubase_t dma_addr_srch, dma_addr_dsth; +#endif + struct mmp_pdma_desc_hw *desc, *prev_desc; + struct mmp_pdma_chan *chan = raw_to_mmp_pdma_device_chan(raw_chan); + + if (buf_len % period_len != 0) + { + return -RT_EINVAL; + } + + if (period_len > PDMA_MAX_DESC_BYTES) + { + return -RT_EINVAL; + } + + if (buf_len > chan->desc_nr * PDMA_MAX_DESC_BYTES) + { + return -RT_EEMPTY; + } + + mmp_pdma_config_write(chan, &raw_chan->conf, dir); + + switch (dir) + { + case RT_DMA_MEM_TO_DEV: + dma_addr_src = dma_buf_addr & 0xffffffff; + dma_addr_dst = chan->dev_addr; + #ifdef RT_DMA_MMP_PDMA_SUPPORT_64BIT + dma_addr_srch = dma_buf_addr >> 32; + dma_addr_dsth = 0; + #endif + break; + + case RT_DMA_DEV_TO_MEM: + dma_addr_dst = dma_buf_addr & 0xffffffff; + dma_addr_src = chan->dev_addr; + #ifdef RT_DMA_MMP_PDMA_SUPPORT_64BIT + dma_addr_dsth = dma_buf_addr >> 32; + dma_addr_srch = 0; + #endif + break; + + default: + LOG_E("Unsupported direction for cyclic DMA"); + return -RT_EINVAL; + } + + chan->dir = dir; + chan->size = buf_len; + + for (idx = 0, desc_dma = chan->desc_dma; buf_len; ++idx, desc_dma += sizeof(*desc)) + { + desc = &chan->desc[idx]; + + desc->dcmd = chan->dcmd | DCMD_ENDIRQEN | (DCMD_LENGTH & period_len); + desc->dsadr = dma_addr_src; + desc->dtadr = dma_addr_dst; + #ifdef RT_DMA_MMP_PDMA_SUPPORT_64BIT + desc->dsadrh = dma_addr_dsth; + desc->dtadrh = dma_addr_srch; + #endif + + buf_len -= period_len; + + if (chan->dir == RT_DMA_MEM_TO_DEV) + { + dma_addr_src += period_len; + } + else + { + dma_addr_dst += period_len; + } + + if (idx) + { + prev_desc = &chan->desc[idx - 1]; + + prev_desc->ddadr = desc_dma; + #ifdef RT_DMA_MMP_PDMA_SUPPORT_64BIT + prev_desc->ddadrh = desc_dma >> 32; + #endif + } + }; + + prev_desc = &chan->desc[idx - 1]; + + /* Make the cyclic link */ + prev_desc->ddadr = chan->desc_dma; + + return RT_EOK; +} + +static rt_err_t mmp_pdma_prep_single(struct rt_dma_chan *raw_chan, + rt_ubase_t dma_buf_addr, rt_size_t buf_len, + enum rt_dma_transfer_direction dir) +{ + int idx; + rt_size_t copy = 0; + rt_ubase_t desc_dma; + struct mmp_pdma_desc_hw *desc, *prev_desc; + struct mmp_pdma_chan *chan = raw_to_mmp_pdma_device_chan(raw_chan); + + if (buf_len > chan->desc_nr * PDMA_MAX_DESC_BYTES) + { + return -RT_EEMPTY; + } + + chan->byte_align = RT_TRUE; + + mmp_pdma_config_write(chan, &raw_chan->conf, dir); + + chan->dir = dir; + chan->size = buf_len; + + for (idx = 0, desc_dma = chan->desc_dma; buf_len; ++idx, desc_dma += sizeof(*desc)) + { + copy = rt_min_t(rt_size_t, buf_len, PDMA_MAX_DESC_BYTES); + + if (dma_buf_addr & 0x7) + { + chan->byte_align = RT_TRUE; + } + + desc = &chan->desc[idx]; + desc->dcmd = chan->dcmd | (DCMD_LENGTH & copy); + + /* + * Check whether descriptor/source-addr/target-addr is in + * region higher than 4G. If so, set related higher bits to 1. + */ + if (dir == RT_DMA_MEM_TO_DEV) + { + desc->dsadr = dma_buf_addr & 0xffffffff; + desc->dtadr = chan->dev_addr; + #ifdef RT_DMA_MMP_PDMA_SUPPORT_64BIT + desc->dsadrh = dma_buf_addr >> 32; + desc->dtadrh = 0; + #endif + } + else if (dir == RT_DMA_DEV_TO_MEM) + { + desc->dsadr = chan->dev_addr; + desc->dtadr = dma_buf_addr & 0xffffffff; + #ifdef RT_DMA_MMP_PDMA_SUPPORT_64BIT + desc->dsadrh = 0; + desc->dtadrh = dma_buf_addr >> 32; + #endif + } + else + { + return -RT_EINVAL; + } + + dma_buf_addr += copy; + buf_len -= copy; + + if (idx) + { + prev_desc = &chan->desc[idx - 1]; + + prev_desc->ddadr = desc_dma; + #ifdef RT_DMA_MMP_PDMA_SUPPORT_64BIT + prev_desc->ddadrh = desc_dma >> 32; + #endif + } + } + + prev_desc = &chan->desc[idx - 1]; + + prev_desc->ddadr = DDADR_STOP; + prev_desc->dcmd |= DCMD_ENDIRQEN; + + return RT_EOK; +} + +static const struct rt_dma_controller_ops mmp_pdma_ops = +{ + .request_chan = mmp_pdma_request_chan, + .release_chan = mmp_pdma_release_chan, + .start = mmp_pdma_start, + .pause = mmp_pdma_pause, + .stop = mmp_pdma_stop, + .config = mmp_pdma_config, + .prep_memcpy = mmp_pdma_prep_memcpy, + .prep_cyclic = mmp_pdma_prep_cyclic, + .prep_single = mmp_pdma_prep_single, +}; + +static void mmp_pdma_isr(int irq, void *param) +{ + rt_uint32_t i, dint, dcsr; + struct mmp_pdma_chan *chan; + struct mmp_pdma_device *pdma = param; + + dint = HWREG32(pdma->base + DINT); + + while (dint) + { + if ((i = __rt_ffs(dint) - 1) >= pdma->dma_channels) + { + break; + } + + chan = &pdma->chan[i]; + + /* Clear IRQ */ + dcsr = HWREG32(pdma->base + (i << 2) + DCSR); + HWREG32(pdma->base + (i << 2) + DCSR) = dcsr; + + rt_dma_chan_done(&chan->parent, chan->size); + + dint &= (dint - 1); + } +} + +#ifdef RT_USING_PM +static rt_err_t mmp_pdma_pm_suspend(const struct rt_device *device, rt_uint8_t mode) +{ + struct mmp_pdma_device *pdma = device->user_data; + + rt_clk_disable_unprepare(pdma->clk); + + return RT_EOK; +} + +static void mmp_pdma_pm_resume(const struct rt_device *device, rt_uint8_t mode) +{ + struct mmp_pdma_device *pdma = device->user_data; + + rt_clk_prepare_enable(pdma->clk); +} + +static const struct rt_device_pm_ops mmp_pdma_pm_ops = +{ + .suspend = mmp_pdma_pm_suspend, + .resume = mmp_pdma_pm_resume, +}; +#endif /* RT_USING_PM */ + +static void mmp_pdma_free(struct mmp_pdma_device *pdma, struct rt_device *dev) +{ + if (pdma->base) + { + rt_iounmap(pdma->base); + } + + if (!rt_is_err_or_null(pdma->clk)) + { + rt_clk_disable_unprepare(pdma->clk); + rt_clk_put(pdma->clk); + } + + if (!rt_is_err_or_null(pdma->rstc)) + { + rt_reset_control_put(pdma->rstc); + } + + if (pdma->reserved_channels) + { + rt_free(pdma->reserved_channels); + } + + if (pdma->chan) + { + rt_free(pdma->chan); + } + + rt_free(pdma); +} + +static rt_err_t mmp_pdma_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + struct rt_device *dev = &pdev->parent; + struct mmp_pdma_device *pdma = rt_calloc(1, sizeof(*pdma)); + + if (!pdma) + { + return -RT_ENOMEM; + } + + if (!(pdma->base = rt_dm_dev_iomap(dev, 0))) + { + err = -RT_EIO; + goto _fail; + } + + if ((pdma->irq = rt_dm_dev_get_irq(dev, 0)) < 0) + { + err = pdma->irq; + goto _fail; + } + + pdma->clk = rt_clk_get_by_index(dev, 0); + if (rt_is_err(pdma->clk)) + { + err = rt_ptr_err(pdma->clk); + goto _fail; + } + + if ((err = rt_clk_prepare_enable(pdma->clk))) + { + goto _fail; + } + + pdma->rstc = rt_reset_control_get_by_index(dev, 0); + if (rt_is_err(pdma->rstc)) + { + err = rt_ptr_err(pdma->rstc); + goto _fail; + } + + if ((err = rt_reset_control_deassert(pdma->rstc))) + { + goto _fail; + } + + if ((err = rt_dm_dev_prop_read_u32(dev, "#dma-channels", &pdma->dma_channels))) + { + goto _fail; + } + + if (rt_dm_dev_prop_read_u32(dev, "max-burst-size", &pdma->max_burst_size) || + get_max_burst_setting(pdma->max_burst_size) == INVALID_BURST_SETTING) + { + pdma->max_burst_size = DEFAULT_MAX_BURST_SIZE; + } + + pdma->reserved_channels_nr = rt_dm_dev_prop_count_of_size(dev, + "reserved-channels", sizeof(rt_uint32_t) * 2); + + if (pdma->reserved_channels_nr > 0) + { + pdma->reserved_channels = rt_calloc(pdma->reserved_channels_nr, sizeof(struct reserved_chan)); + + if (!pdma->reserved_channels) + { + err = -RT_ENOMEM; + goto _fail; + } + + for (int i = 0; i < pdma->reserved_channels_nr; ++i) + { + rt_dm_dev_prop_read_u32_index(dev, "reserved-channels", i * 2, + &pdma->reserved_channels[i].chan_id); + rt_dm_dev_prop_read_u32_index(dev, "reserved-channels", i * 2 + 1, + &pdma->reserved_channels[i].drcmr); + } + } + + if (!(pdma->chan = rt_calloc(pdma->dma_channels, sizeof(*pdma->chan)))) + { + err = -RT_ENOMEM; + goto _fail; + } + + pdma->parent.dev = dev; + pdma->parent.ops = &mmp_pdma_ops; + rt_dma_controller_add_direction(&pdma->parent, RT_DMA_MEM_TO_MEM); + rt_dma_controller_add_direction(&pdma->parent, RT_DMA_MEM_TO_DEV); + rt_dma_controller_add_direction(&pdma->parent, RT_DMA_DEV_TO_MEM); +#ifdef RT_DMA_MMP_PDMA_SUPPORT_64BIT + rt_dma_controller_set_addr_mask(&pdma->parent, RT_DMA_ADDR_MASK(64)); +#else + rt_dma_controller_set_addr_mask(&pdma->parent, RT_DMA_ADDR_MASK(32)); +#endif + + if ((err = rt_dma_controller_register(&pdma->parent))) + { + goto _fail; + } + + rt_hw_interrupt_install(pdma->irq, mmp_pdma_isr, pdma, "pdma"); + rt_hw_interrupt_umask(pdma->irq); + + dev->user_data = pdma; + +#ifdef RT_USING_PM + rt_pm_device_register(dev, &mmp_pdma_pm_ops); +#endif + + return RT_EOK; + +_fail: + mmp_pdma_free(pdma, dev); + + return err; +} + +static rt_err_t mmp_pdma_remove(struct rt_platform_device *pdev) +{ + struct rt_device *dev = &pdev->parent; + struct mmp_pdma_device *pdma = dev->user_data; + +#ifdef RT_USING_PM + rt_pm_device_unregister(dev); +#endif + + rt_dma_controller_unregister(&pdma->parent); + + rt_hw_interrupt_mask(pdma->irq); + rt_pic_detach_irq(pdma->irq, pdma); + + rt_reset_control_assert(pdma->rstc); + + mmp_pdma_free(pdma, dev); + + return RT_EOK; +} + +static const struct rt_ofw_node_id mmp_pdma_ofw_ids[] = +{ + { .compatible = "spacemit,pdma-1.0" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver mmp_pdma_driver = +{ + .name = "dma-mmp-pdma", + .ids = mmp_pdma_ofw_ids, + + .probe = mmp_pdma_probe, + .remove = mmp_pdma_remove, +}; + +static int mmp_pdma_drv_register(void) +{ + rt_platform_driver_register(&mmp_pdma_driver); + + return 0; +} +INIT_SUBSYS_EXPORT(mmp_pdma_drv_register); diff --git a/bsp/spacemit/dm/dvfs/SConscript b/bsp/spacemit/dm/dvfs/SConscript new file mode 100644 index 000000000000..f56996e72966 --- /dev/null +++ b/bsp/spacemit/dm/dvfs/SConscript @@ -0,0 +1,16 @@ +from building import * + +group = [] + +if not GetDepend(['RT_USING_DVFS']): + Return('group') + +cwd = GetCurrentDir() +list = os.listdir(cwd) + +for d in list: + path = os.path.join(cwd, d) + if os.path.isfile(os.path.join(path, 'SConscript')): + group = group + SConscript(os.path.join(d, 'SConscript')) + +Return('group') diff --git a/bsp/spacemit/dm/dvfs/cpufreq/Kconfig b/bsp/spacemit/dm/dvfs/cpufreq/Kconfig new file mode 100644 index 000000000000..b0f6170177e6 --- /dev/null +++ b/bsp/spacemit/dm/dvfs/cpufreq/Kconfig @@ -0,0 +1,11 @@ +config RT_DVFS_SPACEMIT_CPUFREQ + bool "Spacemit K1/M1 CPUfreq driver" + depends on RT_USING_DVFS + depends on RT_USING_OFW + depends on SOC_SPACEMIT_K1 + depends on RT_CLK_SPACEMIT_K1X + depends on RT_REGULATOR_SPACEMIT_PMIC + default y + help + Enable CPU DVFS for the Spacemit K1/M1 shared CPU voltage domain. + Both CPU clusters and their TCM/ACE clocks are switched together. diff --git a/bsp/spacemit/dm/dvfs/cpufreq/SConscript b/bsp/spacemit/dm/dvfs/cpufreq/SConscript new file mode 100644 index 000000000000..3f1244a16cd0 --- /dev/null +++ b/bsp/spacemit/dm/dvfs/cpufreq/SConscript @@ -0,0 +1,11 @@ +from building import * + +cwd = GetCurrentDir() +src = [] + +if GetDepend(['RT_DVFS_SPACEMIT_CPUFREQ']): + src += ['dvfs-spacemit-cpufreq.c'] + +group = DefineGroup('DeviceDrivers', src, depend = ['']) + +Return('group') diff --git a/bsp/spacemit/dm/dvfs/cpufreq/dvfs-spacemit-cpufreq.c b/bsp/spacemit/dm/dvfs/cpufreq/dvfs-spacemit-cpufreq.c new file mode 100644 index 000000000000..d950bb8d9cb8 --- /dev/null +++ b/bsp/spacemit/dm/dvfs/cpufreq/dvfs-spacemit-cpufreq.c @@ -0,0 +1,864 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#include +#include +#include + +#include +#include +#include + +#define DBG_TAG "dvfs.spacemit" +#define DBG_LVL DBG_INFO +#include + +#define SPACEMIT_PRODUCT_ID_M1 0x36070000U +#define SPACEMIT_K1_MAX_FREQ 1600000000UL +#define SPACEMIT_M1_MAX_FREQ 1800000000UL +#define SPACEMIT_TURBO0_FREQ 1600000000UL +#define SPACEMIT_TURBO1_FREQ 3200000000UL +#define SPACEMIT_STABLE_FREQ 1200000000UL +#define SPACEMIT_FREQ_TOLERANCE 1000000UL +#define SPACEMIT_STABLE_TOLERANCE 50000000UL +#define SPACEMIT_DEFAULT_CCI_FREQ 614000000UL +#define SPACEMIT_DEFAULT_LATENCY_NS 200000U +#define SPACEMIT_DEFAULT_RETRY_NS 100000U +#define SPACEMIT_DRO_TABLE0_MAX 135U +#define SPACEMIT_DRO_TABLE1_MAX 142U + +struct spacemit_cpufreq_opp +{ + rt_ubase_t cluster_hz[2]; + rt_ubase_t tcm_hz; + rt_ubase_t ace_hz; +}; + +struct spacemit_cpufreq +{ + struct rt_dvfs_cpufreq cpufreq; + struct rt_platform_device *pdev; + struct rt_ofw_node *cpu_np; + struct rt_ofw_node *opp_np; + + struct rt_regulator *supply; + struct rt_clk *cluster[2]; + struct rt_clk *ace[2]; + struct rt_clk *tcm; + struct rt_clk *cci; + struct rt_clk *pll3; + struct rt_clk *hi[2]; + + struct rt_mutex lock; + rt_bool_t lock_ready; + rt_bool_t dev_registered; + rt_bool_t is_m1; + rt_uint32_t silicon_id; + rt_uint32_t opp_index; +}; + +static struct spacemit_cpufreq *spacemit_cpufreq_data; + +static rt_ubase_t rate_delta(rt_ubase_t a, rt_ubase_t b) +{ + return a > b ? a - b : b - a; +} + +static rt_bool_t rate_matches(rt_ubase_t actual, rt_ubase_t target) +{ + return rate_delta(actual, target) <= SPACEMIT_FREQ_TOLERANCE; +} + +static rt_ubase_t spacemit_mux_hw_rate(struct rt_clk *clk) +{ + rt_uint8_t parent_index; + struct rt_clk_cell *parent_cell; + + parent_index = rt_clk_cell_get_parent_index(clk->cell); + if (parent_index == RT_UINT8_MAX) + { + return 0; + } + + parent_cell = rt_clk_cell_get_parent_by_index(clk->cell, parent_index); + + return parent_cell ? rt_clk_cell_get_rate(parent_cell) : 0; +} + +static rt_err_t spacemit_get_clk(struct rt_ofw_node *np, const char *name, + struct rt_clk **out_clk) +{ + struct rt_clk *clk; + + clk = rt_ofw_get_clk_by_name(np, name); + + if (rt_is_err_or_null(clk)) + { + rt_err_t err = clk ? rt_ptr_err(clk) : -RT_ENOENT; + + LOG_E("%s: get clock %s failed: %s", + rt_ofw_node_full_name(np), name, rt_strerror(err)); + return err; + } + + *out_clk = clk; + + return RT_EOK; +} + +static rt_err_t spacemit_set_rate(struct rt_clk *clk, rt_ubase_t target, + const char *name, rt_ubase_t tolerance) +{ + rt_err_t err; + rt_ubase_t actual; + + if ((err = rt_clk_set_rate(clk, target))) + { + LOG_E("set %s to %lu Hz failed: %s", name, target, rt_strerror(err)); + return err; + } + + actual = rt_clk_get_rate(clk); + if (rate_delta(actual, target) > tolerance) + { + LOG_E("%s rate mismatch: requested %lu Hz, got %lu Hz", + name, target, actual); + return -RT_EIO; + } + + return RT_EOK; +} + +static rt_err_t spacemit_set_mux_rate(struct rt_clk *clk, rt_ubase_t target, + const char *name, rt_ubase_t tolerance) +{ + rt_err_t err; + rt_ubase_t actual; + + if ((err = rt_clk_set_rate(clk, target))) + { + LOG_E("set %s to %lu Hz failed: %s", name, target, rt_strerror(err)); + return err; + } + + actual = spacemit_mux_hw_rate(clk); + if (!actual || rate_delta(actual, target) > tolerance) + { + LOG_E("%s hardware rate mismatch: requested %lu Hz, got %lu Hz", + name, target, actual); + return -RT_EIO; + } + + return RT_EOK; +} + +static rt_err_t spacemit_set_binary_div(struct rt_clk *clk, const char *name) +{ + struct rt_clk *parent = rt_clk_get_parent(clk); + rt_ubase_t parent_rate; + + if (!parent || !(parent_rate = rt_clk_get_rate(parent))) + { + LOG_E("%s has no valid parent rate", name); + return -RT_EIO; + } + + return spacemit_set_rate(clk, parent_rate / 2, name, + SPACEMIT_FREQ_TOLERANCE); +} + +static rt_err_t spacemit_set_voltage(struct spacemit_cpufreq *priv, + rt_ubase_t uvolt) +{ + rt_err_t err = rt_regulator_set_voltage(priv->supply, uvolt, uvolt); + + if (err) + { + LOG_E("set CPU voltage to %lu uV failed: %s", uvolt, + rt_strerror(err)); + } + + return err; +} + +static int spacemit_current_voltage(struct rt_dvfs_scaling *scaling, + struct spacemit_cpufreq *priv) +{ + int uvolt = rt_regulator_get_voltage(priv->supply); + + if (uvolt <= 0 && scaling->opp_table && scaling->opp_table->current_opp) + { + uvolt = (int)scaling->opp_table->current_opp->uvolt; + } + + return uvolt; +} + +static rt_err_t spacemit_prepare_dependent_clks(struct spacemit_cpufreq *priv) +{ + rt_err_t err; + + if ((err = spacemit_set_binary_div(priv->ace[0], "ace0"))) + { + return err; + } + if ((err = spacemit_set_binary_div(priv->ace[1], "ace1"))) + { + return err; + } + + return spacemit_set_binary_div(priv->tcm, "tcm"); +} + +static rt_err_t spacemit_finish_dependent_clks(struct spacemit_cpufreq *priv, + const struct spacemit_cpufreq_opp *opp_data) +{ + rt_err_t err; + + if ((err = spacemit_set_rate(priv->tcm, opp_data->tcm_hz, "tcm", + SPACEMIT_FREQ_TOLERANCE))) + { + return err; + } + if ((err = spacemit_set_rate(priv->ace[0], opp_data->ace_hz, "ace0", + SPACEMIT_FREQ_TOLERANCE))) + { + return err; + } + + return spacemit_set_rate(priv->ace[1], opp_data->ace_hz, "ace1", + SPACEMIT_FREQ_TOLERANCE); +} + +static rt_err_t spacemit_prepare_turbo_clks(struct spacemit_cpufreq *priv, + rt_ubase_t old_freq, rt_ubase_t new_freq) +{ + rt_err_t err; + + if (new_freq < SPACEMIT_TURBO0_FREQ) + { + return RT_EOK; + } + + if (old_freq >= SPACEMIT_TURBO0_FREQ) + { + if ((err = spacemit_set_mux_rate(priv->cluster[0], + SPACEMIT_STABLE_FREQ, "cls0-stable", + SPACEMIT_STABLE_TOLERANCE))) + { + return err; + } + if ((err = spacemit_set_mux_rate(priv->cluster[1], + SPACEMIT_STABLE_FREQ, "cls1-stable", + SPACEMIT_STABLE_TOLERANCE))) + { + return err; + } + } + + if (new_freq == SPACEMIT_TURBO0_FREQ) + { + if ((err = spacemit_set_rate(priv->pll3, SPACEMIT_TURBO1_FREQ, + "pll3", SPACEMIT_FREQ_TOLERANCE))) + { + return err; + } + } + else + { + if ((err = spacemit_set_rate(priv->pll3, new_freq, "pll3", + SPACEMIT_FREQ_TOLERANCE))) + { + return err; + } + } + + if ((err = spacemit_set_mux_rate(priv->hi[0], new_freq, "c0hi", + SPACEMIT_FREQ_TOLERANCE))) + { + return err; + } + + return spacemit_set_mux_rate(priv->hi[1], new_freq, "c1hi", + SPACEMIT_FREQ_TOLERANCE); +} + +static rt_err_t spacemit_cpufreq_set_opp(struct rt_dvfs_scaling *scaling, + struct rt_dvfs_opp *opp) +{ + rt_err_t err; + int old_uvolt; + rt_bool_t voltage_raised = RT_FALSE; + rt_ubase_t old_rate[2], old_freq, new_freq; + struct spacemit_cpufreq *priv = scaling->priv; + struct spacemit_cpufreq_opp *opp_data = opp->priv; + + if (!priv || !opp_data) + { + return -RT_EINVAL; + } + + if ((err = rt_mutex_take(&priv->lock, RT_WAITING_FOREVER))) + { + return err; + } + + old_rate[0] = spacemit_mux_hw_rate(priv->cluster[0]); + old_rate[1] = spacemit_mux_hw_rate(priv->cluster[1]); + old_freq = rt_max(old_rate[0], old_rate[1]); + new_freq = rt_max(opp_data->cluster_hz[0], opp_data->cluster_hz[1]); + old_uvolt = spacemit_current_voltage(scaling, priv); + + if ((old_uvolt > 0 && opp->uvolt > (rt_ubase_t)old_uvolt) || + (old_uvolt <= 0 && new_freq > old_freq)) + { + if ((err = spacemit_set_voltage(priv, opp->uvolt))) + { + goto _out; + } + + voltage_raised = RT_TRUE; + rt_dvfs_ns_sleep(scaling->transition_latency); + } + + if ((err = spacemit_prepare_dependent_clks(priv))) + { + goto _out; + } + if ((err = spacemit_prepare_turbo_clks(priv, old_freq, new_freq))) + { + goto _out; + } + + { + rt_err_t err0, err1; + + err0 = spacemit_set_mux_rate(priv->cluster[0], opp_data->cluster_hz[0], + "cls0", SPACEMIT_FREQ_TOLERANCE); + err1 = spacemit_set_mux_rate(priv->cluster[1], opp_data->cluster_hz[1], + "cls1", SPACEMIT_FREQ_TOLERANCE); + if (err0 || err1) + { + err = err0 ? err0 : err1; + goto _out; + } + } + + if ((err = spacemit_finish_dependent_clks(priv, opp_data))) + { + goto _out; + } + + if (old_uvolt > 0 && opp->uvolt < (rt_ubase_t)old_uvolt && + !voltage_raised) + { + if ((err = spacemit_set_voltage(priv, opp->uvolt))) + { + goto _out; + } + } + + scaling->cur_freq = opp->freq; + scaling->opp_table->current_opp = opp; + + LOG_D("CPU OPP: %lu Hz @ %lu uV (hw %lu/%lu Hz)", + opp->freq, opp->uvolt, + spacemit_mux_hw_rate(priv->cluster[0]), + spacemit_mux_hw_rate(priv->cluster[1])); + +_out: + if (err && voltage_raised) + { + LOG_W("CPU clock transition failed after voltage raise; keeping %lu uV", + opp->uvolt); + } + + rt_mutex_release(&priv->lock); + + return err; +} + +static const struct rt_dvfs_scaling_ops spacemit_cpufreq_ops = +{ + .set_opp = spacemit_cpufreq_set_opp, +}; + +static int spacemit_select_opp_index(struct spacemit_cpufreq *priv) +{ + rt_uint32_t wafer = 0, product = 0, dro = 0; + struct rt_ofw_node *root, *cpus; + int index = 0; + + root = rt_ofw_find_node_by_path("/"); + if (root) + { + rt_ofw_prop_read_u32(root, "wafer-id", &wafer); + rt_ofw_prop_read_u32(root, "product-id", &product); + rt_ofw_node_put(root); + } + + priv->silicon_id = (wafer << 16) | (product & 0xffffU); + priv->is_m1 = priv->silicon_id == SPACEMIT_PRODUCT_ID_M1; + + cpus = rt_ofw_find_node_by_path("/cpus"); + if (cpus) + { + rt_ofw_prop_read_u32(cpus, "svt-dro", &dro); + rt_ofw_node_put(cpus); + } + + if (priv->is_m1) + { + if (dro <= SPACEMIT_DRO_TABLE0_MAX) + { + index = 0; + } + else if (dro <= SPACEMIT_DRO_TABLE1_MAX) + { + index = 1; + } + else + { + index = 2; + } + } + + LOG_D("silicon=0x%08x svt-dro=%u OPP table=%d max=%lu Hz", + priv->silicon_id, dro, index, + priv->is_m1 ? SPACEMIT_M1_MAX_FREQ : SPACEMIT_K1_MAX_FREQ); + + return index; +} + +static rt_err_t spacemit_parse_opps(struct spacemit_cpufreq *priv, + struct rt_dvfs_scaling *scaling) +{ + int count = 0; + struct rt_ofw_node *opp_np; + + rt_ofw_foreach_available_child_node(priv->opp_np, opp_np) + { + int hz_nr; + rt_uint32_t uvolt = 0, latency = 0; + rt_uint64_t hz[2] = {0}, tcm_hz = 0, ace_hz = 0; + struct rt_dvfs_opp *opp; + struct spacemit_cpufreq_opp *opp_data; + + hz_nr = rt_ofw_prop_read_u64_array_index(opp_np, "opp-hz", 0, + RT_ARRAY_SIZE(hz), hz); + if (hz_nr < 1 || rt_ofw_prop_read_u32(opp_np, "opp-microvolt", &uvolt)) + { + LOG_W("skip invalid OPP %s", rt_ofw_node_full_name(opp_np)); + continue; + } + + if (hz_nr < 2) + { + hz[1] = hz[0]; + } + if (rt_ofw_prop_read_u64(opp_np, "tcm-hz", &tcm_hz)) + { + tcm_hz = hz[0] / 2; + } + if (rt_ofw_prop_read_u64(opp_np, "ace-hz", &ace_hz)) + { + ace_hz = hz[0] / 2; + } + + if (!(opp_data = rt_calloc(1, sizeof(*opp_data)))) + { + return -RT_ENOMEM; + } + + opp_data->cluster_hz[0] = (rt_ubase_t)hz[0]; + opp_data->cluster_hz[1] = (rt_ubase_t)hz[1]; + opp_data->tcm_hz = (rt_ubase_t)tcm_hz; + opp_data->ace_hz = (rt_ubase_t)ace_hz; + + opp = rt_dvfs_scaling_add_opp(scaling, (rt_ubase_t)hz[0], uvolt); + if (!opp) + { + rt_free(opp_data); + return -RT_ENOMEM; + } + + opp->priv = opp_data; + if (!priv->is_m1 && opp->freq > SPACEMIT_K1_MAX_FREQ) + { + opp->available = RT_FALSE; + } + + if (!rt_ofw_prop_read_u32(opp_np, "clock-latency-ns", &latency) && + latency > scaling->transition_latency) + { + scaling->transition_latency = latency; + } + + ++count; + } + + if (!count) + { + return -RT_ENOENT; + } + + scaling->opp_table->share = RT_TRUE; + scaling->opp_table->priv = priv->opp_np; + + return RT_EOK; +} + +static void spacemit_free_opps(struct rt_dvfs_scaling *scaling) +{ + struct rt_dvfs_opp *opp; + + if (!scaling->opp_table) + { + return; + } + + rt_list_for_each_entry(opp, &scaling->opp_table->opp_nodes, list) + { + rt_free(opp->priv); + opp->priv = RT_NULL; + } + + rt_dvfs_scaling_remove_opp_all(scaling); + rt_free(scaling->opp_table); + scaling->opp_table = RT_NULL; +} + +static rt_err_t spacemit_get_resources(struct spacemit_cpufreq *priv) +{ + rt_err_t err; + struct rt_device *dev = &priv->pdev->parent; + + if ((err = spacemit_get_clk(priv->cpu_np, "cls0", &priv->cluster[0])) || + (err = spacemit_get_clk(priv->cpu_np, "cls1", &priv->cluster[1])) || + (err = spacemit_get_clk(priv->opp_np, "ace0", &priv->ace[0])) || + (err = spacemit_get_clk(priv->opp_np, "ace1", &priv->ace[1])) || + (err = spacemit_get_clk(priv->opp_np, "tcm", &priv->tcm)) || + (err = spacemit_get_clk(priv->opp_np, "cci", &priv->cci)) || + (err = spacemit_get_clk(priv->opp_np, "pll3", &priv->pll3)) || + (err = spacemit_get_clk(priv->opp_np, "c0hi", &priv->hi[0])) || + (err = spacemit_get_clk(priv->opp_np, "c1hi", &priv->hi[1]))) + { + return err; + } + + priv->supply = rt_regulator_get(dev, "clst"); + if (rt_is_err_or_null(priv->supply)) + { + err = priv->supply ? rt_ptr_err(priv->supply) : -RT_ENOENT; + priv->supply = RT_NULL; + LOG_E("get clst supply failed: %s", rt_strerror(err)); + return err; + } + + return RT_EOK; +} + +static void spacemit_put_resources(struct spacemit_cpufreq *priv) +{ + struct rt_clk **clks[] = + { + &priv->cluster[0], &priv->cluster[1], + &priv->ace[0], &priv->ace[1], &priv->tcm, &priv->cci, + &priv->pll3, &priv->hi[0], &priv->hi[1], + }; + + for (int i = 0; i < RT_ARRAY_SIZE(clks); ++i) + { + if (*clks[i]) + { + rt_clk_put(*clks[i]); + *clks[i] = RT_NULL; + } + } + + if (priv->supply) + { + rt_regulator_put(priv->supply); + priv->supply = RT_NULL; + } +} + +static struct rt_dvfs_opp *spacemit_closest_opp( + struct rt_dvfs_scaling *scaling, rt_ubase_t rate) +{ + rt_ubase_t best_delta = ~0UL; + struct rt_dvfs_opp *opp, *best = RT_NULL; + + rt_list_for_each_entry(opp, &scaling->opp_table->opp_nodes, list) + { + rt_ubase_t delta; + + if (!opp->available || opp->freq > scaling->max_freq) + { + continue; + } + + delta = rate_delta(rate, opp->freq); + if (!best || delta < best_delta) + { + best = opp; + best_delta = delta; + } + } + + return best; +} + +static rt_err_t spacemit_sync_hw_state(struct spacemit_cpufreq *priv, + struct rt_dvfs_scaling *scaling) +{ + rt_err_t err; + int uvolt; + rt_ubase_t rate[2], max_rate; + struct rt_dvfs_opp *opp; + struct spacemit_cpufreq_opp *opp_data; + + rate[0] = spacemit_mux_hw_rate(priv->cluster[0]); + rate[1] = spacemit_mux_hw_rate(priv->cluster[1]); + max_rate = rt_max(rate[0], rate[1]); + opp = spacemit_closest_opp(scaling, max_rate); + if (!opp) + { + return -RT_ENOENT; + } + + opp_data = opp->priv; + if (rate_matches(rate[0], opp_data->cluster_hz[0]) && + rate_matches(rate[1], opp_data->cluster_hz[1])) + { + uvolt = rt_regulator_get_voltage(priv->supply); + if (uvolt > 0 && (rt_ubase_t)uvolt < opp->uvolt) + { + if ((err = spacemit_set_voltage(priv, opp->uvolt))) + { + return err; + } + rt_dvfs_ns_sleep(scaling->transition_latency); + } + + if ((err = spacemit_finish_dependent_clks(priv, opp_data))) + { + return err; + } + + scaling->cur_freq = opp->freq; + scaling->opp_table->current_opp = opp; + return RT_EOK; + } + + LOG_W("synchronizing boot CPU clocks %lu/%lu Hz to OPP %lu Hz", + rate[0], rate[1], opp->freq); + + scaling->cur_freq = max_rate; + scaling->opp_table->current_opp = RT_NULL; + + return rt_dvfs_scaling_apply_opp(scaling, opp); +} + +static void spacemit_fill_cpu_map(struct rt_dvfs_cpufreq *cpufreq) +{ + int cpu_id = 0; + struct rt_ofw_node *cpu_np = RT_NULL; + + cpufreq->master_cpu = 0; + rt_ofw_foreach_cpu_node(cpu_np) + { + if (cpu_id < RT_CPUS_NR) + { + rt_bitmap_set_bit(cpufreq->cpus_map, cpu_id); + } + ++cpu_id; + } +} + +static void spacemit_cpufreq_destroy(struct spacemit_cpufreq *priv, + rt_bool_t scaling_registered) +{ + struct rt_dvfs_scaling *scaling; + + if (!priv) + { + return; + } + + scaling = rt_dvfs_cpufreq_to_scaling(&priv->cpufreq); + if (scaling_registered) + { + rt_dvfs_cpufreq_unregister(&priv->cpufreq); + } + + spacemit_free_opps(scaling); + spacemit_put_resources(priv); + + if (priv->lock_ready) + { + rt_mutex_detach(&priv->lock); + } + + if (priv->pdev) + { + if (priv->dev_registered) + { + rt_device_unregister(&priv->pdev->parent); + } + rt_ofw_node_put(priv->pdev->parent.ofw_node); + rt_free(priv->pdev); + } + rt_ofw_node_put(priv->opp_np); + rt_ofw_node_put(priv->cpu_np); + rt_free(priv); +} + +static int spacemit_dvfs_cpufreq_init(void) +{ + rt_err_t err; + rt_uint64_t cci_hz = SPACEMIT_DEFAULT_CCI_FREQ; + rt_ubase_t boot_freq; + struct rt_device *dev; + struct rt_ofw_node *saved_np; + struct spacemit_cpufreq *priv; + struct rt_dvfs_scaling *scaling; + + if (spacemit_cpufreq_data) + { + return RT_EOK; + } + + if (!(priv = rt_calloc(1, sizeof(*priv)))) + { + return -RT_ENOMEM; + } + + priv->cpu_np = rt_ofw_get_next_cpu_node(RT_NULL); + if (!priv->cpu_np) + { + err = -RT_ENOENT; + goto _fail; + } + + priv->opp_index = spacemit_select_opp_index(priv); + priv->opp_np = rt_ofw_parse_phandle(priv->cpu_np, "operating-points-v2", + priv->opp_index); + if (!priv->opp_np && priv->opp_index) + { + LOG_W("OPP table %u missing, falling back to table 0", priv->opp_index); + priv->opp_index = 0; + priv->opp_np = rt_ofw_parse_phandle(priv->cpu_np, + "operating-points-v2", 0); + } + if (!priv->opp_np) + { + err = -RT_ENOENT; + goto _fail; + } + + if (!(priv->pdev = rt_platform_device_alloc("cpufreq"))) + { + err = -RT_ENOMEM; + goto _fail; + } + + dev = &priv->pdev->parent; + dev->ofw_node = rt_ofw_node_get(priv->cpu_np); + rt_dm_dev_set_name_auto(dev, "cpufreq"); + + if ((err = rt_device_register(dev, rt_dm_dev_get_name(dev), + RT_DEVICE_FLAG_DEACTIVATE))) + { + goto _fail; + } + priv->dev_registered = RT_TRUE; + + if ((err = rt_mutex_init(&priv->lock, "k1-cpufreq", RT_IPC_FLAG_PRIO))) + { + goto _fail; + } + priv->lock_ready = RT_TRUE; + + if ((err = spacemit_get_resources(priv))) + { + goto _fail; + } + + scaling = rt_dvfs_cpufreq_to_scaling(&priv->cpufreq); + scaling->dev = dev; + scaling->clk = priv->cluster[0]; + scaling->supply = priv->supply; + scaling->ops = &spacemit_cpufreq_ops; + scaling->priv = priv; + scaling->transition_latency = SPACEMIT_DEFAULT_LATENCY_NS; + scaling->retry_delay = SPACEMIT_DEFAULT_RETRY_NS; + + if ((err = spacemit_parse_opps(priv, scaling))) + { + goto _fail; + } + + scaling->max_freq = priv->is_m1 ? SPACEMIT_M1_MAX_FREQ : + SPACEMIT_K1_MAX_FREQ; + boot_freq = rt_max(spacemit_mux_hw_rate(priv->cluster[0]), + spacemit_mux_hw_rate(priv->cluster[1])); + scaling->cur_freq = boot_freq; + spacemit_fill_cpu_map(&priv->cpufreq); + + rt_ofw_prop_read_u64(priv->opp_np, "cci-hz", &cci_hz); + if ((err = spacemit_set_rate(priv->cci, (rt_ubase_t)cci_hz, "cci", + SPACEMIT_FREQ_TOLERANCE))) + { + goto _fail; + } + + saved_np = dev->ofw_node; + dev->ofw_node = RT_NULL; + err = rt_dvfs_cpufreq_register(&priv->cpufreq); + dev->ofw_node = saved_np; + if (err) + { + goto _fail; + } + + if ((err = spacemit_sync_hw_state(priv, scaling))) + { + LOG_E("sync hardware state failed: %s", rt_strerror(err)); + spacemit_cpufreq_destroy(priv, RT_TRUE); + return err; + } + + if ((err = rt_dvfs_scaling_set_governor(scaling, + RT_DVFS_GOVERNOR_TYPE_ONDEMAND))) + { + LOG_W("ondemand governor unavailable: %s", rt_strerror(err)); + err = rt_dvfs_scaling_set_governor(scaling, + RT_DVFS_GOVERNOR_TYPE_PERFORMANCE); + if (err) + { + spacemit_cpufreq_destroy(priv, RT_TRUE); + return err; + } + } + + spacemit_cpufreq_data = priv; + LOG_D("CPUfreq registered as %s: %lu-%lu Hz, current %lu Hz", + rt_dm_dev_get_name(dev), scaling->min_freq, scaling->max_freq, + scaling->cur_freq); + + return RT_EOK; + +_fail: + LOG_E("CPUfreq initialization failed: %s", rt_strerror(err)); + spacemit_cpufreq_destroy(priv, RT_FALSE); + return err; +} +INIT_APP_EXPORT(spacemit_dvfs_cpufreq_init); diff --git a/bsp/spacemit/dm/ethernet/Kconfig b/bsp/spacemit/dm/ethernet/Kconfig new file mode 100644 index 000000000000..9bae7633a210 --- /dev/null +++ b/bsp/spacemit/dm/ethernet/Kconfig @@ -0,0 +1,14 @@ +config RT_ETHERNET_K1X_EMAC + bool "Spacemit K1X Ethernet MAC" + depends on RT_USING_OFW + depends on RT_USING_DMA + depends on RT_USING_PIN + depends on RT_USING_PHY_V2 + select RT_PHY_V2_REALTEK + default n + +config RT_ETHERNET_K1X_EMAC_PTP + bool "PTP clock support" + depends on RT_ETHERNET_K1X_EMAC + depends on RT_USING_PTP + default y diff --git a/bsp/spacemit/dm/ethernet/SConscript b/bsp/spacemit/dm/ethernet/SConscript new file mode 100644 index 000000000000..ebd6d2d74f14 --- /dev/null +++ b/bsp/spacemit/dm/ethernet/SConscript @@ -0,0 +1,13 @@ +from building import * + +group = [] +src = [] +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../include', cwd + '/../../../../components/drivers/ethernet'] + +if GetDepend(['RT_ETHERNET_K1X_EMAC']): + src += ['eth-k1x-emac.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/spacemit/dm/ethernet/eth-k1x-emac.c b/bsp/spacemit/dm/ethernet/eth-k1x-emac.c new file mode 100644 index 000000000000..c9b8142c1866 --- /dev/null +++ b/bsp/spacemit/dm/ethernet/eth-k1x-emac.c @@ -0,0 +1,1928 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#include +#include +#include + +#ifdef RT_ETHERNET_K1X_EMAC_PTP +#include +#include +#endif +#ifdef RT_USING_SYSTEM_WORKQUEUE +#include +#endif + +#include +#include "ethernet_dm.h" + +#define DBG_TAG "ethernet.k1x" +#define DBG_LVL DBG_INFO +#include + +/* K1X APMU Ethernet control bits. */ +#define K1X_APMU_BASE_DEFAULT 0xd4282800UL +#define K1X_PHY_INTF_RGMII RT_BIT(2) +#define K1X_REF_CLK_SEL RT_BIT(3) +#define K1X_RMII_TX_CLK_SEL RT_BIT(6) +#define K1X_RMII_RX_CLK_SEL RT_BIT(7) +#define K1X_RGMII_TX_CLK_SEL RT_BIT(8) +#define K1X_AXI_SINGLE_ID RT_BIT(13) +#define K1X_RMII_TX_PHASE_SHIFT 16 +#define K1X_RMII_TX_PHASE_MASK RT_GENMASK(18, 16) +#define K1X_RMII_RX_PHASE_SHIFT 20 +#define K1X_RMII_RX_PHASE_MASK RT_GENMASK(22, 20) +#define K1X_RGMII_TX_PHASE_SHIFT 24 +#define K1X_RGMII_TX_PHASE_MASK RT_GENMASK(26, 24) +#define K1X_RGMII_RX_PHASE_SHIFT 28 +#define K1X_RGMII_RX_PHASE_MASK RT_GENMASK(30, 28) + +#define K1X_RX_DLINE_EN RT_BIT(0) +#define K1X_RX_DLINE_CODE_SHIFT 8 +#define K1X_RX_DLINE_CODE_MASK RT_GENMASK(15, 8) +#define K1X_TX_DLINE_EN RT_BIT(16) +#define K1X_TX_DLINE_CODE_SHIFT 24 +#define K1X_TX_DLINE_CODE_MASK RT_GENMASK(31, 24) + +/* DMA registers. */ +#define K1X_DMA_CONFIGURATION 0x0000 +#define K1X_DMA_CONTROL 0x0004 +#define K1X_DMA_STATUS_IRQ 0x0008 +#define K1X_DMA_INTERRUPT_ENABLE 0x000c +#define K1X_DMA_TX_AUTO_POLL_COUNTER 0x0010 +#define K1X_DMA_TX_POLL_DEMAND 0x0014 +#define K1X_DMA_RX_POLL_DEMAND 0x0018 +#define K1X_DMA_TX_BASE 0x001c +#define K1X_DMA_RX_BASE 0x0020 +#define K1X_DMA_RX_IRQ_MITIGATION 0x002c + +/* MAC registers. */ +#define K1X_MAC_GLOBAL_CONTROL 0x0100 +#define K1X_MAC_TRANSMIT_CONTROL 0x0104 +#define K1X_MAC_RECEIVE_CONTROL 0x0108 +#define K1X_MAC_ADDRESS_CONTROL 0x0118 +#define K1X_MAC_ADDRESS1_HIGH 0x0120 +#define K1X_MAC_ADDRESS1_MED 0x0124 +#define K1X_MAC_ADDRESS1_LOW 0x0128 +#define K1X_MAC_HASH_TABLE1 0x0150 +#define K1X_MAC_HASH_TABLE2 0x0154 +#define K1X_MAC_HASH_TABLE3 0x0158 +#define K1X_MAC_HASH_TABLE4 0x015c +#define K1X_MAC_FC_CONTROL 0x0160 +#define K1X_MAC_MDIO_CONTROL 0x01a0 +#define K1X_MAC_MDIO_DATA 0x01a4 +#define K1X_MAC_TX_FIFO_AF 0x01c0 +#define K1X_MAC_TX_THRESHOLD 0x01c4 +#define K1X_MAC_RX_THRESHOLD 0x01c8 +#define K1X_MAC_INTERRUPT_ENABLE 0x01e4 + +#ifdef RT_ETHERNET_K1X_EMAC_PTP +/* PTP 1588 registers. The system timer is a 17-bit fixed-point ns counter. */ +#define K1X_PTP_CONTROL 0x0300 +#define K1X_PTP_INCREMENT 0x0304 +#define K1X_PTP_ETHERTYPE 0x0308 +#define K1X_PTP_MESSAGE_ID 0x030c +#define K1X_PTP_UDP_PORT 0x0310 +#define K1X_PTP_TIME_LOW 0x0320 +#define K1X_PTP_TIME_HIGH 0x0324 +#define K1X_PTP_TX_TIME_LOW 0x0330 +#define K1X_PTP_TX_TIME_HIGH 0x0334 +#define K1X_PTP_RX_TIME_LOW 0x0340 +#define K1X_PTP_RX_TIME_HIGH 0x0344 +#define K1X_PTP_IRQ_STATUS 0x0360 +#define K1X_PTP_IRQ_ENABLE 0x0364 + +#define K1X_PTP_TX_TIMESTAMP_ENABLE RT_BIT(1) +#define K1X_PTP_RX_TIMESTAMP_ENABLE RT_BIT(2) +#define K1X_PTP_RX_TYPE_SHIFT 3 +#define K1X_PTP_RX_TYPE_MASK RT_GENMASK(5, 3) +#define K1X_PTP_RX_TYPE_V2_L2_L4 2U +#define K1X_PTP_IRQ_TX_TIMESTAMP RT_BIT(0) +#define K1X_PTP_IRQ_RX_TIMESTAMP RT_BIT(1) +#define K1X_PTP_IRQ_ALL (K1X_PTP_IRQ_TX_TIMESTAMP | \ + K1X_PTP_IRQ_RX_TIMESTAMP) + +#define K1X_PTP_INCREMENT_MASK RT_GENMASK(23, 0) +#define K1X_PTP_PERIOD_SHIFT 24 +#define K1X_PTP_INCREMENT_SHIFT 17U +#define K1X_PTP_INCREMENT_FRAC_MASK ((1ULL << K1X_PTP_INCREMENT_SHIFT) - 1) +#define K1X_PTP_DEFAULT_INCREMENT (10U << K1X_PTP_INCREMENT_SHIFT) +#define K1X_PTP_DEFAULT_PERIOD 1U +#define K1X_PTP_MAX_ADJ_PPB 1000000000L +#define K1X_PTP_NSEC_PER_SEC 1000000000ULL +#define K1X_PTP_ETHERTYPE_VALUE 0x88f7U +#define K1X_PTP_UDP_EVENT_PORT 319U +#define K1X_PTP_ALL_EVENT_MESSAGES 0x03020100U +#define K1X_PTP_OVERFLOW_POLL_MS (4U * 60U * 60U * 1000U) +#endif + +/* DMA configuration and control. */ +#define K1X_DMA_SOFT_RESET RT_BIT(0) +#define K1X_DMA_STRICT_BURST RT_BIT(17) +#define K1X_DMA_64BIT_MODE RT_BIT(18) +#define K1X_DMA_START_TX RT_BIT(0) +#define K1X_DMA_START_RX RT_BIT(1) + +/* DMA status/interrupt bits. */ +#define K1X_DMA_IRQ_TX_DONE RT_BIT(0) +#define K1X_DMA_IRQ_TX_UNAVAILABLE RT_BIT(1) +#define K1X_DMA_IRQ_TX_STOPPED RT_BIT(2) +#define K1X_DMA_IRQ_RX_DONE RT_BIT(4) +#define K1X_DMA_IRQ_RX_UNAVAILABLE RT_BIT(5) +#define K1X_DMA_IRQ_RX_STOPPED RT_BIT(6) +#define K1X_DMA_IRQ_RX_MISSED RT_BIT(7) +#define K1X_DMA_IRQ_MAC RT_BIT(8) +#define K1X_DMA_IRQ_ALL RT_GENMASK(8, 0) +#define K1X_DMA_IRQ_DEFAULT (K1X_DMA_IRQ_TX_DONE | \ + K1X_DMA_IRQ_TX_UNAVAILABLE | \ + K1X_DMA_IRQ_TX_STOPPED | \ + K1X_DMA_IRQ_RX_DONE | \ + K1X_DMA_IRQ_RX_UNAVAILABLE | \ + K1X_DMA_IRQ_RX_STOPPED | \ + K1X_DMA_IRQ_RX_MISSED) + +/* MAC control bits. */ +#define K1X_MAC_SPEED_MASK RT_GENMASK(1, 0) +#define K1X_MAC_SPEED_10 0 +#define K1X_MAC_SPEED_100 RT_BIT(0) +#define K1X_MAC_SPEED_1000 RT_BIT(1) +#define K1X_MAC_FULL_DUPLEX RT_BIT(2) +#define K1X_MAC_TX_ENABLE RT_BIT(0) +#define K1X_MAC_TX_AUTO_RETRY RT_BIT(3) +#define K1X_MAC_TX_IFG_MASK RT_GENMASK(6, 4) +#define K1X_MAC_RX_ENABLE RT_BIT(0) +#define K1X_MAC_RX_STORE_FORWARD RT_BIT(3) +#define K1X_MAC_ADDR1_ENABLE RT_BIT(0) +#define K1X_MAC_FC_DECODE_ENABLE RT_BIT(0) +#define K1X_MDIO_START RT_BIT(15) +#define K1X_MDIO_READ RT_BIT(10) + +/* RX interrupt mitigation fields. */ +#define K1X_RX_COAL_FRAMES_MASK RT_GENMASK(7, 0) +#define K1X_RX_COAL_TIMEOUT_SHIFT 8 +#define K1X_RX_COAL_TIMEOUT_MASK RT_GENMASK(27, 8) +#define K1X_RX_COAL_ENABLE RT_BIT(31) +#define K1X_AXI_CYCLES_PER_US 312U + +/* Four-word K1X DMA descriptor. */ +struct k1x_emac_desc +{ + volatile rt_uint32_t des0; + volatile rt_uint32_t des1; + volatile rt_uint32_t des2; + volatile rt_uint32_t des3; +}; + +#define K1X_DESC_OWN RT_BIT(31) +#define K1X_RX_DESC_FIRST RT_BIT(30) +#define K1X_RX_DESC_LAST RT_BIT(29) +#define K1X_DESC_END_RING RT_BIT(26) +#define K1X_DESC_BUFFER1_SIZE_MASK RT_GENMASK(11, 0) +#define K1X_TX_DESC_FIRST RT_BIT(29) +#define K1X_TX_DESC_LAST RT_BIT(30) +#define K1X_TX_DESC_IRQ RT_BIT(31) +#define K1X_RX_FRAME_LENGTH_MASK RT_GENMASK(13, 0) +#define K1X_RX_APP_STATUS_SHIFT 14 +#define K1X_RX_APP_STATUS_MASK RT_GENMASK(28, 14) +#define K1X_RX_ERR_ALIGN RT_BIT(0) +#define K1X_RX_ERR_RUNT RT_BIT(1) +#define K1X_RX_ERR_CRC RT_BIT(6) +#define K1X_RX_ERR_MAX_LEN RT_BIT(7) +#define K1X_RX_ERR_JABBER RT_BIT(8) +#define K1X_RX_ERR_LENGTH RT_BIT(9) +#define K1X_RX_ERROR_MASK (K1X_RX_ERR_ALIGN | K1X_RX_ERR_RUNT | \ + K1X_RX_ERR_CRC | K1X_RX_ERR_MAX_LEN | \ + K1X_RX_ERR_JABBER | K1X_RX_ERR_LENGTH) + +#define K1X_EMAC_BUFFER_SIZE 1536U +#define K1X_EMAC_TX_RING_DEFAULT 128U +#define K1X_EMAC_RX_RING_DEFAULT 128U +#define K1X_EMAC_RING_MIN 4U +#define K1X_EMAC_RING_MAX 128U +#define K1X_EMAC_TX_THRESHOLD_DEFAULT 192U +#define K1X_EMAC_RX_THRESHOLD_DEFAULT 12U +#define K1X_EMAC_DMA_BURST_DEFAULT 1U +#define K1X_EMAC_RX_COAL_FRAMES 64U +#define K1X_EMAC_RX_COAL_TIMEOUT_US 120U +#define K1X_EMAC_FCS_SIZE 4U +#define K1X_EMAC_LINK_POLL_MS 2000U +#define K1X_EMAC_DMA_FLAGS (RT_DMA_F_LINEAR | RT_DMA_F_32BITS | \ + RT_DMA_F_NOCACHE) + +enum k1x_clk_tuning_way +{ + K1X_CLK_TUNING_BY_REG, + K1X_CLK_TUNING_BY_DLINE, + K1X_CLK_TUNING_BY_CLK_REVERT, +}; + +struct k1x_emac +{ + struct eth_device parent; + struct rt_device *dev; + + void *base; + void *ctrl_reg; + void *dline_reg; + struct rt_clk *mac_clk; +#ifdef RT_ETHERNET_K1X_EMAC_PTP + struct rt_clk *ptp_clk; +#endif + struct rt_reset_control *rstc; + int irq; + + struct mii_bus *mii; + struct rt_phy_device *phy; + rt_phy_interface phy_interface; + struct rt_mutex mdio_lock; + rt_bool_t mdio_lock_inited; + + rt_uint8_t mac[6]; + rt_bool_t hw_ready; + rt_bool_t net_registered; + rt_bool_t irq_installed; + rt_bool_t link_up; + int speed; + int duplex; + + struct k1x_emac_desc *tx_ring; + struct k1x_emac_desc *rx_ring; + rt_uint8_t *tx_buffers; + rt_uint8_t *rx_buffers; + rt_uint32_t tx_ring_num; + rt_uint32_t rx_ring_num; + rt_uint32_t tx_head; + rt_uint32_t tx_tail; + rt_uint32_t rx_tail; + rt_ubase_t tx_ring_dma; + rt_ubase_t rx_ring_dma; + rt_ubase_t tx_buffers_dma; + rt_ubase_t rx_buffers_dma; + void *dma_blob; + rt_ubase_t dma_blob_handle; + rt_size_t dma_blob_size; + rt_sem_t tx_sem; + struct rt_mutex tx_mutex; + rt_bool_t tx_mutex_inited; + struct rt_spinlock tx_lock; + + rt_uint32_t tx_threshold; + rt_uint32_t rx_threshold; + rt_uint32_t dma_burst_len; + rt_bool_t ref_clk_from_soc; + rt_bool_t clk_tuning_enable; + enum k1x_clk_tuning_way clk_tuning_way; + rt_uint8_t tx_phase; + rt_uint8_t rx_phase; + + rt_base_t phy_reset_pin; + rt_uint8_t phy_reset_active; + rt_uint32_t phy_reset_delays[3]; + +#ifdef RT_ETHERNET_K1X_EMAC_PTP + struct rt_ptp_clock ptp_parent; + struct rt_spinlock ptp_lock; + rt_uint64_t ptp_cycle_last; + rt_uint64_t ptp_nsec; + rt_uint64_t ptp_frac; + rt_uint32_t ptp_clk_rate; + rt_uint32_t ptp_increment; + rt_bool_t ptp_supported; + rt_bool_t ptp_clk_enabled; + rt_bool_t ptp_registered; +#ifdef RT_USING_SYSTEM_WORKQUEUE + struct rt_work ptp_overflow_work; + rt_bool_t ptp_work_inited; + rt_bool_t ptp_stopping; +#endif +#endif + +#ifdef RT_USING_SYSTEM_WORKQUEUE + struct rt_work link_work; + rt_bool_t link_work_inited; + rt_bool_t stopping; +#endif +}; + +#define raw_to_k1x_emac(dev) \ + rt_container_of(dev, struct k1x_emac, parent.parent) +#ifdef RT_ETHERNET_K1X_EMAC_PTP +#define ptp_to_k1x_emac(ptp) \ + rt_container_of(ptp, struct k1x_emac, ptp_parent) +#endif + +rt_inline rt_uint32_t k1x_emac_readl(struct k1x_emac *emac, + rt_uint32_t reg) +{ + return HWREG32((rt_uint8_t *)emac->base + reg); +} + +rt_inline void k1x_emac_writel(struct k1x_emac *emac, + rt_uint32_t reg, rt_uint32_t value) +{ + HWREG32((rt_uint8_t *)emac->base + reg) = value; +} + +static rt_uint32_t k1x_emac_next(rt_uint32_t index, rt_uint32_t count) +{ + return ++index == count ? 0 : index; +} + +#ifdef RT_ETHERNET_K1X_EMAC_PTP +static rt_uint64_t k1x_emac_ptp_read_cycles(struct k1x_emac *emac) +{ + rt_uint64_t low; + rt_uint64_t high; + + /* Reading LOW first latches the matching HIGH word on K1X. */ + low = k1x_emac_readl(emac, K1X_PTP_TIME_LOW); + high = k1x_emac_readl(emac, K1X_PTP_TIME_HIGH); + + return (high << 32) | low; +} + +static rt_uint64_t k1x_emac_ptp_update_locked(struct k1x_emac *emac) +{ + rt_uint64_t now = k1x_emac_ptp_read_cycles(emac); + rt_uint64_t delta = now - emac->ptp_cycle_last; + rt_uint64_t scaled = delta + emac->ptp_frac; + + emac->ptp_frac = scaled & K1X_PTP_INCREMENT_FRAC_MASK; + emac->ptp_nsec += scaled >> K1X_PTP_INCREMENT_SHIFT; + emac->ptp_cycle_last = now; + + return emac->ptp_nsec; +} + +static rt_err_t k1x_emac_ptp_adjfreq(struct rt_ptp_clock *ptp, + rt_base_t freq) +{ + rt_bool_t negative; + rt_uint64_t magnitude; + rt_uint64_t adjustment; + rt_uint32_t increment; + rt_ubase_t level; + struct k1x_emac *emac = ptp_to_k1x_emac(ptp); + + if (freq > K1X_PTP_MAX_ADJ_PPB || freq <= -K1X_PTP_MAX_ADJ_PPB) + { + return -RT_EINVAL; + } + + negative = freq < 0; + magnitude = negative ? (rt_uint64_t)(-(rt_int64_t)freq) : + (rt_uint64_t)freq; + adjustment = (rt_uint64_t)K1X_PTP_DEFAULT_INCREMENT * magnitude / + K1X_PTP_NSEC_PER_SEC; + increment = negative ? K1X_PTP_DEFAULT_INCREMENT - adjustment : + K1X_PTP_DEFAULT_INCREMENT + adjustment; + if (!increment || increment > K1X_PTP_INCREMENT_MASK) + { + return -RT_EINVAL; + } + + level = rt_spin_lock_irqsave(&emac->ptp_lock); + k1x_emac_ptp_update_locked(emac); + k1x_emac_writel(emac, K1X_PTP_INCREMENT, + (K1X_PTP_DEFAULT_PERIOD << K1X_PTP_PERIOD_SHIFT) | + increment); + emac->ptp_increment = increment; + rt_spin_unlock_irqrestore(&emac->ptp_lock, level); + + return RT_EOK; +} + +static rt_err_t k1x_emac_ptp_adjtime(struct rt_ptp_clock *ptp, + rt_int64_t delta) +{ + rt_uint64_t magnitude; + rt_ubase_t level; + struct k1x_emac *emac = ptp_to_k1x_emac(ptp); + + level = rt_spin_lock_irqsave(&emac->ptp_lock); + k1x_emac_ptp_update_locked(emac); + + if (delta < 0) + { + magnitude = (rt_uint64_t)(-(delta + 1)) + 1; + if (magnitude > emac->ptp_nsec) + { + rt_spin_unlock_irqrestore(&emac->ptp_lock, level); + return -RT_EINVAL; + } + emac->ptp_nsec -= magnitude; + } + else + { + magnitude = (rt_uint64_t)delta; + if (magnitude > RT_UINT64_MAX - emac->ptp_nsec) + { + rt_spin_unlock_irqrestore(&emac->ptp_lock, level); + return -RT_EINVAL; + } + emac->ptp_nsec += magnitude; + } + + rt_spin_unlock_irqrestore(&emac->ptp_lock, level); + return RT_EOK; +} + +static rt_err_t k1x_emac_ptp_gettime(struct rt_ptp_clock *ptp, + struct rt_ptp_clock_time *ts) +{ + rt_uint64_t ns; + rt_ubase_t level; + struct k1x_emac *emac = ptp_to_k1x_emac(ptp); + + level = rt_spin_lock_irqsave(&emac->ptp_lock); + ns = k1x_emac_ptp_update_locked(emac); + rt_spin_unlock_irqrestore(&emac->ptp_lock, level); + + ts->sec = ns / K1X_PTP_NSEC_PER_SEC; + ts->nsec = ns % K1X_PTP_NSEC_PER_SEC; + + return RT_EOK; +} + +static rt_err_t k1x_emac_ptp_settime(struct rt_ptp_clock *ptp, + const struct rt_ptp_clock_time *ts) +{ + rt_uint64_t ns; + rt_ubase_t level; + struct k1x_emac *emac = ptp_to_k1x_emac(ptp); + + if (ts->sec < 0 || ts->nsec < 0 || + (rt_uint64_t)ts->nsec >= K1X_PTP_NSEC_PER_SEC || + (rt_uint64_t)ts->sec > + (RT_UINT64_MAX - (rt_uint64_t)ts->nsec) / + K1X_PTP_NSEC_PER_SEC) + { + return -RT_EINVAL; + } + ns = (rt_uint64_t)ts->sec * K1X_PTP_NSEC_PER_SEC + ts->nsec; + + level = rt_spin_lock_irqsave(&emac->ptp_lock); + emac->ptp_cycle_last = k1x_emac_ptp_read_cycles(emac); + emac->ptp_nsec = ns; + emac->ptp_frac = 0; + rt_spin_unlock_irqrestore(&emac->ptp_lock, level); + + return RT_EOK; +} + +static const struct rt_ptp_ops k1x_emac_ptp_ops = +{ + .adjfreq = k1x_emac_ptp_adjfreq, + .adjtime = k1x_emac_ptp_adjtime, + .gettime = k1x_emac_ptp_gettime, + .settime = k1x_emac_ptp_settime, +}; + +static void k1x_emac_ptp_hw_enable(struct k1x_emac *emac) +{ + rt_uint32_t control; + + emac->ptp_increment = K1X_PTP_DEFAULT_INCREMENT; + k1x_emac_writel(emac, K1X_PTP_INCREMENT, + (K1X_PTP_DEFAULT_PERIOD << K1X_PTP_PERIOD_SHIFT) | + emac->ptp_increment); + k1x_emac_writel(emac, K1X_PTP_MESSAGE_ID, + K1X_PTP_ALL_EVENT_MESSAGES); + k1x_emac_writel(emac, K1X_PTP_ETHERTYPE, + K1X_PTP_ETHERTYPE_VALUE); + k1x_emac_writel(emac, K1X_PTP_UDP_PORT, + K1X_PTP_UDP_EVENT_PORT); + + control = K1X_PTP_TX_TIMESTAMP_ENABLE | + K1X_PTP_RX_TIMESTAMP_ENABLE | + ((K1X_PTP_RX_TYPE_V2_L2_L4 << K1X_PTP_RX_TYPE_SHIFT) & + K1X_PTP_RX_TYPE_MASK); + k1x_emac_writel(emac, K1X_PTP_CONTROL, control); + k1x_emac_writel(emac, K1X_PTP_IRQ_STATUS, K1X_PTP_IRQ_ALL); + k1x_emac_writel(emac, K1X_PTP_IRQ_ENABLE, K1X_PTP_IRQ_ALL); + rt_hw_dsb(); +} + +static void k1x_emac_ptp_hw_disable(struct k1x_emac *emac) +{ + k1x_emac_writel(emac, K1X_PTP_IRQ_ENABLE, 0); + k1x_emac_writel(emac, K1X_PTP_CONTROL, 0); + k1x_emac_writel(emac, K1X_PTP_IRQ_STATUS, K1X_PTP_IRQ_ALL); + rt_hw_dsb(); +} + +#ifdef RT_USING_SYSTEM_WORKQUEUE +static void k1x_emac_ptp_overflow_work(struct rt_work *work, void *work_data) +{ + rt_ubase_t level; + struct k1x_emac *emac = work_data; + + RT_UNUSED(work); + + if (emac->ptp_stopping || !emac->ptp_registered) + { + return; + } + + level = rt_spin_lock_irqsave(&emac->ptp_lock); + k1x_emac_ptp_update_locked(emac); + rt_spin_unlock_irqrestore(&emac->ptp_lock, level); + + if (!emac->ptp_stopping) + { + rt_work_submit(&emac->ptp_overflow_work, + rt_tick_from_millisecond(K1X_PTP_OVERFLOW_POLL_MS)); + } +} +#endif + +static rt_err_t k1x_emac_ptp_register(struct k1x_emac *emac) +{ + rt_err_t err; + rt_uint64_t start_ns = 0; + struct timespec now; + struct rt_ptp_clock *ptp = &emac->ptp_parent; + + if (!emac->ptp_supported) + { + return RT_EOK; + } + + emac->ptp_clk = rt_clk_get_by_name(emac->dev, "ptp-clk"); + if (rt_is_err_or_null(emac->ptp_clk)) + { + LOG_E("ptp-clk is missing"); + emac->ptp_clk = RT_NULL; + return -RT_ENOSYS; + } + if ((err = rt_clk_prepare_enable(emac->ptp_clk))) + { + rt_clk_put(emac->ptp_clk); + emac->ptp_clk = RT_NULL; + return err; + } + emac->ptp_clk_enabled = RT_TRUE; + + if (!emac->ptp_clk_rate) + { + emac->ptp_clk_rate = (rt_uint32_t)rt_clk_get_rate(emac->ptp_clk); + } + + rt_spin_lock_init(&emac->ptp_lock); + k1x_emac_ptp_hw_enable(emac); + emac->ptp_cycle_last = k1x_emac_ptp_read_cycles(emac); + if (!clock_gettime(CLOCK_REALTIME, &now) && now.tv_sec >= 0 && + now.tv_nsec >= 0 && + (rt_uint64_t)now.tv_sec <= + (RT_UINT64_MAX - (rt_uint64_t)now.tv_nsec) / + K1X_PTP_NSEC_PER_SEC) + { + start_ns = (rt_uint64_t)now.tv_sec * K1X_PTP_NSEC_PER_SEC + + now.tv_nsec; + } + emac->ptp_nsec = start_ns; + emac->ptp_frac = 0; + + ptp->ops = &k1x_emac_ptp_ops; + ptp->max_freq = K1X_PTP_MAX_ADJ_PPB; + if ((err = rt_ptp_clock_register(ptp))) + { + ptp->ops = RT_NULL; + k1x_emac_ptp_hw_disable(emac); + rt_clk_disable_unprepare(emac->ptp_clk); + emac->ptp_clk_enabled = RT_FALSE; + rt_clk_put(emac->ptp_clk); + emac->ptp_clk = RT_NULL; + return err; + } + emac->ptp_registered = RT_TRUE; + +#ifdef RT_USING_SYSTEM_WORKQUEUE + rt_work_init(&emac->ptp_overflow_work, k1x_emac_ptp_overflow_work, emac); + emac->ptp_work_inited = RT_TRUE; + rt_work_submit(&emac->ptp_overflow_work, + rt_tick_from_millisecond(K1X_PTP_OVERFLOW_POLL_MS)); +#endif + + LOG_D("%s: PTP clock registered as %s, source %u Hz", + rt_dm_dev_get_name(&emac->parent.parent), + rt_dm_dev_get_name(&ptp->parent), emac->ptp_clk_rate); + return RT_EOK; +} + +static void k1x_emac_ptp_unregister(struct k1x_emac *emac) +{ +#ifdef RT_USING_SYSTEM_WORKQUEUE + emac->ptp_stopping = RT_TRUE; + if (emac->ptp_work_inited) + { + rt_work_cancel(&emac->ptp_overflow_work); + emac->ptp_work_inited = RT_FALSE; + } +#endif + + if (emac->ptp_clk_enabled) + { + k1x_emac_ptp_hw_disable(emac); + } + if (emac->ptp_registered) + { + rt_ptp_clock_unregister(&emac->ptp_parent); + emac->ptp_parent.ops = RT_NULL; + emac->ptp_registered = RT_FALSE; + } + if (emac->ptp_clk_enabled) + { + rt_clk_disable_unprepare(emac->ptp_clk); + emac->ptp_clk_enabled = RT_FALSE; + } + if (!rt_is_err_or_null(emac->ptp_clk)) + { + rt_clk_put(emac->ptp_clk); + emac->ptp_clk = RT_NULL; + } +} +#endif + +static void k1x_emac_delay_us(rt_uint32_t delay) +{ + if (delay >= 1000) + { + rt_thread_mdelay((delay + 999) / 1000); + } + else if (delay) + { + rt_hw_us_delay(delay); + } +} + +static void k1x_emac_reset_hw(struct k1x_emac *emac) +{ + k1x_emac_writel(emac, K1X_MAC_INTERRUPT_ENABLE, 0); + k1x_emac_writel(emac, K1X_DMA_INTERRUPT_ENABLE, 0); + k1x_emac_writel(emac, K1X_MAC_RECEIVE_CONTROL, 0); + k1x_emac_writel(emac, K1X_MAC_TRANSMIT_CONTROL, 0); + k1x_emac_writel(emac, K1X_DMA_CONTROL, 0); + k1x_emac_writel(emac, K1X_MAC_GLOBAL_CONTROL, 0x18); + k1x_emac_writel(emac, K1X_MAC_GLOBAL_CONTROL, 0); +} + +static rt_err_t k1x_emac_parse_phy_interface(struct k1x_emac *emac) +{ + rt_err_t err = -RT_ERROR; + struct rt_ofw_node *phy_np; + + phy_np = rt_ofw_parse_phandle(emac->dev->ofw_node, "phy-handle", 0); + if (phy_np) + { + err = rt_ofw_get_interface(phy_np, &emac->phy_interface); + rt_ofw_node_put(phy_np); + } + if (err) + { + err = rt_ofw_get_interface(emac->dev->ofw_node, + &emac->phy_interface); + } + if (err) + { + emac->phy_interface = RT_PHY_INTERFACE_MODE_RGMII; + } + + switch (emac->phy_interface) + { + case RT_PHY_INTERFACE_MODE_RMII: + case RT_PHY_INTERFACE_MODE_RGMII: + case RT_PHY_INTERFACE_MODE_RGMII_ID: + case RT_PHY_INTERFACE_MODE_RGMII_RXID: + case RT_PHY_INTERFACE_MODE_RGMII_TXID: + return RT_EOK; + default: + LOG_E("unsupported PHY interface %d", emac->phy_interface); + return -RT_EINVAL; + } +} + +static rt_err_t k1x_emac_parse_dt(struct k1x_emac *emac) +{ + struct rt_device *dev = emac->dev; + rt_uint32_t apmu_base = K1X_APMU_BASE_DEFAULT; + rt_uint32_t offset; + rt_uint32_t value; + + emac->tx_threshold = K1X_EMAC_TX_THRESHOLD_DEFAULT; + emac->rx_threshold = K1X_EMAC_RX_THRESHOLD_DEFAULT; + emac->tx_ring_num = K1X_EMAC_TX_RING_DEFAULT; + emac->rx_ring_num = K1X_EMAC_RX_RING_DEFAULT; + emac->dma_burst_len = K1X_EMAC_DMA_BURST_DEFAULT; + emac->phy_reset_pin = -1; + + rt_dm_dev_prop_read_u32(dev, "k1x,apmu-base-reg", &apmu_base); + if (rt_dm_dev_prop_read_u32(dev, "ctrl-reg", &offset)) + { + LOG_E("ctrl-reg is missing"); + return -RT_EINVAL; + } + emac->ctrl_reg = rt_ioremap((void *)(rt_ubase_t)(apmu_base + offset), 4); + if (!emac->ctrl_reg) + { + return -RT_ENOMEM; + } + + rt_dm_dev_prop_read_u32(dev, "tx-threshold", &emac->tx_threshold); + rt_dm_dev_prop_read_u32(dev, "rx-threshold", &emac->rx_threshold); + rt_dm_dev_prop_read_u32(dev, "tx-ring-num", &emac->tx_ring_num); + rt_dm_dev_prop_read_u32(dev, "rx-ring-num", &emac->rx_ring_num); + rt_dm_dev_prop_read_u32(dev, "dma-burst-len", &emac->dma_burst_len); + + if (emac->tx_ring_num < K1X_EMAC_RING_MIN) + { + LOG_D("invalid tx-ring-num %u, use %u", emac->tx_ring_num, + K1X_EMAC_TX_RING_DEFAULT); + emac->tx_ring_num = K1X_EMAC_TX_RING_DEFAULT; + } + else if (emac->tx_ring_num > K1X_EMAC_RING_MAX) + { + LOG_D("tx-ring-num %u exceeds BSP limit, clamp to %u", + emac->tx_ring_num, K1X_EMAC_RING_MAX); + emac->tx_ring_num = K1X_EMAC_RING_MAX; + } + if (emac->rx_ring_num < K1X_EMAC_RING_MIN) + { + LOG_D("invalid rx-ring-num %u, use %u", emac->rx_ring_num, + K1X_EMAC_RX_RING_DEFAULT); + emac->rx_ring_num = K1X_EMAC_RX_RING_DEFAULT; + } + else if (emac->rx_ring_num > K1X_EMAC_RING_MAX) + { + LOG_D("rx-ring-num %u exceeds BSP limit, clamp to %u", + emac->rx_ring_num, K1X_EMAC_RING_MAX); + emac->rx_ring_num = K1X_EMAC_RING_MAX; + } + if (!emac->dma_burst_len || emac->dma_burst_len > 7) + { + emac->dma_burst_len = K1X_EMAC_DMA_BURST_DEFAULT; + } + + emac->ref_clk_from_soc = + !rt_dm_dev_prop_read_bool(dev, "ref-clock-from-phy"); + emac->clk_tuning_enable = + rt_dm_dev_prop_read_bool(dev, "clk-tuning-enable"); + if (emac->clk_tuning_enable) + { + if (rt_dm_dev_prop_read_bool(dev, "clk-tuning-by-delayline")) + { + emac->clk_tuning_way = K1X_CLK_TUNING_BY_DLINE; + if (rt_dm_dev_prop_read_u32(dev, "dline-reg", &offset)) + { + LOG_E("dline-reg is missing"); + return -RT_EINVAL; + } + emac->dline_reg = rt_ioremap( + (void *)(rt_ubase_t)(apmu_base + offset), 4); + if (!emac->dline_reg) + { + return -RT_ENOMEM; + } + } + else if (rt_dm_dev_prop_read_bool(dev, "clk-tuning-by-clk-revert")) + { + emac->clk_tuning_way = K1X_CLK_TUNING_BY_CLK_REVERT; + } + else + { + emac->clk_tuning_way = K1X_CLK_TUNING_BY_REG; + } + + if (!rt_dm_dev_prop_read_u32(dev, "tx-phase", &value)) + { + emac->tx_phase = value; + } + if (!rt_dm_dev_prop_read_u32(dev, "rx-phase", &value)) + { + emac->rx_phase = value; + } + } + + emac->phy_reset_pin = rt_pin_get_named_pin(dev, "emac,reset", 0, + RT_NULL, RT_NULL); + emac->phy_reset_active = + rt_dm_dev_prop_read_bool(dev, "emac,reset-active-low") ? + PIN_LOW : PIN_HIGH; + rt_dm_dev_prop_read_u32_array_index(dev, "emac,reset-delays-us", 0, + RT_ARRAY_SIZE(emac->phy_reset_delays), + emac->phy_reset_delays); + +#ifdef RT_ETHERNET_K1X_EMAC_PTP + emac->ptp_supported = rt_dm_dev_prop_read_bool(dev, "ptp-support"); + rt_dm_dev_prop_read_u32(dev, "ptp-clk-rate", &emac->ptp_clk_rate); +#endif + + return k1x_emac_parse_phy_interface(emac); +} + +static void k1x_emac_config_interface(struct k1x_emac *emac) +{ + rt_uint32_t value = HWREG32(emac->ctrl_reg); + + if (emac->phy_interface == RT_PHY_INTERFACE_MODE_RMII) + { + value &= ~K1X_PHY_INTF_RGMII; + if (emac->ref_clk_from_soc) + { + value |= K1X_REF_CLK_SEL; + } + else + { + value &= ~K1X_REF_CLK_SEL; + } + } + else + { + value |= K1X_PHY_INTF_RGMII; + if (emac->ref_clk_from_soc) + { + value |= K1X_RGMII_TX_CLK_SEL; + } + else + { + value &= ~K1X_RGMII_TX_CLK_SEL; + } + } + value |= K1X_AXI_SINGLE_ID; + HWREG32(emac->ctrl_reg) = value; +} + +static rt_err_t k1x_emac_config_clock_phase(struct k1x_emac *emac) +{ + rt_uint32_t value; + + if (!emac->clk_tuning_enable) + { + return RT_EOK; + } + + if (emac->phy_interface == RT_PHY_INTERFACE_MODE_RMII) + { + value = HWREG32(emac->ctrl_reg); + if (emac->clk_tuning_way == K1X_CLK_TUNING_BY_CLK_REVERT) + { + value &= ~(K1X_RMII_TX_CLK_SEL | K1X_RMII_RX_CLK_SEL); + if (emac->tx_phase == 180) + { + value |= K1X_RMII_TX_CLK_SEL; + } + if (emac->rx_phase == 180) + { + value |= K1X_RMII_RX_CLK_SEL; + } + } + else if (emac->clk_tuning_way == K1X_CLK_TUNING_BY_REG) + { + value &= ~(K1X_RMII_TX_PHASE_MASK | K1X_RMII_RX_PHASE_MASK); + value |= (emac->tx_phase & 0x7) << K1X_RMII_TX_PHASE_SHIFT; + value |= (emac->rx_phase & 0x7) << K1X_RMII_RX_PHASE_SHIFT; + } + else + { + return -RT_EINVAL; + } + HWREG32(emac->ctrl_reg) = value; + } + else if (emac->clk_tuning_way == K1X_CLK_TUNING_BY_DLINE) + { + if (!emac->dline_reg) + { + return -RT_EINVAL; + } + value = HWREG32(emac->dline_reg); + value &= ~(K1X_TX_DLINE_CODE_MASK | K1X_RX_DLINE_CODE_MASK); + value |= ((rt_uint32_t)emac->tx_phase << K1X_TX_DLINE_CODE_SHIFT) & + K1X_TX_DLINE_CODE_MASK; + value |= ((rt_uint32_t)emac->rx_phase << K1X_RX_DLINE_CODE_SHIFT) & + K1X_RX_DLINE_CODE_MASK; + value |= K1X_TX_DLINE_EN | K1X_RX_DLINE_EN; + HWREG32(emac->dline_reg) = value; + } + else if (emac->clk_tuning_way == K1X_CLK_TUNING_BY_REG) + { + value = HWREG32(emac->ctrl_reg); + value &= ~(K1X_RGMII_TX_PHASE_MASK | K1X_RGMII_RX_PHASE_MASK); + value |= (emac->tx_phase & 0x7) << K1X_RGMII_TX_PHASE_SHIFT; + value |= (emac->rx_phase & 0x7) << K1X_RGMII_RX_PHASE_SHIFT; + HWREG32(emac->ctrl_reg) = value; + } + else + { + return -RT_EINVAL; + } + + return RT_EOK; +} + +static void k1x_emac_external_phy_reset(struct k1x_emac *emac) +{ + if (emac->phy_reset_pin < 0) + { + return; + } + + rt_pin_write(emac->phy_reset_pin, !emac->phy_reset_active); + rt_pin_mode(emac->phy_reset_pin, PIN_MODE_OUTPUT); + k1x_emac_delay_us(emac->phy_reset_delays[0]); + rt_pin_write(emac->phy_reset_pin, emac->phy_reset_active); + k1x_emac_delay_us(emac->phy_reset_delays[1]); + rt_pin_write(emac->phy_reset_pin, !emac->phy_reset_active); + k1x_emac_delay_us(emac->phy_reset_delays[2]); +} + +static rt_err_t k1x_emac_mdio_wait(struct k1x_emac *emac) +{ + rt_uint32_t value; + + return readl_poll_timeout((rt_uint8_t *)emac->base + K1X_MAC_MDIO_CONTROL, + value, !(value & K1X_MDIO_START), 10, 10000); +} + +static int k1x_emac_mdio_read(struct mii_bus *bus, int addr, int devad, + int reg) +{ + rt_err_t err; + rt_uint32_t command; + struct k1x_emac *emac = bus->priv; + + RT_UNUSED(devad); + + rt_mutex_take(&emac->mdio_lock, RT_WAITING_FOREVER); + err = k1x_emac_mdio_wait(emac); + if (!err) + { + command = (addr & 0x1f) | ((reg & 0x1f) << 5) | + K1X_MDIO_START | K1X_MDIO_READ; + k1x_emac_writel(emac, K1X_MAC_MDIO_DATA, 0); + k1x_emac_writel(emac, K1X_MAC_MDIO_CONTROL, command); + err = k1x_emac_mdio_wait(emac); + } + command = err ? 0 : k1x_emac_readl(emac, K1X_MAC_MDIO_DATA) & 0xffff; + rt_mutex_release(&emac->mdio_lock); + + return err ? err : (int)command; +} + +static int k1x_emac_mdio_write(struct mii_bus *bus, int addr, int devad, + int reg, rt_uint16_t value) +{ + rt_err_t err; + rt_uint32_t command; + struct k1x_emac *emac = bus->priv; + + RT_UNUSED(devad); + + rt_mutex_take(&emac->mdio_lock, RT_WAITING_FOREVER); + err = k1x_emac_mdio_wait(emac); + if (!err) + { + command = (addr & 0x1f) | ((reg & 0x1f) << 5) | K1X_MDIO_START; + k1x_emac_writel(emac, K1X_MAC_MDIO_DATA, value); + k1x_emac_writel(emac, K1X_MAC_MDIO_CONTROL, command); + err = k1x_emac_mdio_wait(emac); + } + rt_mutex_release(&emac->mdio_lock); + + return err; +} + +static int k1x_emac_find_phy_addr(struct k1x_emac *emac) +{ + struct rt_ofw_node *phy_np; + rt_uint32_t reg; + + phy_np = rt_ofw_parse_phandle(emac->dev->ofw_node, "phy-handle", 0); + if (phy_np) + { + if (!rt_ofw_prop_read_u32(phy_np, "reg", ®)) + { + rt_ofw_node_put(phy_np); + return reg; + } + rt_ofw_node_put(phy_np); + } + + for (int addr = 0; addr < 32; ++addr) + { + int id = k1x_emac_mdio_read(emac->mii, addr, + RT_MDIO_DEVAD_NONE, RT_MII_PHYSID1); + + if (id > 0 && id != 0xffff) + { + return addr; + } + } + + return -1; +} + +static rt_err_t k1x_emac_mdio_register(struct k1x_emac *emac) +{ + rt_err_t err; + int alias_id = rt_ofw_get_alias_id(emac->dev->ofw_node, "ethernet"); + + emac->mii = rt_mdio_alloc(); + if (!emac->mii) + { + return -RT_ENOMEM; + } + + emac->mii->priv = emac; + emac->mii->read = k1x_emac_mdio_read; + emac->mii->write = k1x_emac_mdio_write; + rt_snprintf(emac->mii->name, sizeof(emac->mii->name), "k1x-mdio%d", + alias_id < 0 ? 0 : alias_id); + + err = rt_mdio_register(emac->mii); + if (err) + { + rt_free(emac->mii); + emac->mii = RT_NULL; + } + + return err; +} + +static void k1x_emac_mdio_unregister(struct k1x_emac *emac) +{ + if (emac->mii) + { + rt_mdio_unregister(emac->mii); + rt_free(emac->mii); + emac->mii = RT_NULL; + } +} + +static rt_err_t k1x_emac_dma_alloc(struct k1x_emac *emac) +{ + rt_size_t tx_desc_size = sizeof(*emac->tx_ring) * emac->tx_ring_num; + rt_size_t rx_desc_size = sizeof(*emac->rx_ring) * emac->rx_ring_num; + rt_size_t tx_buf_size = K1X_EMAC_BUFFER_SIZE * emac->tx_ring_num; + rt_size_t rx_buf_size = K1X_EMAC_BUFFER_SIZE * emac->rx_ring_num; + rt_size_t rx_desc_offset = RT_ALIGN(tx_desc_size, RT_MM_PAGE_SIZE); + rt_size_t tx_buf_offset = RT_ALIGN(rx_desc_offset + rx_desc_size, + RT_MM_PAGE_SIZE); + rt_size_t rx_buf_offset = RT_ALIGN(tx_buf_offset + tx_buf_size, + RT_MM_PAGE_SIZE); + rt_ubase_t handle; + rt_uint8_t *blob; + + /* Allocates each descriptor ring independently, so both DMA ring + * bases are page aligned. Preserve that requirement in the shared pool. */ + emac->dma_blob_size = rx_buf_offset + rx_buf_size; + blob = rt_dma_alloc(emac->dev, emac->dma_blob_size, &handle, + K1X_EMAC_DMA_FLAGS); + if (!blob) + { + return -RT_ENOMEM; + } + if ((handle & RT_MM_PAGE_MASK) || handle > 0xffffffffULL || + handle + emac->dma_blob_size - 1 > 0xffffffffULL) + { + LOG_E("DMA address %#lx is not page aligned or exceeds the 32-bit aperture", + (unsigned long)handle); + rt_dma_free(emac->dev, emac->dma_blob_size, blob, handle, + K1X_EMAC_DMA_FLAGS); + return -RT_EINVAL; + } + + emac->dma_blob = blob; + emac->dma_blob_handle = handle; + emac->tx_ring = (struct k1x_emac_desc *)blob; + emac->rx_ring = (struct k1x_emac_desc *)(blob + rx_desc_offset); + emac->tx_buffers = blob + tx_buf_offset; + emac->rx_buffers = blob + rx_buf_offset; + emac->tx_ring_dma = handle; + emac->rx_ring_dma = handle + rx_desc_offset; + emac->tx_buffers_dma = handle + tx_buf_offset; + emac->rx_buffers_dma = handle + rx_buf_offset; + rt_memset(blob, 0, emac->dma_blob_size); + + return RT_EOK; +} + +static void k1x_emac_dma_free(struct k1x_emac *emac) +{ + if (emac->dma_blob) + { + rt_dma_free(emac->dev, emac->dma_blob_size, emac->dma_blob, + emac->dma_blob_handle, K1X_EMAC_DMA_FLAGS); + emac->dma_blob = RT_NULL; + } +} + +static void k1x_emac_rx_refill(struct k1x_emac *emac, rt_uint32_t index) +{ + struct k1x_emac_desc *desc = &emac->rx_ring[index]; + rt_ubase_t buffer_dma = emac->rx_buffers_dma + + index * K1X_EMAC_BUFFER_SIZE; + + desc->des0 = 0; + desc->des1 = K1X_EMAC_BUFFER_SIZE & K1X_DESC_BUFFER1_SIZE_MASK; + if (index == emac->rx_ring_num - 1) + { + desc->des1 |= K1X_DESC_END_RING; + } + desc->des2 = (rt_uint32_t)buffer_dma; + desc->des3 = 0; + rt_hw_wmb(); + desc->des0 = K1X_DESC_OWN; + rt_hw_wmb(); +} + +static rt_err_t k1x_emac_rings_init(struct k1x_emac *emac) +{ + char sem_name[RT_NAME_MAX]; + int alias_id = rt_ofw_get_alias_id(emac->dev->ofw_node, "ethernet"); + + for (rt_uint32_t i = 0; i < emac->rx_ring_num; ++i) + { + k1x_emac_rx_refill(emac, i); + } + emac->tx_head = 0; + emac->tx_tail = 0; + emac->rx_tail = 0; + + rt_snprintf(sem_name, sizeof(sem_name), "k1xtx%d", + alias_id < 0 ? 0 : alias_id); + emac->tx_sem = rt_sem_create(sem_name, emac->tx_ring_num - 1, + RT_IPC_FLAG_FIFO); + if (!emac->tx_sem) + { + return -RT_ENOMEM; + } + + rt_spin_lock_init(&emac->tx_lock); + rt_mutex_init(&emac->tx_mutex, "k1xtxm", RT_IPC_FLAG_PRIO); + emac->tx_mutex_inited = RT_TRUE; + + return RT_EOK; +} + +static void k1x_emac_rings_deinit(struct k1x_emac *emac) +{ + if (emac->tx_sem) + { + rt_sem_delete(emac->tx_sem); + emac->tx_sem = RT_NULL; + } + if (emac->tx_mutex_inited) + { + rt_mutex_detach(&emac->tx_mutex); + emac->tx_mutex_inited = RT_FALSE; + } +} + +static void k1x_emac_set_mac_address(struct k1x_emac *emac) +{ + k1x_emac_writel(emac, K1X_MAC_ADDRESS1_HIGH, + ((rt_uint32_t)emac->mac[1] << 8) | emac->mac[0]); + k1x_emac_writel(emac, K1X_MAC_ADDRESS1_MED, + ((rt_uint32_t)emac->mac[3] << 8) | emac->mac[2]); + k1x_emac_writel(emac, K1X_MAC_ADDRESS1_LOW, + ((rt_uint32_t)emac->mac[5] << 8) | emac->mac[4]); +} + +static rt_err_t k1x_emac_hw_init(struct k1x_emac *emac) +{ + rt_uint32_t value; + + k1x_emac_reset_hw(emac); + + k1x_emac_writel(emac, K1X_MAC_ADDRESS_CONTROL, + K1X_MAC_ADDR1_ENABLE); + k1x_emac_writel(emac, K1X_MAC_HASH_TABLE1, 0); + k1x_emac_writel(emac, K1X_MAC_HASH_TABLE2, 0); + k1x_emac_writel(emac, K1X_MAC_HASH_TABLE3, 0); + k1x_emac_writel(emac, K1X_MAC_HASH_TABLE4, 0); + k1x_emac_writel(emac, K1X_MAC_TX_FIFO_AF, 0x1f8); + k1x_emac_writel(emac, K1X_MAC_TX_THRESHOLD, emac->tx_threshold); + k1x_emac_writel(emac, K1X_MAC_RX_THRESHOLD, emac->rx_threshold); + k1x_emac_writel(emac, K1X_MAC_FC_CONTROL, + K1X_MAC_FC_DECODE_ENABLE); + + value = K1X_EMAC_RX_COAL_FRAMES & K1X_RX_COAL_FRAMES_MASK; + value |= ((K1X_EMAC_RX_COAL_TIMEOUT_US * K1X_AXI_CYCLES_PER_US) << + K1X_RX_COAL_TIMEOUT_SHIFT) & K1X_RX_COAL_TIMEOUT_MASK; + value |= K1X_RX_COAL_ENABLE; + k1x_emac_writel(emac, K1X_DMA_RX_IRQ_MITIGATION, value); + + k1x_emac_writel(emac, K1X_DMA_CONFIGURATION, K1X_DMA_SOFT_RESET); + rt_thread_mdelay(10); + k1x_emac_writel(emac, K1X_DMA_CONFIGURATION, 0); + rt_thread_mdelay(10); + + value = K1X_DMA_STRICT_BURST | K1X_DMA_64BIT_MODE | + RT_BIT(emac->dma_burst_len); + k1x_emac_writel(emac, K1X_DMA_CONFIGURATION, value); + k1x_emac_writel(emac, K1X_DMA_STATUS_IRQ, K1X_DMA_IRQ_ALL); + k1x_emac_set_mac_address(emac); + + k1x_emac_writel(emac, K1X_DMA_TX_BASE, + (rt_uint32_t)emac->tx_ring_dma); + k1x_emac_writel(emac, K1X_DMA_RX_BASE, + (rt_uint32_t)emac->rx_ring_dma); + + emac->hw_ready = RT_TRUE; + return RT_EOK; +} + +static void k1x_emac_hw_start(struct k1x_emac *emac) +{ + rt_uint32_t value; + + value = k1x_emac_readl(emac, K1X_MAC_TRANSMIT_CONTROL); + value &= ~K1X_MAC_TX_IFG_MASK; + value |= K1X_MAC_TX_ENABLE | K1X_MAC_TX_AUTO_RETRY; + k1x_emac_writel(emac, K1X_MAC_TRANSMIT_CONTROL, value); + k1x_emac_writel(emac, K1X_DMA_TX_AUTO_POLL_COUNTER, 0); + + value = k1x_emac_readl(emac, K1X_MAC_RECEIVE_CONTROL); + value |= K1X_MAC_RX_ENABLE | K1X_MAC_RX_STORE_FORWARD; + k1x_emac_writel(emac, K1X_MAC_RECEIVE_CONTROL, value); + + value = k1x_emac_readl(emac, K1X_DMA_CONTROL); + value |= K1X_DMA_START_TX | K1X_DMA_START_RX; + k1x_emac_writel(emac, K1X_DMA_CONTROL, value); + k1x_emac_writel(emac, K1X_DMA_RX_POLL_DEMAND, 0xff); + rt_hw_dsb(); +} + +static void k1x_emac_tx_cleanup(struct k1x_emac *emac) +{ + rt_uint32_t released = 0; + rt_ubase_t level = rt_spin_lock_irqsave(&emac->tx_lock); + + while (emac->tx_tail != emac->tx_head) + { + struct k1x_emac_desc *desc = &emac->tx_ring[emac->tx_tail]; + + rt_hw_rmb(); + if (desc->des0 & K1X_DESC_OWN) + { + break; + } + + desc->des0 = 0; + emac->tx_tail = k1x_emac_next(emac->tx_tail, emac->tx_ring_num); + ++released; + } + + rt_spin_unlock_irqrestore(&emac->tx_lock, level); + + while (released--) + { + rt_sem_release(emac->tx_sem); + } +} + +static rt_err_t k1x_emac_adjust_link(struct k1x_emac *emac) +{ + rt_uint32_t control; + + if (!emac->phy || !emac->phy->link) + { + return -RT_ERROR; + } + + control = k1x_emac_readl(emac, K1X_MAC_GLOBAL_CONTROL); + control &= ~(K1X_MAC_SPEED_MASK | K1X_MAC_FULL_DUPLEX); + + if (emac->phy->duplex == DUPLEX_FULL) + { + control |= K1X_MAC_FULL_DUPLEX; + } + switch (emac->phy->speed) + { + case SPEED_1000: + control |= K1X_MAC_SPEED_1000; + break; + case SPEED_100: + control |= K1X_MAC_SPEED_100; + break; + case SPEED_10: + control |= K1X_MAC_SPEED_10; + break; + default: + return -RT_EINVAL; + } + + k1x_emac_writel(emac, K1X_MAC_GLOBAL_CONTROL, control); + emac->speed = emac->phy->speed; + emac->duplex = emac->phy->duplex; + return RT_EOK; +} + +#ifdef RT_USING_SYSTEM_WORKQUEUE +static rt_bool_t k1x_emac_phy_poll_link(struct k1x_emac *emac) +{ + int bmsr; + + bmsr = rt_phy_read(emac->phy, RT_MDIO_DEVAD_NONE, RT_MII_BMSR); + if (bmsr < 0 || bmsr == 0xffff) + { + emac->phy->link = 0; + return RT_FALSE; + } + + /* BMSR link status is latched low, so read it again before deciding. */ + bmsr = rt_phy_read(emac->phy, RT_MDIO_DEVAD_NONE, RT_MII_BMSR); + if (bmsr < 0 || bmsr == 0xffff || !(bmsr & RT_BMSR_LSTATUS)) + { + emac->phy->link = 0; + return RT_FALSE; + } + + emac->phy->link = 1; + if (rt_genphy_parse_link(emac->phy)) + { + emac->phy->link = 0; + return RT_FALSE; + } + + return RT_TRUE; +} + +static void k1x_emac_link_work(struct rt_work *work, void *work_data) +{ + rt_bool_t link; + struct k1x_emac *emac = work_data; + + RT_UNUSED(work); + + if (emac->stopping || !emac->phy) + { + return; + } + + link = k1x_emac_phy_poll_link(emac); + + if (link) + { + if (!emac->link_up || emac->speed != emac->phy->speed || + emac->duplex != emac->phy->duplex) + { + if (!k1x_emac_adjust_link(emac)) + { + LOG_I("%s: link up, %d Mbps, %s duplex", + rt_dm_dev_get_name(&emac->parent.parent), + emac->speed, + emac->duplex == DUPLEX_FULL ? "full" : "half"); + } + } + if (!emac->link_up) + { + emac->link_up = RT_TRUE; + eth_device_linkchange(&emac->parent, RT_TRUE); + } + } + else if (emac->link_up) + { + emac->link_up = RT_FALSE; + emac->speed = 0; + emac->duplex = -1; + LOG_I("%s: link down", rt_dm_dev_get_name(&emac->parent.parent)); + eth_device_linkchange(&emac->parent, RT_FALSE); + } + + if (!emac->stopping) + { + rt_work_submit(&emac->link_work, + rt_tick_from_millisecond(K1X_EMAC_LINK_POLL_MS)); + } +} +#endif + +static rt_err_t k1x_emac_eth_tx(rt_device_t dev, struct pbuf *p) +{ + rt_err_t err = RT_EOK; + rt_uint32_t index; + rt_uint32_t next; + rt_uint32_t length; + rt_uint8_t *buffer; + struct k1x_emac_desc *desc; + struct k1x_emac *emac = raw_to_k1x_emac(dev); + + if (!emac->hw_ready || !emac->link_up || !emac->phy || + !emac->phy->link) + { + return -RT_EBUSY; + } + if (!p || !p->tot_len || p->tot_len > K1X_EMAC_BUFFER_SIZE) + { + return -RT_EINVAL; + } + + rt_mutex_take(&emac->tx_mutex, RT_WAITING_FOREVER); + k1x_emac_tx_cleanup(emac); + if (rt_sem_take(emac->tx_sem, rt_tick_from_millisecond(1000)) != RT_EOK) + { + k1x_emac_tx_cleanup(emac); + if (rt_sem_take(emac->tx_sem, 0) != RT_EOK) + { + LOG_E("%s: TX ring timeout", + rt_dm_dev_get_name(&emac->parent.parent)); + err = -RT_ETIMEOUT; + goto _out_unlock; + } + } + + index = emac->tx_head; + next = k1x_emac_next(index, emac->tx_ring_num); + desc = &emac->tx_ring[index]; + buffer = emac->tx_buffers + index * K1X_EMAC_BUFFER_SIZE; + length = p->tot_len; + pbuf_copy_partial(p, buffer, length, 0); + + desc->des0 = 0; + desc->des1 = (length & K1X_DESC_BUFFER1_SIZE_MASK) | + K1X_TX_DESC_FIRST | K1X_TX_DESC_LAST | K1X_TX_DESC_IRQ; + if (index == emac->tx_ring_num - 1) + { + desc->des1 |= K1X_DESC_END_RING; + } + desc->des2 = (rt_uint32_t)(emac->tx_buffers_dma + + index * K1X_EMAC_BUFFER_SIZE); + desc->des3 = 0; + rt_hw_wmb(); + desc->des0 = K1X_DESC_OWN; + rt_hw_wmb(); + + { + rt_ubase_t level = rt_spin_lock_irqsave(&emac->tx_lock); + emac->tx_head = next; + rt_spin_unlock_irqrestore(&emac->tx_lock, level); + } + + k1x_emac_writel(emac, K1X_DMA_TX_POLL_DEMAND, 0xff); + rt_hw_dsb(); + +_out_unlock: + rt_mutex_release(&emac->tx_mutex); + return err; +} + +static rt_bool_t k1x_emac_rx_desc_valid(rt_uint32_t des0) +{ + rt_uint32_t status = (des0 & K1X_RX_APP_STATUS_MASK) >> + K1X_RX_APP_STATUS_SHIFT; + rt_uint32_t length = des0 & K1X_RX_FRAME_LENGTH_MASK; + + if (!(des0 & K1X_RX_DESC_FIRST) || !(des0 & K1X_RX_DESC_LAST)) + { + return RT_FALSE; + } + if (status & K1X_RX_ERROR_MASK) + { + return RT_FALSE; + } + return length > K1X_EMAC_FCS_SIZE && + length <= K1X_EMAC_BUFFER_SIZE; +} + +static struct pbuf *k1x_emac_eth_rx(rt_device_t dev) +{ + struct k1x_emac *emac = raw_to_k1x_emac(dev); + + for (rt_uint32_t count = 0; count < emac->rx_ring_num; ++count) + { + rt_uint32_t index = emac->rx_tail; + struct k1x_emac_desc *desc = &emac->rx_ring[index]; + rt_uint32_t des0; + struct pbuf *p = RT_NULL; + + rt_hw_rmb(); + des0 = desc->des0; + if (des0 & K1X_DESC_OWN) + { + return RT_NULL; + } + + if (k1x_emac_rx_desc_valid(des0)) + { + rt_uint32_t length = (des0 & K1X_RX_FRAME_LENGTH_MASK) - + K1X_EMAC_FCS_SIZE; + rt_uint8_t *buffer = emac->rx_buffers + + index * K1X_EMAC_BUFFER_SIZE; + + p = pbuf_alloc(PBUF_RAW, length, PBUF_RAM); + if (p) + { + pbuf_take(p, buffer, length); + } + } + + k1x_emac_rx_refill(emac, index); + emac->rx_tail = k1x_emac_next(index, emac->rx_ring_num); + k1x_emac_writel(emac, K1X_DMA_RX_POLL_DEMAND, 0xff); + + if (p) + { + return p; + } + } + + return RT_NULL; +} + +static rt_err_t k1x_emac_eth_control(rt_device_t dev, int cmd, void *args) +{ + struct k1x_emac *emac = raw_to_k1x_emac(dev); + + switch (cmd) + { + case NIOCTL_GADDR: + if (!args) + { + return -RT_EINVAL; + } + rt_memcpy(args, emac->mac, sizeof(emac->mac)); + return RT_EOK; + default: + return -RT_EINVAL; + } +} + +static void k1x_emac_isr(int irq, void *param) +{ + rt_uint32_t status; +#ifdef RT_ETHERNET_K1X_EMAC_PTP + rt_uint32_t ptp_status = 0; +#endif + struct k1x_emac *emac = param; + + RT_UNUSED(irq); + + status = k1x_emac_readl(emac, K1X_DMA_STATUS_IRQ); + status &= K1X_DMA_IRQ_ALL; +#ifdef RT_ETHERNET_K1X_EMAC_PTP + if (emac->ptp_registered) + { + ptp_status = k1x_emac_readl(emac, K1X_PTP_IRQ_STATUS) & + K1X_PTP_IRQ_ALL; + } + if (!status && !ptp_status) +#else + if (!status) +#endif + { + return; + } + if (status) + { + k1x_emac_writel(emac, K1X_DMA_STATUS_IRQ, status); + } +#ifdef RT_ETHERNET_K1X_EMAC_PTP + if (ptp_status) + { + k1x_emac_writel(emac, K1X_PTP_IRQ_STATUS, ptp_status); + } +#endif + + if (status & (K1X_DMA_IRQ_TX_DONE | K1X_DMA_IRQ_TX_UNAVAILABLE | + K1X_DMA_IRQ_TX_STOPPED)) + { + k1x_emac_tx_cleanup(emac); + } + if (status & K1X_DMA_IRQ_RX_UNAVAILABLE) + { + k1x_emac_writel(emac, K1X_DMA_RX_POLL_DEMAND, 0xff); + } + if (emac->net_registered && + (status & (K1X_DMA_IRQ_RX_DONE | K1X_DMA_IRQ_RX_UNAVAILABLE | + K1X_DMA_IRQ_RX_STOPPED | K1X_DMA_IRQ_RX_MISSED))) + { + eth_device_ready(&emac->parent); + } +} + +#ifdef RT_USING_DEVICE_OPS +static const struct rt_device_ops k1x_emac_device_ops = +{ + .control = k1x_emac_eth_control, +}; +#endif + +static rt_err_t k1x_emac_net_register(struct k1x_emac *emac) +{ + rt_err_t err; + +#ifdef RT_USING_DEVICE_OPS + emac->parent.parent.ops = &k1x_emac_device_ops; +#else + emac->parent.parent.control = k1x_emac_eth_control; +#endif + emac->parent.eth_tx = k1x_emac_eth_tx; + emac->parent.eth_rx = k1x_emac_eth_rx; + + err = rt_dm_dev_set_name_auto(&emac->parent.parent, "e"); + if (err < 0) + { + return err; + } + + if (emac->irq >= 0) + { + rt_hw_interrupt_install(emac->irq, k1x_emac_isr, emac, + "k1x-emac"); + rt_hw_interrupt_umask(emac->irq); + emac->irq_installed = RT_TRUE; + } + + err = eth_device_init(&emac->parent, + rt_dm_dev_get_name(&emac->parent.parent)); + if (err) + { + if (emac->irq_installed) + { + rt_hw_interrupt_mask(emac->irq); + rt_pic_detach_irq(emac->irq, emac); + emac->irq_installed = RT_FALSE; + } + return err; + } + + emac->net_registered = RT_TRUE; + eth_device_linkchange(&emac->parent, RT_FALSE); + +#ifdef RT_ETHERNET_K1X_EMAC_PTP + if ((err = k1x_emac_ptp_register(emac))) + { + LOG_W("%s: PTP registration failed: %s", + rt_dm_dev_get_name(&emac->parent.parent), + rt_strerror(err)); + } +#endif + + k1x_emac_writel(emac, K1X_DMA_INTERRUPT_ENABLE, + K1X_DMA_IRQ_DEFAULT); + k1x_emac_hw_start(emac); + +#ifdef RT_USING_SYSTEM_WORKQUEUE + rt_work_init(&emac->link_work, k1x_emac_link_work, emac); + emac->link_work_inited = RT_TRUE; + rt_work_submit(&emac->link_work, 0); +#else + rt_phy_startup(emac->phy); + if (emac->phy->link && !k1x_emac_adjust_link(emac)) + { + emac->link_up = RT_TRUE; + eth_device_linkchange(&emac->parent, RT_TRUE); + } +#endif + + return RT_EOK; +} + +static void k1x_emac_net_unregister(struct k1x_emac *emac) +{ +#ifdef RT_USING_SYSTEM_WORKQUEUE + emac->stopping = RT_TRUE; + if (emac->link_work_inited) + { + rt_work_cancel(&emac->link_work); + emac->link_work_inited = RT_FALSE; + } +#endif + + k1x_emac_writel(emac, K1X_DMA_INTERRUPT_ENABLE, 0); + if (emac->irq_installed) + { + rt_hw_interrupt_mask(emac->irq); + rt_pic_detach_irq(emac->irq, emac); + emac->irq_installed = RT_FALSE; + } + if (emac->net_registered) + { + eth_device_linkchange(&emac->parent, RT_FALSE); + eth_device_deinit(&emac->parent); + emac->net_registered = RT_FALSE; + } +} + +static void k1x_emac_release(struct k1x_emac *emac) +{ + if (!emac) + { + return; + } + +#ifdef RT_ETHERNET_K1X_EMAC_PTP + k1x_emac_ptp_unregister(emac); +#endif + if (emac->base && emac->hw_ready) + { + k1x_emac_reset_hw(emac); + emac->hw_ready = RT_FALSE; + } + if (emac->phy) + { + rt_phy_shutdown(emac->phy); + emac->phy = RT_NULL; + } + k1x_emac_mdio_unregister(emac); + k1x_emac_rings_deinit(emac); + k1x_emac_dma_free(emac); + + if (emac->mdio_lock_inited) + { + rt_mutex_detach(&emac->mdio_lock); + emac->mdio_lock_inited = RT_FALSE; + } + if (!rt_is_err_or_null(emac->rstc)) + { + rt_reset_control_assert(emac->rstc); + rt_reset_control_put(emac->rstc); + } + if (!rt_is_err_or_null(emac->mac_clk)) + { + rt_clk_disable_unprepare(emac->mac_clk); + rt_clk_put(emac->mac_clk); + } + if (emac->dline_reg) + { + rt_iounmap(emac->dline_reg); + } + if (emac->ctrl_reg) + { + rt_iounmap(emac->ctrl_reg); + } + if (emac->base) + { + rt_iounmap(emac->base); + } +} + +static rt_err_t k1x_emac_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + int phy_addr; + struct rt_device *dev = &pdev->parent; + struct k1x_emac *emac = rt_calloc(1, sizeof(*emac)); + + if (!emac) + { + return -RT_ENOMEM; + } + emac->dev = dev; + emac->irq = rt_dm_dev_get_irq(dev, 0); + emac->speed = 0; + emac->duplex = -1; + + emac->base = rt_dm_dev_iomap(dev, 0); + if (!emac->base) + { + err = -RT_EIO; + goto _fail; + } + if ((err = k1x_emac_parse_dt(emac))) + { + goto _fail; + } + + emac->mac_clk = rt_clk_get_by_name(dev, "emac-clk"); + if (rt_is_err_or_null(emac->mac_clk)) + { + LOG_E("emac-clk is missing"); + err = -RT_ENOSYS; + goto _fail; + } + if ((err = rt_clk_prepare_enable(emac->mac_clk))) + { + goto _fail; + } + + emac->rstc = rt_reset_control_get_by_name(dev, "emac-reset"); + if (rt_is_err_or_null(emac->rstc)) + { + LOG_E("emac-reset is missing"); + err = -RT_ENOSYS; + goto _fail; + } + if ((err = rt_reset_control_deassert(emac->rstc))) + { + goto _fail; + } + + rt_mutex_init(&emac->mdio_lock, "k1xmdio", RT_IPC_FLAG_PRIO); + emac->mdio_lock_inited = RT_TRUE; + k1x_emac_config_interface(emac); + if ((err = k1x_emac_config_clock_phase(emac))) + { + goto _fail; + } + k1x_emac_external_phy_reset(emac); + + if ((err = k1x_emac_dma_alloc(emac))) + { + goto _fail; + } + if ((err = k1x_emac_rings_init(emac))) + { + goto _fail; + } + if ((err = k1x_emac_hw_init(emac))) + { + goto _fail; + } + if ((err = k1x_emac_mdio_register(emac))) + { + goto _fail; + } + + phy_addr = k1x_emac_find_phy_addr(emac); + if (phy_addr < 0) + { + LOG_E("no PHY found on MDIO"); + err = -RT_ENOSYS; + goto _fail; + } + LOG_D("%s: PHY attach begin at address %d", + rt_dm_dev_get_name(dev), phy_addr); + emac->phy = rt_phy_get_device(emac->mii, dev->ofw_node, phy_addr, + emac->phy_interface); + if (!emac->phy) + { + LOG_E("PHY attach failed at address %d", phy_addr); + err = -RT_ERROR; + goto _fail; + } + LOG_D("%s: PHY attach done, config begin", rt_dm_dev_get_name(dev)); + if ((err = rt_phy_config(emac->phy)) < 0) + { + LOG_E("PHY config failed: %s", rt_strerror(err)); + goto _fail; + } + LOG_D("%s: PHY config done", rt_dm_dev_get_name(dev)); + + if (rt_ofw_get_mac_addr(dev->ofw_node, emac->mac)) + { + ethernet_random_addr(&emac->parent, emac->mac); + } + k1x_emac_set_mac_address(emac); + + LOG_D("%s: network registration begin", rt_dm_dev_get_name(dev)); + if ((err = k1x_emac_net_register(emac))) + { + LOG_E("%s: network registration failed: %s", + rt_dm_dev_get_name(dev), rt_strerror(err)); + goto _fail; + } + + dev->user_data = emac; + LOG_D("%s: PHY addr %d, MAC %02x:%02x:%02x:%02x:%02x:%02x, rings %u/%u", + rt_dm_dev_get_name(&emac->parent.parent), phy_addr, + emac->mac[0], emac->mac[1], emac->mac[2], emac->mac[3], + emac->mac[4], emac->mac[5], emac->tx_ring_num, + emac->rx_ring_num); + + return RT_EOK; + +_fail: + k1x_emac_release(emac); + rt_free(emac); + return err; +} + +static rt_err_t k1x_emac_remove(struct rt_platform_device *pdev) +{ + struct k1x_emac *emac = pdev->parent.user_data; + + if (!emac) + { + return RT_EOK; + } + + pdev->parent.user_data = RT_NULL; + k1x_emac_net_unregister(emac); + k1x_emac_release(emac); + rt_free(emac); + return RT_EOK; +} + +static const struct rt_ofw_node_id k1x_emac_ofw_ids[] = +{ + { .compatible = "spacemit,k1x-emac" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver k1x_emac_driver = +{ + .name = "k1x-emac", + .ids = k1x_emac_ofw_ids, + .probe = k1x_emac_probe, + .remove = k1x_emac_remove, +}; +RT_PLATFORM_DRIVER_EXPORT(k1x_emac_driver); diff --git a/bsp/spacemit/dm/firmware/SConscript b/bsp/spacemit/dm/firmware/SConscript new file mode 100644 index 000000000000..4cf3fd818f62 --- /dev/null +++ b/bsp/spacemit/dm/firmware/SConscript @@ -0,0 +1,12 @@ +from building import * + +group = [] +src = [] +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../include'] + +src += ['firmware-spacemit.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/spacemit/dm/firmware/firmware-spacemit.c b/bsp/spacemit/dm/firmware/firmware-spacemit.c new file mode 100644 index 000000000000..14907a421f21 --- /dev/null +++ b/bsp/spacemit/dm/firmware/firmware-spacemit.c @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#include +#include + +#include +#include + +rt_weak rt_ubase_t spacemit_firmwares_start, spacemit_firmwares_end; + +rt_bool_t spacemit_firmware_find(const char *name, rt_ubase_t *out_base, rt_size_t *out_size) +{ + rt_ubase_t *start = &spacemit_firmwares_start, *end = &spacemit_firmwares_end; + + while (start < end) + { + if (!rt_strcmp((const char *)(*start), name)) + { + ++start; + + *out_base = *start++; + *out_size = *start++; + *out_size -= *out_base; + + return RT_TRUE; + } + + start += 3; + } + + return RT_FALSE; +} + +rt_err_t spacemit_firmware_load_elf(const char *name, rt_ubase_t phy_addr) +{ + void *vma; + rt_ubase_t base, size, load_base, seg_phys, seg_src, memsz, filesz, copy, chunk; + Elf32_Ehdr *ehdr; + Elf32_Phdr *phdr; + const rt_ubase_t MAX_IOMAP_SIZE = 128 * SIZE_MB; + + if (!spacemit_firmware_find(name, &base, &size)) + { + return -RT_EEMPTY; + } + + ehdr = (Elf32_Ehdr *)base; + + if (rt_memcmp(ehdr->e_ident, ELFMAG, SELFMAG) != 0) + { + return -RT_EINVAL; + } + + if (ehdr->e_ident[EI_CLASS] != ELFCLASS32) + { + return -RT_EINVAL; + } + + if (ehdr->e_phoff == 0 || ehdr->e_phnum == 0) + { + return -RT_EINVAL; + } + + phdr = (Elf32_Phdr *)(base + ehdr->e_phoff); + load_base = phy_addr - ehdr->e_entry; + + for (int i = 0; i < ehdr->e_phnum; ++i) + { + Elf32_Phdr *p = &phdr[i]; + + if (p->p_type != PT_LOAD) + { + continue; + } + + /* Sparse remoteproc metadata (for example .resource_table) has its + * own device address and reserved-memory mapping. Relocating it with + * the executable image would write to an unrelated DDR address. */ + if (p->p_paddr > ehdr->e_entry + MAX_IOMAP_SIZE) + { + continue; + } + + if (p->p_offset + p->p_filesz > size) + { + return -RT_EINVAL; + } + + seg_phys = load_base + p->p_paddr; + seg_src = base + p->p_offset; + memsz = p->p_memsz; + filesz = p->p_filesz; + + while (memsz > 0) + { + chunk = rt_min_t(rt_ubase_t, memsz, MAX_IOMAP_SIZE); + + if (!(vma = rt_ioremap_nocache((void *)seg_phys, chunk))) + { + return -RT_ENOMEM; + } + + copy = filesz > chunk ? chunk : filesz; + + if (copy > 0) + { + rt_memcpy((void *)vma, (const void *)seg_src, copy); + seg_src += copy; + filesz -= copy; + } + + if (chunk > copy) + { + rt_memset((void *)((rt_ubase_t)vma + copy), 0, chunk - copy); + } + + rt_iounmap(vma); + + seg_phys += chunk; + memsz -= chunk; + } + } + + return RT_EOK; +} diff --git a/bsp/spacemit/dm/graphic/SConscript b/bsp/spacemit/dm/graphic/SConscript new file mode 100644 index 000000000000..3d15055d62d2 --- /dev/null +++ b/bsp/spacemit/dm/graphic/SConscript @@ -0,0 +1,13 @@ +import os +from building import * + +cwd = GetCurrentDir() +objs = [] +list = os.listdir(cwd) + +for d in list: + path = os.path.join(cwd, d) + if os.path.isfile(os.path.join(path, 'SConscript')): + objs = objs + SConscript(os.path.join(d, 'SConscript')) + +Return('objs') diff --git a/bsp/spacemit/dm/graphic/framebuffer/Kconfig b/bsp/spacemit/dm/graphic/framebuffer/Kconfig new file mode 100644 index 000000000000..4d8f8625b204 --- /dev/null +++ b/bsp/spacemit/dm/graphic/framebuffer/Kconfig @@ -0,0 +1,14 @@ +config RT_GRAPHIC_FB_SPACEMIT + bool "Spacemit K1 Saturn framebuffer" + depends on RT_USING_GRAPHIC + depends on RT_USING_OFW + depends on RT_USING_CLK + depends on RT_USING_RESET + default n + help + RT-Thread framebuffer and HDMI output drivers for the Spacemit K1 + Saturn DPU. The display clock, reset, HDMI PHY and DPU scanout are + initialized by RT-Thread without relying on a bootloader handoff. + + Supported primary-plane formats are ARGB8888, ABGR8888, RGB565 and + BGR565. HDMI currently uses the board's known-good 1920x1080p60 mode. diff --git a/bsp/spacemit/dm/graphic/framebuffer/SConscript b/bsp/spacemit/dm/graphic/framebuffer/SConscript new file mode 100644 index 000000000000..194b42d24172 --- /dev/null +++ b/bsp/spacemit/dm/graphic/framebuffer/SConscript @@ -0,0 +1,11 @@ +from building import * + +cwd = GetCurrentDir() +src = [] + +if GetDepend(['RT_GRAPHIC_FB_SPACEMIT']): + src += ['display-spacemit.c', 'hdmi-spacemit.c', 'fb-spacemit.c'] + +group = DefineGroup('DeviceDrivers', src, depend=[''], CPPPATH=[cwd]) if src else [] + +Return('group') diff --git a/bsp/spacemit/dm/graphic/framebuffer/display-spacemit.c b/bsp/spacemit/dm/graphic/framebuffer/display-spacemit.c new file mode 100644 index 000000000000..52b9ac9567ef --- /dev/null +++ b/bsp/spacemit/dm/graphic/framebuffer/display-spacemit.c @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#include "display-spacemit.h" + +static rt_list_t spacemit_connectors = RT_LIST_OBJECT_INIT(spacemit_connectors); + +rt_err_t spacemit_display_connector_register( + struct spacemit_display_connector *connector, + struct rt_ofw_node *np, + const struct spacemit_display_connector_ops *ops, + void *priv) +{ + struct spacemit_display_connector *entry; + + if (!connector || !np || !ops || !ops->get_timing || !ops->enable) + { + return -RT_EINVAL; + } + + rt_list_for_each_entry(entry, &spacemit_connectors, list) + { + if (entry->ofw_node == np) + { + return -RT_EBUSY; + } + } + + rt_list_init(&connector->list); + connector->ofw_node = rt_ofw_node_get(np); + connector->ops = ops; + connector->priv = priv; + rt_list_insert_before(&spacemit_connectors, &connector->list); + + return RT_EOK; +} + +void spacemit_display_connector_unregister( + struct spacemit_display_connector *connector) +{ + if (!connector || !connector->ofw_node) + { + return; + } + + rt_list_remove(&connector->list); + rt_ofw_node_put(connector->ofw_node); + connector->ofw_node = RT_NULL; + connector->ops = RT_NULL; + connector->priv = RT_NULL; +} + +struct spacemit_display_connector *spacemit_display_connector_find( + const char *compatible) +{ + struct spacemit_display_connector *connector; + + if (!compatible) + { + return RT_NULL; + } + + rt_list_for_each_entry(connector, &spacemit_connectors, list) + { + if (rt_ofw_node_is_compatible(connector->ofw_node, compatible)) + { + return connector; + } + } + + return RT_NULL; +} + +static int spacemit_display_drivers_init(void) +{ + rt_err_t err; + + err = spacemit_hdmi_driver_register(); + if (err) + { + return err; + } + + return spacemit_fb_driver_register(); +} +INIT_DEVICE_EXPORT(spacemit_display_drivers_init); diff --git a/bsp/spacemit/dm/graphic/framebuffer/display-spacemit.h b/bsp/spacemit/dm/graphic/framebuffer/display-spacemit.h new file mode 100644 index 000000000000..f9eed6c5bb11 --- /dev/null +++ b/bsp/spacemit/dm/graphic/framebuffer/display-spacemit.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#ifndef __DISPLAY_SPACEMIT_H__ +#define __DISPLAY_SPACEMIT_H__ + +#include +#include + +#define SPACEMIT_DISPLAY_F_PHSYNC (1U << 0) +#define SPACEMIT_DISPLAY_F_PVSYNC (1U << 1) + +struct spacemit_display_timing +{ + rt_uint32_t hactive; + rt_uint32_t vactive; + rt_uint32_t hfront_porch; + rt_uint32_t hback_porch; + rt_uint32_t hsync_len; + rt_uint32_t vfront_porch; + rt_uint32_t vback_porch; + rt_uint32_t vsync_len; + rt_uint32_t refresh; + rt_uint64_t pixelclock; + rt_uint32_t flags; +}; + +struct spacemit_display_connector; + +struct spacemit_display_connector_ops +{ + rt_err_t (*detect)(struct spacemit_display_connector *connector, + rt_bool_t *connected); + rt_err_t (*get_timing)(struct spacemit_display_connector *connector, + struct spacemit_display_timing *timing); + rt_err_t (*enable)(struct spacemit_display_connector *connector, + const struct spacemit_display_timing *timing); + rt_err_t (*disable)(struct spacemit_display_connector *connector); +}; + +struct spacemit_display_connector +{ + rt_list_t list; + struct rt_ofw_node *ofw_node; + const struct spacemit_display_connector_ops *ops; + void *priv; +}; + +rt_err_t spacemit_display_connector_register( + struct spacemit_display_connector *connector, + struct rt_ofw_node *np, + const struct spacemit_display_connector_ops *ops, + void *priv); +void spacemit_display_connector_unregister( + struct spacemit_display_connector *connector); +struct spacemit_display_connector *spacemit_display_connector_find( + const char *compatible); + +rt_err_t spacemit_hdmi_driver_register(void); +rt_err_t spacemit_fb_driver_register(void); + +#endif /* __DISPLAY_SPACEMIT_H__ */ diff --git a/bsp/spacemit/dm/graphic/framebuffer/fb-spacemit.c b/bsp/spacemit/dm/graphic/framebuffer/fb-spacemit.c new file mode 100644 index 000000000000..fa16b2fc1077 --- /dev/null +++ b/bsp/spacemit/dm/graphic/framebuffer/fb-spacemit.c @@ -0,0 +1,1135 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#include +#include +#include + +#include +#include +#include "display-spacemit.h" + +#define DBG_TAG "fb.spacemit" +#define DBG_LVL DBG_INFO +#include + +#define SPACEMIT_DPU_HDMI 0U +#define SPACEMIT_DPU_DSI 1U + +#define SPACEMIT_DPU_MAX_DIMENSION 8192U +#define SPACEMIT_DPU_HDMI_MCLK_RATE 491520000UL + +/* Saturn RDMA3, composer2 and online2 registers used by U-Boot/Linux. */ +#define SPACEMIT_DPU_CTL2_NORMAL 0x0560 +#define SPACEMIT_DPU_CTL2_CFG_READY 0x056c +#define SPACEMIT_DPU_CTL2_TIMING 0x0588 +#define SPACEMIT_DPU_CTL2_SW_START 0x058c + +#define SPACEMIT_DPU_INT_ONLINE2_MASK 0x0910 +#define SPACEMIT_DPU_INT_ONLINE2_STATUS 0x0938 +#define SPACEMIT_DPU_INT_ONLINE2_RAW 0x0960 +#define SPACEMIT_DPU_INT_VSYNC RT_BIT(0) + +#define SPACEMIT_DPU_RDMA3_LAYER_CTRL 0x0d80 +#define SPACEMIT_DPU_RDMA3_ADDR_LOW 0x0da0 +#define SPACEMIT_DPU_RDMA3_ADDR_HIGH 0x0da4 +#define SPACEMIT_DPU_RDMA3_STRIDE 0x0db8 +#define SPACEMIT_DPU_RDMA3_IMAGE_SIZE 0x0dbc +#define SPACEMIT_DPU_RDMA3_CROP_START 0x0dc0 +#define SPACEMIT_DPU_RDMA3_CROP_END 0x0dc4 +#define SPACEMIT_DPU_RDMA3_ROT_FORMAT 0x0df0 + +#define SPACEMIT_DPU_CMPS2_LAYER0 0x4c00 +#define SPACEMIT_DPU_CMPS2_HEIGHT 0x4c04 +#define SPACEMIT_DPU_CMPS2_SOLID_R 0x4c10 +#define SPACEMIT_DPU_CMPS2_SOLID_A 0x4c14 +#define SPACEMIT_DPU_CMPS2_BLEND 0x4c38 +#define SPACEMIT_DPU_CMPS2_POSITION 0x4c48 +#define SPACEMIT_DPU_CMPS2_RIGHT 0x4c4c +#define SPACEMIT_DPU_CMPS2_BOTTOM 0x4c50 +#define SPACEMIT_DPU_CMPS2_SOLID_COLOR 0x4c54 + +#define SPACEMIT_DPU_OUT2_SIZE 0x18000 +#define SPACEMIT_DPU_OUT2_CTRL4 0x18018 +#define SPACEMIT_DPU_OUT2_CTRL31 0x1807c +#define SPACEMIT_DPU_OUT2_HPORCH 0x18080 +#define SPACEMIT_DPU_OUT2_VPORCH 0x18084 +#define SPACEMIT_DPU_OUT2_SYNC 0x18088 +#define SPACEMIT_DPU_OUT2_ACTIVE_SIZE 0x1808c +#define SPACEMIT_DPU_OUT2_FORMAT 0x18090 + +#define SPACEMIT_DPU_TOP_MISC 0x0a1c + +#define SPACEMIT_DPU_RDMA3_CTRL_VALUE 0x00202040U +#define SPACEMIT_DPU_CTL2_NORMAL_VALUE 0x00040008U +#define SPACEMIT_DPU_CTL2_TIMING_VALUE 0x00000821U +#define SPACEMIT_DPU_OUT_FORMAT_RGB888 2U + +enum spacemit_dpu_rdma_format +{ + SPACEMIT_RDMA_FORMAT_ARGB8888 = 4, + SPACEMIT_RDMA_FORMAT_ABGR8888 = 5, + SPACEMIT_RDMA_FORMAT_RGB565 = 22, + SPACEMIT_RDMA_FORMAT_BGR565 = 23, +}; + +struct spacemit_fb_plane +{ + rt_ubase_t dma_handle; + rt_ubase_t dma_flags; + rt_size_t pan_offset; + rt_bool_t enabled; + rt_bool_t reserved; +}; + +struct spacemit_fb +{ + struct rt_graphic_device parent; + struct rt_device *dev; + + void *regs; + struct rt_clk_array *clks; + struct rt_reset_control *rstc; + struct spacemit_display_connector *connector; + struct spacemit_display_timing timing; + rt_bool_t clocks_enabled; + rt_bool_t connector_enabled; + rt_bool_t dpu_configured; + rt_bool_t powered; + rt_bool_t irq_attached; + rt_bool_t vsync_sem_initialized; + + rt_uint32_t output_type; + rt_uint32_t width; + rt_uint32_t height; + rt_uint32_t refresh; + rt_ubase_t reserved_fb_dma; + rt_size_t reserved_fb_size; + int irq; + struct rt_semaphore vsync_sem; + rt_atomic_t vsync_waiting; + struct rt_graphic_plane *primary; +}; + +static const rt_uint32_t spacemit_fb_modes[] = +{ + RTGRAPHIC_PIXEL_FORMAT_ARGB888, + RTGRAPHIC_PIXEL_FORMAT_ABGR888, + RTGRAPHIC_PIXEL_FORMAT_RGB565, + RTGRAPHIC_PIXEL_FORMAT_BGR565, +}; + +rt_inline rt_uint32_t spacemit_fb_readl(struct spacemit_fb *sfb, + rt_uint32_t offset) +{ + return HWREG32((rt_uint8_t *)sfb->regs + offset); +} + +rt_inline void spacemit_fb_writel(struct spacemit_fb *sfb, + rt_uint32_t offset, rt_uint32_t value) +{ + HWREG32((rt_uint8_t *)sfb->regs + offset) = value; +} + +static void spacemit_fb_isr(int irqno, void *param) +{ + struct spacemit_fb *sfb = param; + rt_uint32_t status = spacemit_fb_readl(sfb, + SPACEMIT_DPU_INT_ONLINE2_RAW); + + RT_UNUSED(irqno); + + if (status & SPACEMIT_DPU_INT_VSYNC) + { + spacemit_fb_writel(sfb, SPACEMIT_DPU_INT_ONLINE2_STATUS, + SPACEMIT_DPU_INT_VSYNC); + + if (rt_atomic_load(&sfb->vsync_waiting)) + { + rt_sem_release(&sfb->vsync_sem); + } + } +} + +static void spacemit_fb_vsync_irq_enable(struct spacemit_fb *sfb, + rt_bool_t enable) +{ + rt_uint32_t mask; + + if (!sfb->irq_attached) + { + return; + } + + mask = spacemit_fb_readl(sfb, SPACEMIT_DPU_INT_ONLINE2_MASK); + if (enable) + { + spacemit_fb_writel(sfb, SPACEMIT_DPU_INT_ONLINE2_STATUS, + SPACEMIT_DPU_INT_VSYNC); + mask |= SPACEMIT_DPU_INT_VSYNC; + } + else + { + mask &= ~SPACEMIT_DPU_INT_VSYNC; + } + spacemit_fb_writel(sfb, SPACEMIT_DPU_INT_ONLINE2_MASK, mask); +} + +static rt_err_t spacemit_fb_irq_setup(struct spacemit_fb *sfb) +{ + rt_err_t err; + + sfb->irq = rt_dm_dev_get_irq_by_name(sfb->dev, "ONLINE_IRQ"); + if (sfb->irq < 0) + { + sfb->irq = rt_dm_dev_get_irq(sfb->dev, 0); + } + if (sfb->irq < 0) + { + return sfb->irq; + } + + if ((err = rt_sem_init(&sfb->vsync_sem, "dpu-vsync", 0, + RT_IPC_FLAG_FIFO))) + { + return err; + } + sfb->vsync_sem_initialized = RT_TRUE; + rt_atomic_store(&sfb->vsync_waiting, RT_FALSE); + + rt_hw_interrupt_install(sfb->irq, spacemit_fb_isr, sfb, "dpu-online2"); + sfb->irq_attached = RT_TRUE; + + spacemit_fb_vsync_irq_enable(sfb, RT_TRUE); + rt_hw_interrupt_umask(sfb->irq); + + return RT_EOK; +} + +static void spacemit_fb_irq_cleanup(struct spacemit_fb *sfb) +{ + if (sfb->irq_attached) + { + spacemit_fb_vsync_irq_enable(sfb, RT_FALSE); + spacemit_fb_writel(sfb, SPACEMIT_DPU_INT_ONLINE2_STATUS, + SPACEMIT_DPU_INT_VSYNC); + rt_hw_interrupt_mask(sfb->irq); + rt_pic_detach_irq(sfb->irq, sfb); + sfb->irq_attached = RT_FALSE; + } + if (sfb->vsync_sem_initialized) + { + rt_sem_detach(&sfb->vsync_sem); + sfb->vsync_sem_initialized = RT_FALSE; + } +} + +static struct spacemit_fb *spacemit_fb_from_plane(struct rt_graphic_plane *plane) +{ + return rt_container_of(plane->graphic, struct spacemit_fb, parent); +} + +static struct spacemit_fb_plane *spacemit_fb_plane_priv( + struct rt_graphic_plane *plane) +{ + return (struct spacemit_fb_plane *)plane->priv; +} + +static rt_uint32_t spacemit_fb_mode_to_hw(rt_uint32_t mode) +{ + switch (mode) + { + case RTGRAPHIC_PIXEL_FORMAT_ARGB888: + return SPACEMIT_RDMA_FORMAT_ARGB8888; + case RTGRAPHIC_PIXEL_FORMAT_ABGR888: + return SPACEMIT_RDMA_FORMAT_ABGR8888; + case RTGRAPHIC_PIXEL_FORMAT_RGB565: + return SPACEMIT_RDMA_FORMAT_RGB565; + case RTGRAPHIC_PIXEL_FORMAT_BGR565: + return SPACEMIT_RDMA_FORMAT_BGR565; + default: + return RT_UINT32_MAX; + } +} + +static struct rt_ofw_node *spacemit_fb_find_display_node( + struct rt_ofw_node *port_np, rt_uint32_t output_type) +{ + const char *compatible; + struct rt_ofw_node *display_np; + + compatible = output_type == SPACEMIT_DPU_HDMI ? + "spacemit,saturn-hdmi" : "spacemit,saturn-le"; + + rt_ofw_foreach_node_by_compatible(display_np, compatible) + { + struct rt_ofw_node *ports_np = + rt_ofw_parse_phandle(display_np, "ports", 0); + rt_bool_t matched = ports_np == port_np; + + if (ports_np) + { + rt_ofw_node_put(ports_np); + } + if (matched) + { + return display_np; + } + } + + return RT_NULL; +} + +static void spacemit_fb_find_reserved_buffer(struct spacemit_fb *sfb) +{ + rt_uint64_t addr, size; + struct rt_ofw_node *rmem_np, *fb_np; + + rmem_np = rt_ofw_find_node_by_path("/reserved-memory"); + if (!rmem_np) + { + return; + } + + rt_ofw_foreach_child_node(rmem_np, fb_np) + { + if (!rt_ofw_node_tag_equ(fb_np, "framebuffer") || + rt_ofw_get_address(fb_np, 0, &addr, &size) || !size || + addr > (rt_uint64_t)(rt_ubase_t)-1 || + size > (rt_uint64_t)(rt_size_t)-1) + { + continue; + } + + sfb->reserved_fb_dma = (rt_ubase_t)addr; + sfb->reserved_fb_size = (rt_size_t)size; + rt_ofw_node_put(fb_np); + break; + } + + rt_ofw_node_put(rmem_np); +} + +static rt_err_t spacemit_fb_clocks_enable(struct spacemit_fb *sfb) +{ + rt_err_t err; + + if (sfb->clocks_enabled) + { + return RT_EOK; + } + if ((err = rt_clk_array_prepare_enable(sfb->clks))) + { + return err; + } + + if (sfb->output_type == SPACEMIT_DPU_HDMI && sfb->clks->count) + { + struct rt_clk *clk = sfb->clks->clks[0]; + + if (!rt_is_err_or_null(clk) && + (err = rt_clk_set_rate(clk, SPACEMIT_DPU_HDMI_MCLK_RATE))) + { + rt_clk_array_disable_unprepare(sfb->clks); + return err; + } + } + + sfb->clocks_enabled = RT_TRUE; + return RT_EOK; +} + +static void spacemit_fb_clocks_disable(struct spacemit_fb *sfb) +{ + if (sfb->clocks_enabled) + { + rt_clk_array_disable_unprepare(sfb->clks); + sfb->clocks_enabled = RT_FALSE; + } +} + +static void spacemit_fb_trigger(struct spacemit_fb *sfb) +{ + spacemit_fb_writel(sfb, SPACEMIT_DPU_CTL2_CFG_READY, 1); + if (!sfb->dpu_configured) + { + spacemit_fb_writel(sfb, SPACEMIT_DPU_CTL2_SW_START, 1); + } + rt_hw_dsb(); +} + +static void spacemit_fb_output_mode_set(struct spacemit_fb *sfb) +{ + const struct spacemit_display_timing *timing = &sfb->timing; + rt_uint32_t hsp = !!(timing->flags & SPACEMIT_DISPLAY_F_PHSYNC); + rt_uint32_t vsp = !!(timing->flags & SPACEMIT_DISPLAY_F_PVSYNC); + rt_uint32_t size = (timing->vactive << 16) | timing->hactive; + + spacemit_fb_writel(sfb, SPACEMIT_DPU_TOP_MISC, 0x2223); + spacemit_fb_writel(sfb, SPACEMIT_DPU_OUT2_SIZE, size); + spacemit_fb_writel(sfb, SPACEMIT_DPU_OUT2_CTRL4, 0x20); + spacemit_fb_writel(sfb, SPACEMIT_DPU_OUT2_CTRL31, 0x100); + spacemit_fb_writel(sfb, SPACEMIT_DPU_OUT2_HPORCH, + (timing->hback_porch << 16) | timing->hfront_porch); + spacemit_fb_writel(sfb, SPACEMIT_DPU_OUT2_VPORCH, + (timing->vback_porch << 16) | timing->vfront_porch); + spacemit_fb_writel(sfb, SPACEMIT_DPU_OUT2_SYNC, + (vsp << 28) | (timing->vsync_len << 16) | + (hsp << 12) | timing->hsync_len); + spacemit_fb_writel(sfb, SPACEMIT_DPU_OUT2_ACTIVE_SIZE, size); + spacemit_fb_writel(sfb, SPACEMIT_DPU_OUT2_FORMAT, + SPACEMIT_DPU_OUT_FORMAT_RGB888); +} + +static void spacemit_fb_composer_enable(struct spacemit_fb *sfb, + rt_uint32_t width, rt_uint32_t height, rt_bool_t enable) +{ + if (!enable) + { + rt_uint32_t value = spacemit_fb_readl(sfb, + SPACEMIT_DPU_CMPS2_LAYER0); + + spacemit_fb_writel(sfb, SPACEMIT_DPU_CMPS2_LAYER0, + value & ~RT_BIT(0)); + spacemit_fb_trigger(sfb); + return; + } + + spacemit_fb_writel(sfb, SPACEMIT_DPU_CMPS2_LAYER0, + (width << 8) | 1U); + spacemit_fb_writel(sfb, SPACEMIT_DPU_CMPS2_HEIGHT, height); + spacemit_fb_writel(sfb, SPACEMIT_DPU_CMPS2_SOLID_R, 0xff0000); + spacemit_fb_writel(sfb, SPACEMIT_DPU_CMPS2_SOLID_A, 0xff); + spacemit_fb_writel(sfb, SPACEMIT_DPU_CMPS2_BLEND, 0x7); + spacemit_fb_writel(sfb, SPACEMIT_DPU_CMPS2_POSITION, 0); + spacemit_fb_writel(sfb, SPACEMIT_DPU_CMPS2_RIGHT, + (width - 1U) << 16); + spacemit_fb_writel(sfb, SPACEMIT_DPU_CMPS2_BOTTOM, height - 1U); + spacemit_fb_writel(sfb, SPACEMIT_DPU_CMPS2_SOLID_COLOR, 0xff0000); +} + +static rt_err_t spacemit_fb_plane_commit(struct rt_graphic_plane *plane, + rt_bool_t enable) +{ + struct spacemit_fb *sfb = spacemit_fb_from_plane(plane); + struct spacemit_fb_plane *priv = spacemit_fb_plane_priv(plane); + rt_uint32_t hw_format; + rt_ubase_t dma; + + if (!priv) + { + return -RT_EINVAL; + } + if (!enable || !plane->framebuffer) + { + if (sfb->powered) + { + spacemit_fb_composer_enable(sfb, plane->width, plane->height, + RT_FALSE); + } + priv->enabled = RT_FALSE; + return RT_EOK; + } + if (!sfb->powered) + { + priv->enabled = RT_TRUE; + return RT_EOK; + } + + hw_format = spacemit_fb_mode_to_hw(plane->mode); + if (hw_format == RT_UINT32_MAX || !plane->width || !plane->height || + plane->line_length > 0xffffU) + { + return -RT_EINVAL; + } + + if (!sfb->dpu_configured) + { + LOG_D("initial framebuffer cache flush begin: %u bytes", + (unsigned)plane->screen_len); + } + rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, + (rt_uint8_t *)plane->framebuffer + priv->pan_offset, + plane->screen_len); + if (!sfb->dpu_configured) + { + LOG_D("initial framebuffer cache flush done"); + } + dma = priv->dma_handle + priv->pan_offset; + + if (!sfb->dpu_configured) + { + LOG_D("DPU init: fb=%p stride=%u format=%u", + dma, plane->line_length, hw_format); + } + + spacemit_fb_output_mode_set(sfb); + spacemit_fb_writel(sfb, SPACEMIT_DPU_RDMA3_LAYER_CTRL, + SPACEMIT_DPU_RDMA3_CTRL_VALUE); + spacemit_fb_writel(sfb, SPACEMIT_DPU_RDMA3_ADDR_LOW, + (rt_uint32_t)dma); + spacemit_fb_writel(sfb, SPACEMIT_DPU_RDMA3_ADDR_HIGH, + (rt_uint32_t)(dma >> 32)); + spacemit_fb_writel(sfb, SPACEMIT_DPU_RDMA3_STRIDE, + plane->line_length); + spacemit_fb_writel(sfb, SPACEMIT_DPU_RDMA3_IMAGE_SIZE, + (plane->height << 16) | plane->width); + spacemit_fb_writel(sfb, SPACEMIT_DPU_RDMA3_CROP_START, 0); + spacemit_fb_writel(sfb, SPACEMIT_DPU_RDMA3_CROP_END, + ((plane->height - 1U) << 16) | (plane->width - 1U)); + spacemit_fb_writel(sfb, SPACEMIT_DPU_RDMA3_ROT_FORMAT, hw_format); + + spacemit_fb_composer_enable(sfb, plane->width, plane->height, RT_TRUE); + spacemit_fb_writel(sfb, SPACEMIT_DPU_CTL2_NORMAL, + SPACEMIT_DPU_CTL2_NORMAL_VALUE); + spacemit_fb_writel(sfb, SPACEMIT_DPU_CTL2_TIMING, + SPACEMIT_DPU_CTL2_TIMING_VALUE); + spacemit_fb_trigger(sfb); + + priv->enabled = RT_TRUE; + if (!sfb->dpu_configured) + { + sfb->dpu_configured = RT_TRUE; + } + return RT_EOK; +} + +static void spacemit_fb_plane_free(struct rt_graphic_plane *plane) +{ + struct spacemit_fb *sfb = spacemit_fb_from_plane(plane); + struct spacemit_fb_plane *priv = spacemit_fb_plane_priv(plane); + + if (plane->framebuffer) + { + if (priv->reserved) + { + rt_iounmap(plane->framebuffer); + } + else + { + rt_dma_free(&sfb->parent.parent, plane->framebuffer_len, + plane->framebuffer, priv->dma_handle, priv->dma_flags); + } + plane->framebuffer = RT_NULL; + plane->framebuffer_len = 0; + plane->screen_len = 0; + priv->dma_handle = 0; + priv->dma_flags = 0; + priv->pan_offset = 0; + priv->reserved = RT_FALSE; + } +} + +static rt_err_t spacemit_fb_plane_flush(struct rt_graphic_plane *plane, + struct rt_device_rect_info *rect) +{ + struct spacemit_fb_plane *priv = spacemit_fb_plane_priv(plane); + rt_uint8_t *addr; + rt_size_t row, row_len, bytes_per_pixel; + + if (!plane->framebuffer || !plane->bits_per_pixel) + { + return -RT_EINVAL; + } + + if (!rect || !rect->width || !rect->height) + { + rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, + (rt_uint8_t *)plane->framebuffer + priv->pan_offset, + plane->screen_len); + return RT_EOK; + } + + if (rect->x >= plane->width || rect->y >= plane->height || + rect->width > plane->width - rect->x || + rect->height > plane->height - rect->y) + { + return -RT_EINVAL; + } + + bytes_per_pixel = plane->bits_per_pixel / 8U; + row_len = rect->width * bytes_per_pixel; + addr = (rt_uint8_t *)plane->framebuffer + priv->pan_offset + + rect->y * plane->line_length + rect->x * bytes_per_pixel; + + if (!rect->x && rect->width == plane->width) + { + rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, addr, + rect->height * plane->line_length); + return RT_EOK; + } + + for (row = 0; row < rect->height; ++row) + { + rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, addr, row_len); + addr += plane->line_length; + } + + return RT_EOK; +} + +static rt_err_t spacemit_fb_plane_update(struct rt_graphic_plane *plane, + struct rt_device_rect_info *rect) +{ + struct spacemit_fb_plane *priv = spacemit_fb_plane_priv(plane); + + if (priv->enabled) + { + return spacemit_fb_plane_flush(plane, rect); + } + + return spacemit_fb_plane_commit(plane, RT_TRUE); +} + +static rt_err_t spacemit_fb_plane_remap(struct rt_graphic_plane *plane, + rt_uint32_t mode, struct rt_device_rect_info *rect) +{ + struct spacemit_fb *sfb = spacemit_fb_from_plane(plane); + struct spacemit_fb_plane *priv = spacemit_fb_plane_priv(plane); + rt_uint32_t bpp = rt_graphic_mode_bpp(mode); + rt_size_t screen_len, fb_len; + void *framebuffer; + + if (!rect || !rect->width || !rect->height || + spacemit_fb_mode_to_hw(mode) == RT_UINT32_MAX || + (bpp != 16U && bpp != 32U)) + { + return -RT_EINVAL; + } + + if (plane->framebuffer) + { + spacemit_fb_plane_commit(plane, RT_FALSE); + } + spacemit_fb_plane_free(plane); + + plane->line_length = RT_ALIGN(rect->width * (bpp / 8U), 16U); + if (plane->line_length > 0xffffU || + rect->height > (rt_size_t)-1 / plane->line_length) + { + return -RT_EINVAL; + } + + screen_len = plane->line_length * rect->height; + if (screen_len > (rt_size_t)-1 / 2U) + { + return -RT_EINVAL; + } + fb_len = screen_len * 2U; + priv->dma_flags = RT_DMA_F_LINEAR | RT_DMA_F_32BITS; + + framebuffer = RT_NULL; + if (sfb->reserved_fb_size >= fb_len) + { + framebuffer = rt_ioremap_cached((void *)sfb->reserved_fb_dma, fb_len); + if (framebuffer) + { + priv->dma_handle = sfb->reserved_fb_dma; + priv->reserved = RT_TRUE; + LOG_D("use reserved framebuffer: va=%p dma=%p len=%u", + framebuffer, priv->dma_handle, (unsigned)fb_len); + } + else + { + LOG_D("map reserved framebuffer failed, fallback to CMA"); + } + } + + if (!framebuffer) + { + priv->dma_handle = 0; + framebuffer = rt_dma_alloc(&plane->graphic->parent, fb_len, + &priv->dma_handle, priv->dma_flags); + } + + if (!framebuffer) + { + LOG_W("double buffer allocation failed, fallback to one buffer"); + fb_len = screen_len; + + if (sfb->reserved_fb_size >= fb_len) + { + framebuffer = rt_ioremap_cached((void *)sfb->reserved_fb_dma, + fb_len); + if (framebuffer) + { + priv->dma_handle = sfb->reserved_fb_dma; + priv->reserved = RT_TRUE; + } + } + if (!framebuffer) + { + priv->dma_handle = 0; + framebuffer = rt_dma_alloc(&plane->graphic->parent, fb_len, + &priv->dma_handle, priv->dma_flags); + } + } + if (!framebuffer) + { + priv->dma_flags = 0; + return -RT_ENOMEM; + } + + rt_memset(framebuffer, 0, fb_len); + + plane->framebuffer = framebuffer; + plane->framebuffer_len = fb_len; + plane->screen_len = screen_len; + plane->bits_per_pixel = bpp; + plane->mode = mode; + plane->width = rect->width; + plane->height = rect->height; + plane->x = 0; + plane->y = 0; + priv->pan_offset = 0; + + return spacemit_fb_plane_commit(plane, RT_TRUE); +} + +static rt_err_t spacemit_fb_plane_pan_display(struct rt_graphic_plane *plane, + struct rt_device_rect_info *rect) +{ + struct spacemit_fb_plane *priv = spacemit_fb_plane_priv(plane); + rt_size_t offset; + + if (!rect) + { + return -RT_EINVAL; + } + if (rect->width != plane->width || rect->height != plane->height) + { + return spacemit_fb_plane_remap(plane, plane->mode, rect); + } + + offset = rect->y * plane->line_length + + rect->x * (plane->bits_per_pixel / 8U); + if (offset + plane->screen_len > plane->framebuffer_len) + { + return -RT_EINVAL; + } + + if (offset == priv->pan_offset && priv->enabled) + { + return RT_EOK; + } + + priv->pan_offset = offset; + plane->x = rect->x; + plane->y = rect->y; + + return spacemit_fb_plane_commit(plane, RT_TRUE); +} + +static rt_err_t spacemit_fb_plane_cleanup(struct rt_graphic_plane *plane) +{ + struct spacemit_fb_plane *priv = spacemit_fb_plane_priv(plane); + + if (priv->enabled) + { + spacemit_fb_plane_commit(plane, RT_FALSE); + } + spacemit_fb_plane_free(plane); + + return RT_EOK; +} + +static const struct rt_graphic_plane_ops spacemit_fb_plane_ops = +{ + .update = spacemit_fb_plane_update, + .fb_remap = spacemit_fb_plane_remap, + .fb_pan_display = spacemit_fb_plane_pan_display, + .fb_cleanup = spacemit_fb_plane_cleanup, +}; + +static rt_err_t spacemit_fb_dpms_switch(struct rt_graphic_device *gdev, + rt_uint32_t dpms) +{ + rt_err_t err; + struct spacemit_fb *sfb = rt_container_of(gdev, struct spacemit_fb, parent); + + switch (dpms) + { + case RT_GRAPHIC_DPMS_ON: + if ((err = spacemit_fb_clocks_enable(sfb))) + { + return err; + } + + if ((err = rt_reset_control_deassert(sfb->rstc))) + { + spacemit_fb_clocks_disable(sfb); + return err; + } + rt_hw_us_delay(10); + spacemit_fb_vsync_irq_enable(sfb, RT_TRUE); + + if (!sfb->connector_enabled) + { + err = sfb->connector->ops->enable(sfb->connector, &sfb->timing); + if (err) + { + rt_reset_control_assert(sfb->rstc); + spacemit_fb_clocks_disable(sfb); + return err; + } + sfb->connector_enabled = RT_TRUE; + } + + sfb->powered = RT_TRUE; + if (sfb->primary && sfb->primary->framebuffer && + !spacemit_fb_plane_priv(sfb->primary)->enabled) + { + sfb->dpu_configured = RT_FALSE; + if ((err = spacemit_fb_plane_commit(sfb->primary, RT_TRUE))) + { + return err; + } + } + break; + + case RT_GRAPHIC_DPMS_STANDBY: + case RT_GRAPHIC_DPMS_SUSPEND: + if (sfb->primary) + { + spacemit_fb_plane_commit(sfb->primary, RT_FALSE); + } + break; + + case RT_GRAPHIC_DPMS_OFF: + if (sfb->primary) + { + spacemit_fb_plane_commit(sfb->primary, RT_FALSE); + } + + if (sfb->connector_enabled && sfb->connector->ops->disable) + { + sfb->connector->ops->disable(sfb->connector); + sfb->connector_enabled = RT_FALSE; + } + + spacemit_fb_vsync_irq_enable(sfb, RT_FALSE); + rt_reset_control_assert(sfb->rstc); + sfb->powered = RT_FALSE; + sfb->dpu_configured = RT_FALSE; + spacemit_fb_clocks_disable(sfb); + break; + + default: + return -RT_EINVAL; + } + + gdev->dpms = dpms; + return RT_EOK; +} + +static rt_err_t spacemit_fb_wait_vsync(struct rt_graphic_device *gdev) +{ + struct spacemit_fb *sfb = rt_container_of(gdev, struct spacemit_fb, parent); + rt_uint32_t timeout_ms; + rt_err_t err; + + if (!sfb->powered || !sfb->irq_attached) + { + return -RT_EIO; + } + + while (rt_sem_take(&sfb->vsync_sem, 0) == RT_EOK) + { + } + + rt_atomic_store(&sfb->vsync_waiting, RT_TRUE); + timeout_ms = rt_max(50U, (3000U + sfb->refresh - 1U) / sfb->refresh); + err = rt_sem_take(&sfb->vsync_sem, + rt_tick_from_millisecond(timeout_ms)); + rt_atomic_store(&sfb->vsync_waiting, RT_FALSE); + + if (err) + { + LOG_W("wait for VSYNC timed out: raw=0x%08x mask=0x%08x", + spacemit_fb_readl(sfb, SPACEMIT_DPU_INT_ONLINE2_RAW), + spacemit_fb_readl(sfb, SPACEMIT_DPU_INT_ONLINE2_MASK)); + } + + return err; +} + +static const struct rt_graphic_device_ops spacemit_fb_ops = +{ + .dpms_switch = spacemit_fb_dpms_switch, + .wait_vsync = spacemit_fb_wait_vsync, +}; + +static rt_err_t spacemit_fb_plane_create(struct spacemit_fb *sfb) +{ + rt_err_t err; + struct rt_graphic_plane *plane; + + plane = rt_graphic_device_alloc_plane(&sfb->parent, + sizeof(struct spacemit_fb_plane), &spacemit_fb_plane_ops, + spacemit_fb_modes, RT_ARRAY_SIZE(spacemit_fb_modes), + RT_GRAPHIC_PLANE_TYPE_PRIMARY); + if (!plane) + { + return -RT_ENOMEM; + } + if ((err = rt_graphic_device_add_plane(&sfb->parent, plane))) + { + rt_graphic_device_free_plane(plane); + return err; + } + + plane->mode = RTGRAPHIC_PIXEL_FORMAT_ARGB888; + plane->bits_per_pixel = 32; + /* Let graphic registration allocate the initial buffer from EDID size. */ + plane->width = 0; + plane->height = 0; + plane->alpha = 0xff; + sfb->primary = plane; + + return RT_EOK; +} + +static rt_err_t spacemit_fb_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + const char *connector_compatible; + struct rt_ofw_node *display_np; + struct rt_device *dev = &pdev->parent; + struct spacemit_fb *sfb = rt_calloc(1, sizeof(*sfb)); + + if (!sfb) + { + return -RT_ENOMEM; + } + + sfb->dev = dev; + if (rt_dm_dev_prop_read_u32(dev, "type", &sfb->output_type) || + sfb->output_type > SPACEMIT_DPU_DSI) + { + err = -RT_EINVAL; + goto _fail; + } + + display_np = spacemit_fb_find_display_node(dev->ofw_node, + sfb->output_type); + if (!display_np) + { + LOG_E("cannot find Saturn register node for %s", + rt_ofw_node_full_name(dev->ofw_node)); + err = -RT_ENOENT; + goto _fail; + } + + sfb->regs = rt_ofw_iomap(display_np, 0); + rt_ofw_node_put(display_np); + if (!sfb->regs) + { + err = -RT_EIO; + goto _fail; + } + + sfb->clks = rt_clk_get_array(dev); + if (rt_is_err(sfb->clks)) + { + err = rt_ptr_err(sfb->clks); + sfb->clks = RT_NULL; + goto _fail_unmap; + } + if ((err = spacemit_fb_clocks_enable(sfb))) + { + goto _fail_clks; + } + + sfb->rstc = rt_reset_control_get_by_name(dev, "hdmi_reset"); + if (rt_is_err(sfb->rstc)) + { + err = rt_ptr_err(sfb->rstc); + sfb->rstc = RT_NULL; + LOG_E("get DPU reset failed: %s", rt_strerror(err)); + goto _fail_power; + } + + if ((err = rt_reset_control_assert(sfb->rstc))) + { + LOG_E("assert DPU reset failed: %s", rt_strerror(err)); + goto _fail_reset; + } + rt_hw_us_delay(10); + if ((err = rt_reset_control_deassert(sfb->rstc))) + { + LOG_E("deassert DPU reset failed: %s", rt_strerror(err)); + goto _fail_reset; + } + rt_hw_us_delay(10); + + connector_compatible = sfb->output_type == SPACEMIT_DPU_HDMI ? + "spacemit,hdmi" : "spacemit,dsi2-host"; + sfb->connector = spacemit_display_connector_find(connector_compatible); + if (!sfb->connector) + { + LOG_E("no enabled %s connector found", connector_compatible); + err = -RT_ENOENT; + goto _fail_reset; + } + + if ((err = sfb->connector->ops->get_timing(sfb->connector, + &sfb->timing))) + { + LOG_E("get connector timing failed: %s", rt_strerror(err)); + goto _fail_reset; + } + + sfb->width = sfb->timing.hactive; + sfb->height = sfb->timing.vactive; + sfb->refresh = sfb->timing.refresh; + if (!sfb->width || !sfb->height || !sfb->refresh || + !sfb->timing.pixelclock || !sfb->timing.hsync_len || + !sfb->timing.vsync_len || + sfb->width > SPACEMIT_DPU_MAX_DIMENSION || + sfb->height > SPACEMIT_DPU_MAX_DIMENSION) + { + err = -RT_EINVAL; + goto _fail_reset; + } + + if ((err = sfb->connector->ops->enable(sfb->connector, &sfb->timing))) + { + LOG_E("connector cold init failed: %s", rt_strerror(err)); + goto _fail_reset; + } + sfb->connector_enabled = RT_TRUE; + sfb->powered = RT_TRUE; + + if ((err = spacemit_fb_irq_setup(sfb))) + { + LOG_E("setup DPU VSYNC interrupt failed: %s", rt_strerror(err)); + goto _fail_connector; + } + + spacemit_fb_find_reserved_buffer(sfb); + if (!sfb->reserved_fb_size) + { + LOG_W("no reserved framebuffer found, initial scanout uses CMA"); + } + + sfb->parent.ops = &spacemit_fb_ops; + if ((err = spacemit_fb_plane_create(sfb))) + { + goto _fail_connector; + } + + if ((err = rt_graphic_device_simple_edid(&sfb->parent, sfb->width, + sfb->height, sfb->refresh))) + { + rt_graphic_device_del_plane(&sfb->parent, sfb->primary); + rt_graphic_device_free_plane(sfb->primary); + sfb->primary = RT_NULL; + goto _fail_connector; + } + if ((err = rt_graphic_device_register(&sfb->parent))) + { + rt_graphic_device_del_plane(&sfb->parent, sfb->primary); + rt_graphic_device_free_plane(sfb->primary); + sfb->primary = RT_NULL; + goto _fail_connector; + } + + if ((err = spacemit_fb_dpms_switch(&sfb->parent, RT_GRAPHIC_DPMS_ON))) + { + rt_graphic_device_unregister(&sfb->parent); + sfb->primary = RT_NULL; + goto _fail_connector; + } + pdev->parent.user_data = sfb; + + LOG_D("%s framebuffer fb%u: %ux%u@%u", + sfb->output_type == SPACEMIT_DPU_HDMI ? "HDMI" : "DSI", + sfb->parent.parent.device_id, sfb->width, sfb->height, + sfb->refresh); + + return RT_EOK; + +_fail_connector: + spacemit_fb_irq_cleanup(sfb); + if (sfb->connector_enabled && sfb->connector->ops->disable) + { + sfb->connector->ops->disable(sfb->connector); + sfb->connector_enabled = RT_FALSE; + } + sfb->powered = RT_FALSE; +_fail_reset: + if (sfb->rstc) + { + rt_reset_control_assert(sfb->rstc); + rt_reset_control_put(sfb->rstc); + } +_fail_power: + spacemit_fb_clocks_disable(sfb); +_fail_clks: + if (sfb->clks) + { + rt_clk_array_put(sfb->clks); + } +_fail_unmap: + rt_iounmap(sfb->regs); +_fail: + rt_free(sfb); + return err; +} + +static rt_err_t spacemit_fb_remove(struct rt_platform_device *pdev) +{ + rt_err_t err; + struct spacemit_fb *sfb = pdev->parent.user_data; + + if (!sfb) + { + return RT_EOK; + } + + if ((err = rt_graphic_device_unregister(&sfb->parent))) + { + return err; + } + sfb->primary = RT_NULL; + spacemit_fb_irq_cleanup(sfb); + if (sfb->rstc) + { + rt_reset_control_put(sfb->rstc); + } + if (sfb->clks) + { + rt_clk_array_put(sfb->clks); + } + rt_iounmap(sfb->regs); + rt_free(sfb); + pdev->parent.user_data = RT_NULL; + + return RT_EOK; +} + +static const struct rt_ofw_node_id spacemit_fb_ids[] = +{ + { .compatible = "spacemit,dpu-online2" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver spacemit_fb_driver = +{ + .name = "spacemit-framebuffer", + .ids = spacemit_fb_ids, + .probe = spacemit_fb_probe, + .remove = spacemit_fb_remove, +}; + +rt_err_t spacemit_fb_driver_register(void) +{ + return rt_platform_driver_register(&spacemit_fb_driver); +} diff --git a/bsp/spacemit/dm/graphic/framebuffer/hdmi-spacemit.c b/bsp/spacemit/dm/graphic/framebuffer/hdmi-spacemit.c new file mode 100644 index 000000000000..4708e198b6a2 --- /dev/null +++ b/bsp/spacemit/dm/graphic/framebuffer/hdmi-spacemit.c @@ -0,0 +1,482 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#include +#include +#include + +#include "display-spacemit.h" + +#define DBG_TAG "hdmi.spacemit" +#define DBG_LVL DBG_INFO +#include + +#define SPACEMIT_HDMI_MCLK_RATE 491520000UL +#define SPACEMIT_HDMI_PHY_STATUS 0x000c +#define SPACEMIT_HDMI_PHY_HPD RT_BIT(12) +#define SPACEMIT_HDMI_PHY_CTRL 0x0028 +#define SPACEMIT_HDMI_COLOR_DEPTH 0x0034 +#define SPACEMIT_HDMI_PHY_ANALOG 0x00e0 +#define SPACEMIT_HDMI_PLL_CTRL 0x00e4 +#define SPACEMIT_HDMI_PLL_FRAC 0x00e8 +#define SPACEMIT_HDMI_PLL_DIV 0x00ec +#define SPACEMIT_HDMI_PLL_POST 0x00f0 + +#define SPACEMIT_HDMI_EIGHT_BPP 0U + +struct spacemit_hdmi +{ + struct rt_device *dev; + void *regs; + struct rt_clk *mclk; + struct rt_reset_control *rstc; + struct spacemit_display_connector connector; + rt_bool_t prepared; + rt_bool_t enabled; +}; + +static const struct spacemit_display_timing spacemit_hdmi_1080p60 = +{ + .hactive = 1920, + .vactive = 1080, + .hfront_porch = 88, + .hback_porch = 148, + .hsync_len = 44, + .vfront_porch = 4, + .vback_porch = 36, + .vsync_len = 5, + .refresh = 60, + .pixelclock = 148500000ULL, + .flags = SPACEMIT_DISPLAY_F_PHSYNC | SPACEMIT_DISPLAY_F_PVSYNC, +}; + +rt_inline rt_uint32_t spacemit_hdmi_readl(struct spacemit_hdmi *hdmi, + rt_uint32_t offset) +{ + return HWREG32((rt_uint8_t *)hdmi->regs + offset); +} + +rt_inline void spacemit_hdmi_writel(struct spacemit_hdmi *hdmi, + rt_uint32_t offset, rt_uint32_t value) +{ + HWREG32((rt_uint8_t *)hdmi->regs + offset) = value; +} + +static void spacemit_hdmi_update_bits(struct spacemit_hdmi *hdmi, + rt_uint32_t offset, rt_uint32_t mask, rt_uint32_t value) +{ + rt_uint32_t reg = spacemit_hdmi_readl(hdmi, offset); + + reg &= ~mask; + reg |= value & mask; + spacemit_hdmi_writel(hdmi, offset, reg); +} + +static int spacemit_hdmi_pll8(rt_uint32_t bit_clock_khz) +{ + bit_clock_khz /= 100U; + + if (bit_clock_khz < 425U) + { + return 3; + } + if (bit_clock_khz < 850U) + { + return 2; + } + if (bit_clock_khz < 1700U) + { + return 1; + } + + return 0; +} + +static int spacemit_hdmi_pll6(rt_uint32_t bit_clock_khz) +{ + bit_clock_khz /= 100U; + + if (bit_clock_khz <= 337U) + { + return 0; + } + if (bit_clock_khz < 425U) + { + return 1; + } + if (bit_clock_khz < 675U) + { + return 0; + } + if (bit_clock_khz < 850U) + { + return 1; + } + if (bit_clock_khz < 1350U) + { + return 0; + } + if (bit_clock_khz < 1700U) + { + return 1; + } + + return 0; +} + +static int spacemit_hdmi_pll5(rt_uint32_t bit_clock_khz) +{ + rt_uint32_t value = bit_clock_khz * + (1U << spacemit_hdmi_pll8(bit_clock_khz)) / 100U; + + if (value < 1830U) + { + return 0; + } + if (value < 2030U) + { + return 1; + } + if (value < 2275U) + { + return 2; + } + if (value < 2520U) + { + return 3; + } + if (value < 2765U) + { + return 4; + } + if (value < 3015U) + { + return 5; + } + if (value < 3260U) + { + return 6; + } + + return 7; +} + +static void spacemit_hdmi_pll_fraction(rt_uint32_t bit_clock_khz, + int *integer_part, rt_uint32_t *frac_reg) +{ + const rt_int64_t scale = 1000000000LL; + const int pll8 = spacemit_hdmi_pll8(bit_clock_khz); + const int pll6 = spacemit_hdmi_pll6(bit_clock_khz); + const rt_int64_t numerator = + (rt_int64_t)(1U << pll8) * bit_clock_khz; + const rt_int64_t denominator = 100LL * (pll6 + 1) * 24LL; + rt_int64_t value = numerator * scale / denominator; + rt_int64_t integer = numerator / denominator * scale; + rt_int64_t fraction = value - integer; + rt_int64_t bit = 0; + rt_uint32_t frac20 = 0; + rt_bool_t negative = fraction > scale / 2; + int frac_hi; + + fraction = negative ? scale - fraction : fraction; + *integer_part = (int)(integer / scale) + (negative ? 1 : 0); + + for (int i = 0; i < 20; ++i) + { + if (bit >= scale) + { + frac20 |= 1U << (19 - i); + fraction -= scale; + } + fraction *= 2; + bit = fraction; + } + + if (negative) + { + frac20 = (~frac20 + 1U) & 0xfffffU; + frac_hi = 0x10 | ((frac20 >> 16) & 0xf) | RT_BIT(5); + } + else + { + frac_hi = ((frac20 >> 16) & 0xf) | RT_BIT(5); + } + + *frac_reg = (0x20U << 24) | ((rt_uint32_t)frac_hi << 16) | + (frac20 & 0xffffU); +} + +static void spacemit_hdmi_pll_program(struct spacemit_hdmi *hdmi, + rt_uint32_t pixel_clock_khz) +{ + int integer_part; + rt_uint32_t frac_reg; + rt_uint32_t div_reg, post_reg; + int pll8 = spacemit_hdmi_pll8(pixel_clock_khz); + int pll6 = spacemit_hdmi_pll6(pixel_clock_khz); + int pll5 = spacemit_hdmi_pll5(pixel_clock_khz); + + spacemit_hdmi_pll_fraction(pixel_clock_khz, &integer_part, &frac_reg); + + div_reg = (0x50U << 24) | + ((0x0dU | ((rt_uint32_t)pll6 << 4) | (2U << 6)) << 16) | + ((0x40U | (rt_uint32_t)pll5) << 8) | + ((rt_uint32_t)integer_part & 0xffU); + post_reg = (8U << 8) | ((rt_uint32_t)pll8 << 5) | 1U; + + spacemit_hdmi_writel(hdmi, SPACEMIT_HDMI_PLL_FRAC, frac_reg); + spacemit_hdmi_writel(hdmi, SPACEMIT_HDMI_PLL_DIV, div_reg); + spacemit_hdmi_writel(hdmi, SPACEMIT_HDMI_PLL_POST, post_reg); +} + +static rt_err_t spacemit_hdmi_detect( + struct spacemit_display_connector *connector, rt_bool_t *connected) +{ + struct spacemit_hdmi *hdmi; + + if (!connector || !connected) + { + return -RT_EINVAL; + } + + hdmi = connector->priv; + *connected = !!(spacemit_hdmi_readl(hdmi, + SPACEMIT_HDMI_PHY_STATUS) & SPACEMIT_HDMI_PHY_HPD); + + return RT_EOK; +} + +static rt_err_t spacemit_hdmi_get_timing( + struct spacemit_display_connector *connector, + struct spacemit_display_timing *timing) +{ + if (!connector || !timing) + { + return -RT_EINVAL; + } + + *timing = spacemit_hdmi_1080p60; + return RT_EOK; +} + +static rt_err_t spacemit_hdmi_prepare(struct spacemit_hdmi *hdmi) +{ + rt_err_t err; + + if (hdmi->prepared) + { + return RT_EOK; + } + + if ((err = rt_clk_prepare_enable(hdmi->mclk))) + { + return err; + } + if ((err = rt_clk_set_rate(hdmi->mclk, SPACEMIT_HDMI_MCLK_RATE))) + { + rt_clk_disable_unprepare(hdmi->mclk); + return err; + } + if ((err = rt_reset_control_deassert(hdmi->rstc))) + { + rt_clk_disable_unprepare(hdmi->mclk); + return err; + } + + rt_hw_us_delay(10); + hdmi->prepared = RT_TRUE; + return RT_EOK; +} + +static rt_err_t spacemit_hdmi_enable( + struct spacemit_display_connector *connector, + const struct spacemit_display_timing *timing) +{ + rt_err_t err; + rt_bool_t connected; + rt_uint32_t pixel_clock_khz; + struct spacemit_hdmi *hdmi; + + if (!connector || !timing || !timing->pixelclock) + { + return -RT_EINVAL; + } + + hdmi = connector->priv; + if (hdmi->enabled) + { + return RT_EOK; + } + if ((err = spacemit_hdmi_prepare(hdmi))) + { + return err; + } + + pixel_clock_khz = (rt_uint32_t)(timing->pixelclock / 1000ULL); + + spacemit_hdmi_writel(hdmi, SPACEMIT_HDMI_PHY_ANALOG, 0xae5c410fU); + spacemit_hdmi_update_bits(hdmi, SPACEMIT_HDMI_PHY_ANALOG, + 0x3U << 29, 0x1U << 29); + spacemit_hdmi_update_bits(hdmi, SPACEMIT_HDMI_PHY_ANALOG, + 0xfU << 18, 0x7U << 18); + spacemit_hdmi_update_bits(hdmi, SPACEMIT_HDMI_PHY_ANALOG, + 0x3U << 14, 0); + + spacemit_hdmi_writel(hdmi, SPACEMIT_HDMI_COLOR_DEPTH, + 0x0000000dU | (4U << 4)); + spacemit_hdmi_pll_program(hdmi, pixel_clock_khz); + spacemit_hdmi_writel(hdmi, SPACEMIT_HDMI_PLL_CTRL, 0); + spacemit_hdmi_writel(hdmi, SPACEMIT_HDMI_PLL_CTRL, 3); + rt_hw_us_delay(100); + spacemit_hdmi_writel(hdmi, SPACEMIT_HDMI_PHY_CTRL, + 0x1c208000U | SPACEMIT_HDMI_EIGHT_BPP); + rt_hw_dsb(); + + hdmi->enabled = RT_TRUE; + spacemit_hdmi_detect(connector, &connected); + LOG_D("%ux%u@%u, pclk=%u kHz, mclk=%lu Hz, HPD=%d, pll=0x%08x", + timing->hactive, timing->vactive, timing->refresh, + pixel_clock_khz, rt_clk_get_rate(hdmi->mclk), connected, + spacemit_hdmi_readl(hdmi, SPACEMIT_HDMI_PLL_CTRL)); + + return RT_EOK; +} + +static rt_err_t spacemit_hdmi_disable( + struct spacemit_display_connector *connector) +{ + struct spacemit_hdmi *hdmi; + + if (!connector) + { + return -RT_EINVAL; + } + + hdmi = connector->priv; + if (hdmi->enabled) + { + spacemit_hdmi_writel(hdmi, SPACEMIT_HDMI_PLL_CTRL, 0); + rt_hw_us_delay(100); + hdmi->enabled = RT_FALSE; + } + + if (hdmi->prepared) + { + rt_clk_disable_unprepare(hdmi->mclk); + hdmi->prepared = RT_FALSE; + } + + return RT_EOK; +} + +static const struct spacemit_display_connector_ops spacemit_hdmi_ops = +{ + .detect = spacemit_hdmi_detect, + .get_timing = spacemit_hdmi_get_timing, + .enable = spacemit_hdmi_enable, + .disable = spacemit_hdmi_disable, +}; + +static rt_err_t spacemit_hdmi_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + struct rt_device *dev = &pdev->parent; + struct spacemit_hdmi *hdmi = rt_calloc(1, sizeof(*hdmi)); + + if (!hdmi) + { + return -RT_ENOMEM; + } + + hdmi->dev = dev; + hdmi->regs = rt_dm_dev_iomap(dev, 0); + if (!hdmi->regs) + { + err = -RT_EIO; + goto _fail; + } + + hdmi->mclk = rt_clk_get_by_name(dev, "hmclk"); + if (rt_is_err(hdmi->mclk)) + { + err = rt_ptr_err(hdmi->mclk); + hdmi->mclk = RT_NULL; + goto _fail_unmap; + } + + hdmi->rstc = rt_reset_control_get_by_name(dev, "hdmi_reset"); + if (rt_is_err(hdmi->rstc)) + { + err = rt_ptr_err(hdmi->rstc); + hdmi->rstc = RT_NULL; + goto _fail_clk; + } + + if ((err = spacemit_display_connector_register(&hdmi->connector, + dev->ofw_node, &spacemit_hdmi_ops, hdmi))) + { + goto _fail_reset; + } + + pdev->parent.user_data = hdmi; + LOG_D("connector ready: %s", rt_ofw_node_full_name(dev->ofw_node)); + + return RT_EOK; + +_fail_reset: + rt_reset_control_put(hdmi->rstc); +_fail_clk: + rt_clk_put(hdmi->mclk); +_fail_unmap: + rt_iounmap(hdmi->regs); +_fail: + rt_free(hdmi); + return err; +} + +static rt_err_t spacemit_hdmi_remove(struct rt_platform_device *pdev) +{ + struct spacemit_hdmi *hdmi = pdev->parent.user_data; + + if (!hdmi) + { + return RT_EOK; + } + + spacemit_hdmi_disable(&hdmi->connector); + spacemit_display_connector_unregister(&hdmi->connector); + rt_reset_control_assert(hdmi->rstc); + rt_reset_control_put(hdmi->rstc); + rt_clk_put(hdmi->mclk); + rt_iounmap(hdmi->regs); + rt_free(hdmi); + pdev->parent.user_data = RT_NULL; + + return RT_EOK; +} + +static const struct rt_ofw_node_id spacemit_hdmi_ids[] = +{ + { .compatible = "spacemit,hdmi" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver spacemit_hdmi_driver = +{ + .name = "hdmi-spacemit", + .ids = spacemit_hdmi_ids, + .probe = spacemit_hdmi_probe, + .remove = spacemit_hdmi_remove, +}; + +rt_err_t spacemit_hdmi_driver_register(void) +{ + return rt_platform_driver_register(&spacemit_hdmi_driver); +} diff --git a/bsp/spacemit/dm/graphic/logo/Kconfig b/bsp/spacemit/dm/graphic/logo/Kconfig new file mode 100644 index 000000000000..060eeee53b8d --- /dev/null +++ b/bsp/spacemit/dm/graphic/logo/Kconfig @@ -0,0 +1,5 @@ +config RT_GRAPHIC_LOGO_BIANBU_CLUT224 + bool "Standard 224-color Bianbu logo" + +config RT_GRAPHIC_LOGO_SPACEMIT_CLUT224 + bool "Standard 224-color Spacemit logo" diff --git a/bsp/spacemit/dm/graphic/logo/Kconfig.path b/bsp/spacemit/dm/graphic/logo/Kconfig.path new file mode 100644 index 000000000000..83a3f0012e90 --- /dev/null +++ b/bsp/spacemit/dm/graphic/logo/Kconfig.path @@ -0,0 +1,10 @@ +if RT_GRAPHIC_LOGO_BIANBU_CLUT224 + config RT_GRAPHIC_LOGO_BIANBU_CLUT224_PATH + string + default "../dm/graphic/logo/logo-bianbu-clut224.ppm" +endif +if RT_GRAPHIC_LOGO_SPACEMIT_CLUT224 + config RT_GRAPHIC_LOGO_SPACEMIT_CLUT224_PATH + string + default "../dm/graphic/logo/logo-spacemit-clut224.ppm" +endif diff --git a/bsp/spacemit/dm/graphic/logo/logo-bianbu-clut224.ppm b/bsp/spacemit/dm/graphic/logo/logo-bianbu-clut224.ppm new file mode 100644 index 000000000000..8f9aeeaf8e7c --- /dev/null +++ b/bsp/spacemit/dm/graphic/logo/logo-bianbu-clut224.ppm @@ -0,0 +1,9333 @@ +P3 +256 256 +255 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +6 7 2 28 33 10 49 59 17 67 79 24 80 96 28 95 113 33 108 128 38 121 144 43 +135 160 47 148 175 52 153 181 54 153 182 54 164 195 58 164 195 58 168 200 59 176 209 62 +176 209 62 168 200 59 164 195 58 164 195 58 153 182 54 153 181 54 148 175 52 135 160 47 +121 144 43 108 128 38 95 113 33 80 96 28 67 79 24 49 59 17 26 31 9 6 7 2 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 2 2 1 26 31 9 59 70 21 90 107 32 114 135 40 136 161 48 159 189 56 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 175 208 62 +159 189 56 136 161 48 112 134 40 89 106 31 58 69 20 26 31 9 2 2 1 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 3 3 1 37 43 13 76 90 27 108 128 38 +139 166 49 169 201 60 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 169 201 60 139 166 49 +108 128 38 75 89 26 37 43 13 3 3 1 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +8 10 3 41 49 15 82 98 29 124 147 44 166 197 58 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 169 201 60 135 161 48 94 111 33 54 64 19 12 14 4 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 1 2 0 35 42 12 82 98 29 129 153 45 +173 205 61 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 175 207 62 +141 167 50 94 111 33 41 49 15 1 2 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 10 12 4 63 75 22 112 134 40 162 192 57 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 162 192 57 111 132 39 61 72 21 10 11 3 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 7 2 54 64 19 +111 132 39 168 200 59 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 171 203 60 124 147 44 +65 77 23 9 11 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 4 5 1 58 69 20 118 140 42 170 202 60 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 169 201 60 117 139 41 57 67 20 4 5 1 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 26 31 9 94 111 33 162 192 57 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 164 195 58 105 125 37 31 37 11 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 6 2 59 70 21 +129 153 45 175 208 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 141 167 50 +71 84 25 7 8 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 14 17 5 82 98 29 159 189 56 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 162 193 57 94 111 33 18 21 6 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 28 33 10 106 126 37 170 202 60 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 175 207 62 153 181 54 153 181 54 143 169 50 +143 169 50 153 181 54 153 181 54 157 187 55 164 195 58 164 195 58 175 208 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 170 202 60 105 125 37 26 31 9 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +39 46 14 122 145 43 175 207 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 173 206 61 +154 183 54 131 156 46 109 129 38 88 104 31 67 79 24 54 64 19 41 48 14 28 33 10 +99 99 99 255 255 255 255 255 255 255 255 255 93 93 93 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 14 17 5 +28 33 10 41 48 14 54 64 19 67 79 24 88 104 31 109 129 38 133 157 47 155 184 54 +174 207 61 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 175 207 62 122 145 43 38 45 13 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 35 41 12 124 147 44 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 174 207 61 149 178 53 117 139 41 86 102 30 55 65 19 23 27 8 3 3 1 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 27 27 27 +238 238 238 255 255 255 255 255 255 242 242 242 13 13 13 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +3 4 1 24 29 9 55 65 19 86 102 30 118 140 42 149 178 53 174 207 61 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +122 145 43 35 41 12 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 30 35 10 119 142 42 175 208 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 162 192 57 121 144 43 78 93 27 +39 46 14 7 8 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 183 183 183 +255 255 255 255 255 255 255 255 255 157 157 157 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 8 2 41 48 14 +80 96 28 121 144 43 162 192 57 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 175 208 62 119 142 42 30 35 10 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 19 23 7 112 134 40 175 207 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 162 193 57 114 135 40 66 78 23 26 31 9 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 99 99 99 255 255 255 +255 255 255 255 255 255 255 255 255 60 60 60 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 26 31 9 67 79 24 115 137 41 163 193 57 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 175 207 62 112 134 40 19 23 7 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +7 8 2 82 98 29 168 199 59 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 175 207 62 141 167 50 94 111 33 +47 55 16 3 3 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 21 21 21 234 234 234 255 255 255 +255 255 255 255 255 255 219 219 219 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 2 0 35 42 12 +82 98 29 129 153 45 173 206 61 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 169 201 60 94 111 33 8 10 3 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 54 64 19 +154 183 54 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 175 207 62 135 161 48 77 92 27 18 21 6 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 161 161 161 255 255 255 255 255 255 +255 255 255 255 255 255 124 124 124 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 14 16 5 65 77 23 129 153 45 175 207 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 157 187 55 +65 77 23 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 31 37 11 136 161 48 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +138 164 48 77 92 27 19 22 7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 60 60 60 254 254 254 255 255 255 255 255 255 +255 255 255 252 252 252 27 27 27 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 19 23 7 78 93 27 139 166 49 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 135 160 47 30 35 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 3 4 1 82 98 29 171 203 60 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 166 197 58 105 125 37 32 38 11 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 6 6 6 215 215 215 255 255 255 255 255 255 255 255 255 +255 255 255 187 187 187 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +28 34 10 94 111 33 162 193 57 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 173 205 61 94 111 33 5 6 2 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 41 48 14 148 175 52 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 133 157 47 63 75 22 6 7 2 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 129 129 129 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 88 88 88 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 6 7 2 65 77 23 134 159 47 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 147 175 52 41 48 14 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +8 10 3 103 122 36 175 207 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +173 205 61 112 134 40 35 41 12 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 37 37 37 246 246 246 255 255 255 255 255 255 255 255 255 255 255 255 +241 241 241 10 10 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 71 71 71 190 190 190 215 215 215 234 234 234 238 238 238 +238 238 238 238 238 238 238 238 238 231 231 231 215 215 215 198 198 198 180 180 180 143 143 143 +110 110 110 74 74 74 34 34 34 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 35 41 12 114 135 40 173 206 61 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 175 207 62 101 120 35 8 10 3 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 37 43 13 +149 178 53 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 167 198 59 100 119 35 +21 25 7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 180 180 180 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +154 154 154 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 27 27 27 149 149 149 249 249 249 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 234 234 234 180 180 180 124 124 124 53 53 53 2 2 2 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 17 20 6 +88 105 31 165 196 58 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 153 182 54 +41 48 14 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 1 86 102 30 173 205 61 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 164 195 58 86 102 30 10 11 3 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 66 66 66 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +60 60 60 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 34 34 34 169 169 169 +254 254 254 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 234 234 234 +161 161 161 71 71 71 3 3 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 10 12 4 88 104 31 166 197 58 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +173 205 61 84 99 29 2 2 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 21 25 7 133 157 47 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 168 199 59 94 111 33 12 14 4 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +3 3 3 208 208 208 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 215 215 215 +1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +60 60 60 198 198 198 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 231 231 231 139 139 139 27 27 27 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 9 11 3 82 98 29 166 197 58 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 138 164 48 23 27 8 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 55 65 19 166 197 58 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +170 202 60 95 113 33 13 16 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +99 99 99 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 119 119 119 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 3 3 3 110 110 110 242 242 242 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 249 249 249 165 165 165 48 48 48 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 14 17 5 97 115 34 170 202 60 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 165 196 58 54 64 19 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 1 1 0 82 98 29 175 207 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 124 147 44 +23 27 8 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 13 13 13 +231 231 231 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 252 252 252 27 27 27 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 34 34 34 187 187 187 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 252 252 252 165 165 165 +27 27 27 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 19 23 7 +111 132 39 175 208 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 175 208 62 94 111 33 2 2 1 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +13 16 5 127 151 45 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 143 169 50 44 52 15 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 133 133 133 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 183 183 183 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 114 114 114 249 249 249 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +246 246 246 129 129 129 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 44 52 15 143 169 50 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 131 156 46 14 17 5 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 35 41 12 +154 183 54 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 164 195 58 68 81 24 1 2 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 27 27 27 246 246 246 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 88 88 88 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 53 53 53 222 222 222 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 208 208 208 48 48 48 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 2 2 1 71 84 25 164 195 58 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 153 182 54 +33 39 11 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 56 66 20 169 201 60 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 124 147 44 19 22 7 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 161 161 161 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 239 239 239 8 8 8 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 21 21 21 +190 190 190 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 252 252 250 119 119 119 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 16 19 6 111 132 39 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +170 202 60 59 70 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 92 27 175 207 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +159 189 56 57 67 20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 42 42 42 252 252 252 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 149 149 149 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +6 6 6 161 161 161 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 161 161 161 6 6 6 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 52 62 18 156 185 55 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 175 208 62 88 105 31 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 2 2 1 103 122 36 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 106 126 37 +10 11 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 172 172 172 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 53 53 53 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 1 1 1 143 143 143 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 190 190 190 13 13 13 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 12 4 +108 128 38 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 101 120 35 2 2 1 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 8 9 3 122 145 43 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 162 193 57 55 65 19 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 48 48 48 254 254 254 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 215 215 215 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 143 143 143 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 198 198 198 +13 13 13 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 56 66 20 163 193 57 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 127 151 45 9 11 3 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 11 13 4 136 161 48 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 129 153 45 19 22 7 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 172 172 172 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 124 124 124 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 1 1 1 161 161 161 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +190 190 190 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 16 19 6 125 149 44 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 139 166 49 13 16 5 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +14 17 5 143 169 50 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 172 204 61 77 92 27 1 1 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 42 42 42 252 252 252 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 37 37 37 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 190 190 190 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 157 157 157 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 1 2 0 80 96 28 173 205 61 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 143 169 50 14 17 5 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 17 20 6 +146 173 51 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 157 187 55 39 46 14 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 176 176 176 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 198 198 198 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 24 24 24 231 231 231 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 93 93 93 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 41 48 14 159 189 56 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 148 175 52 +19 22 7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 21 25 8 151 179 53 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +134 159 47 17 20 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 48 48 48 254 254 254 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 105 106 101 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 66 66 66 254 254 254 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 242 242 242 37 37 37 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 14 17 5 130 154 46 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +154 183 54 24 29 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 21 25 8 155 184 54 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 99 117 35 +3 3 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 176 176 176 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 252 252 250 21 21 21 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 157 157 157 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 187 187 187 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 4 1 +100 119 35 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 155 184 54 21 25 8 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 18 21 6 152 180 53 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 172 204 61 65 77 23 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 48 48 48 254 254 254 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 180 180 180 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 17 17 17 +238 238 238 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 84 84 84 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 67 79 24 173 205 61 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 152 180 53 18 21 6 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 14 17 5 147 175 52 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 164 195 58 44 52 15 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 172 172 172 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 88 88 88 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +124 124 124 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 215 215 215 2 2 2 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 47 55 16 165 196 58 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 149 178 53 16 19 6 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 10 12 4 141 167 50 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 154 183 54 28 34 10 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +34 34 34 252 252 252 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 242 242 242 10 10 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +13 13 13 241 241 241 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 77 77 77 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 30 35 10 155 184 54 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 144 171 51 12 14 4 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 8 10 3 138 164 48 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 139 166 49 17 20 6 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +143 143 143 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 165 165 165 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 154 154 154 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 183 183 183 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 17 20 6 141 168 50 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 136 161 48 8 9 3 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +2 2 1 121 144 43 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 134 159 47 10 11 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 13 13 13 +241 241 241 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 77 77 77 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 60 60 60 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 249 249 249 17 17 17 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 8 10 3 130 154 46 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 124 147 44 2 2 1 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +101 120 35 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +131 156 46 8 10 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 114 114 114 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +241 241 241 8 8 8 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 3 3 3 236 236 236 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 93 93 93 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 8 2 127 151 45 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 105 125 37 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 78 93 27 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 124 147 44 +6 7 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 222 222 222 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +161 161 161 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 176 176 176 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 154 154 154 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 5 1 +119 142 42 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +77 92 27 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 57 67 20 175 207 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 117 139 41 3 4 1 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 88 88 88 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +77 77 77 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 133 133 133 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 208 208 208 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +3 4 1 117 139 41 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +174 207 61 55 65 19 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 35 41 12 170 202 60 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 121 144 43 3 4 1 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 198 198 198 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 241 241 241 +8 8 8 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 93 93 93 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 239 239 239 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 3 4 1 122 145 43 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 169 201 60 32 38 11 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 12 14 4 153 181 54 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 129 153 45 6 7 2 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 60 60 60 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 161 161 161 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 80 80 80 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 8 8 8 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 4 5 1 125 149 44 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 155 184 54 13 16 5 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 1 2 0 125 149 44 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 136 161 48 8 10 3 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 172 172 172 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 77 77 77 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 74 74 74 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 24 24 24 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 7 8 2 133 157 47 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 127 151 45 2 2 1 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 92 110 32 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 139 166 49 9 11 3 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 27 27 27 252 252 250 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 239 239 239 6 6 6 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 88 88 88 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 13 13 13 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 10 12 4 141 168 50 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 89 106 31 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 54 64 19 175 208 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 154 183 54 17 20 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 129 129 129 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 161 161 161 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 110 110 110 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 6 6 6 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 17 20 6 155 184 54 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 175 208 62 56 66 20 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 21 25 8 166 197 58 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +165 196 58 28 34 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 3 3 3 222 222 222 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 77 77 77 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 154 154 154 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 231 231 231 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 30 35 10 166 197 58 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 164 195 58 19 23 7 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 2 0 131 156 46 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 173 205 61 +47 55 16 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 77 77 77 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 246 246 246 10 10 10 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 208 208 208 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 187 187 187 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 44 52 15 +172 204 61 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 134 159 47 2 2 1 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +86 102 30 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 66 78 23 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 180 180 180 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 176 176 176 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 24 24 24 254 254 254 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 133 133 133 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +68 81 24 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 82 98 29 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 35 42 12 +173 205 61 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 99 117 35 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 27 27 27 252 252 252 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 99 99 99 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 110 110 110 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 60 60 60 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 101 120 35 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 173 205 61 +37 43 13 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 8 9 3 149 178 53 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 136 161 48 4 5 1 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 124 124 124 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 252 252 252 21 21 21 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 208 208 208 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 234 234 234 4 4 4 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 3 4 1 133 157 47 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +151 179 53 8 10 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 103 122 36 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 157 187 55 16 19 6 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 215 215 215 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 194 194 194 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +71 71 71 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 133 133 133 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 17 20 6 159 189 56 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 100 119 35 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 39 46 14 175 207 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 173 205 61 41 49 15 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 53 53 53 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 114 114 114 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 +198 198 198 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 252 252 250 27 27 27 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 39 46 14 172 204 61 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 175 207 62 41 48 14 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 5 6 2 148 175 52 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 78 93 27 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 149 149 149 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 37 37 37 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 99 99 99 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 149 149 149 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 80 96 28 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 146 173 51 4 5 1 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 90 107 32 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 127 151 45 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +6 6 6 234 234 234 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 215 215 215 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 27 27 27 239 239 239 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 239 239 239 21 21 21 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 1 2 0 130 154 46 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 87 103 31 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 31 37 11 172 204 61 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 164 195 58 19 23 7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +80 80 80 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 133 133 133 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 190 190 190 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 105 106 101 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 19 22 7 163 193 57 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 172 204 61 30 35 10 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 1 1 0 136 161 48 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 55 65 19 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +165 165 165 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 60 60 60 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 143 143 143 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 169 169 169 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 57 67 20 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 133 157 47 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 63 75 22 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +108 128 38 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 10 10 +242 242 242 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 239 239 239 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 119 119 119 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 215 215 215 13 13 13 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 109 129 38 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 59 70 21 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 6 7 2 155 184 54 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 159 189 56 +11 13 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 84 84 84 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 172 172 172 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 110 110 110 254 254 254 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +231 231 231 34 34 34 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 12 4 +157 187 55 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 156 185 55 7 8 2 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 89 106 31 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 55 65 19 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 169 169 169 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 99 99 99 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 124 124 124 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 236 236 236 +42 42 42 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +52 62 18 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 86 102 30 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +19 23 7 168 200 59 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 117 139 41 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 10 10 242 242 242 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 27 27 27 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +6 6 6 154 154 154 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 222 222 222 42 42 42 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 119 142 42 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 169 201 60 21 25 7 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +112 134 40 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 164 195 58 16 19 6 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 84 84 84 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 215 215 215 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 27 27 27 +198 198 198 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 208 208 208 27 27 27 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 17 20 6 165 196 58 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 111 132 39 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 30 35 10 +175 207 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 71 84 25 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 165 165 165 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 143 143 143 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 84 84 84 236 236 236 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 161 161 161 13 13 13 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 71 84 25 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 174 207 61 +28 34 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 119 142 42 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 143 169 50 2 2 1 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 236 236 236 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 71 71 71 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 24 24 24 165 165 165 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 242 242 242 93 93 93 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 2 2 1 144 171 51 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +115 137 41 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 35 41 12 175 208 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 44 52 15 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 60 60 60 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +246 246 246 10 10 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 4 4 4 110 110 110 239 239 239 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 180 180 180 34 34 34 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 44 52 15 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +175 208 62 32 38 11 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 124 147 44 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 117 139 41 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 139 139 139 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +183 183 183 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 1 1 84 84 84 215 215 215 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 222 222 222 +80 80 80 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 119 142 42 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 121 144 43 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 37 43 13 175 208 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 170 202 60 21 25 8 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 215 215 215 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +114 114 114 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 84 84 84 +208 208 208 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 234 234 234 114 114 114 8 8 8 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 23 27 8 170 202 60 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 37 43 13 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 122 145 43 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 95 113 33 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 37 37 37 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +48 48 48 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 13 13 13 110 110 110 219 219 219 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 234 234 234 124 124 124 13 13 13 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 97 115 34 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 120 143 42 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 26 31 9 175 207 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 168 199 59 14 17 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 110 110 110 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 238 238 238 +2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 1 1 1 60 60 60 157 157 157 242 242 242 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 208 208 208 93 93 93 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 14 16 5 167 198 59 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 175 207 62 28 33 10 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 106 126 37 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 90 107 32 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 180 180 180 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 180 180 180 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 48 48 48 +133 133 133 222 222 222 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 239 239 239 157 157 157 +60 60 60 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 94 111 33 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 103 122 36 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 14 17 5 170 202 60 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +166 197 58 12 14 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 4 4 4 241 241 241 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 114 114 114 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 13 13 13 74 74 74 149 149 149 222 222 222 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 252 252 252 176 176 176 80 80 80 6 6 6 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 11 13 4 165 196 58 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 170 202 60 16 19 6 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 90 107 32 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +86 102 30 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 60 60 60 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 53 53 53 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 27 27 27 169 169 169 249 249 249 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 242 242 242 194 194 194 139 139 139 88 88 88 +34 34 34 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 89 106 31 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 88 104 31 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 6 7 2 162 193 57 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 166 198 59 +10 11 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 129 129 129 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 242 242 242 4 4 4 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 2 2 2 60 60 60 149 149 149 231 231 231 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 231 231 231 154 154 154 71 71 71 6 6 6 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 12 14 4 +167 198 59 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 162 192 57 6 7 2 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 63 75 22 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 97 115 34 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 198 198 198 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 183 183 183 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 71 71 71 176 176 176 +252 252 250 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 241 241 241 169 169 169 84 84 84 6 6 6 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +99 117 35 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 61 72 21 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 133 157 47 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 173 205 61 21 25 7 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 13 13 13 252 252 250 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 124 124 124 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +24 24 24 119 119 119 222 222 222 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 234 234 234 +133 133 133 27 27 27 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +19 23 7 173 205 61 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 131 156 46 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 26 31 9 175 208 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 112 134 40 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 74 74 74 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 60 60 60 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 4 4 4 93 93 93 215 215 215 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 249 249 249 165 165 165 53 53 53 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 114 135 40 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 175 208 62 25 30 9 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 97 115 34 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 35 41 12 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 133 133 133 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 246 246 246 6 6 6 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 77 77 77 208 208 208 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 180 180 180 34 34 34 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 35 42 12 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 94 111 33 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +4 5 1 162 192 57 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 134 159 47 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 190 190 190 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 190 190 190 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 84 84 84 +222 222 222 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 249 249 249 139 139 139 17 17 17 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 135 160 47 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 160 190 56 3 4 1 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +58 69 20 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 65 77 23 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 6 6 6 246 246 246 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 133 133 133 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +8 8 8 119 119 119 242 242 242 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 236 236 236 +84 84 84 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 65 77 23 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 55 65 19 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +119 142 42 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 165 196 58 7 8 2 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 60 60 60 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 80 80 80 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 24 24 24 161 161 161 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 161 161 161 13 13 13 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 6 7 2 164 195 58 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 115 137 41 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 8 10 3 +170 202 60 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 100 119 35 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 114 114 114 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 27 27 27 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 71 71 71 231 231 231 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 222 222 222 60 60 60 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 103 122 36 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 169 201 60 +8 9 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 63 75 22 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 32 38 11 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 172 172 172 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 234 234 234 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 17 17 17 165 165 165 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 249 249 249 88 88 88 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 32 38 11 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +59 70 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 121 144 43 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 139 166 49 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 222 222 222 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 180 180 180 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 84 84 84 +242 242 242 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 252 252 252 110 110 110 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 141 168 50 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +119 142 42 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 11 3 170 202 60 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 77 92 27 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +21 21 21 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 129 129 129 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +37 37 37 215 215 215 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 133 133 133 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 80 96 28 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +170 202 60 10 11 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 63 75 22 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 175 207 62 19 23 7 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +71 71 71 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 77 77 77 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 21 21 21 187 187 187 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 139 139 139 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 21 25 8 175 208 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 59 70 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 112 134 40 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 134 159 47 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +119 119 119 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 24 24 24 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 4 4 4 157 157 157 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +110 110 110 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 138 164 48 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 109 129 38 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 2 0 162 192 57 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 75 89 26 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +172 172 172 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 231 231 231 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 1 1 1 149 149 149 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +252 252 252 71 71 71 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 92 27 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 159 189 56 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 37 43 13 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 175 207 62 17 20 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +222 222 222 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 176 176 176 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 157 157 157 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 234 234 234 27 27 27 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 19 22 7 175 208 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 35 41 12 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 88 104 31 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 139 166 49 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 13 13 13 +254 254 254 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 124 124 124 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 165 165 165 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 183 183 183 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 141 168 50 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 84 99 29 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 138 164 48 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 88 105 31 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 53 53 53 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 77 77 77 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 8 8 8 208 208 208 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 99 99 99 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 90 107 32 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 134 159 47 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 11 13 4 174 207 61 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 39 46 14 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 99 99 99 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 34 34 34 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 34 34 34 +234 234 234 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 234 234 234 13 13 13 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 41 48 14 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 173 206 61 9 11 3 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 51 61 18 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +164 195 58 2 2 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 139 139 139 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 246 246 246 3 3 3 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +74 74 74 254 254 254 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 129 129 129 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 1 164 195 58 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 49 59 17 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 90 107 32 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +114 135 40 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 180 180 180 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 208 208 208 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 154 154 154 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 239 239 239 13 13 13 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 117 139 41 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 88 105 31 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 131 156 46 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +67 79 24 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 222 222 222 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 169 169 169 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 17 17 17 236 236 236 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 110 110 110 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 68 81 24 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 129 153 45 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 3 4 1 169 201 60 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +25 30 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 10 10 252 252 252 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 129 129 129 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 119 119 119 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 208 208 208 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 28 34 10 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 168 199 59 3 3 1 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 37 43 13 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 162 193 57 +1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 48 48 48 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 88 88 88 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 10 10 10 238 238 238 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 42 42 42 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 +162 192 57 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 35 41 12 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 75 89 26 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 121 144 43 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 80 80 80 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 48 48 48 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 143 143 143 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 114 114 114 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +122 145 43 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 75 89 26 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 108 128 38 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 80 96 28 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 114 114 114 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 252 252 252 10 10 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 48 48 48 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 183 183 183 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +82 98 29 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 106 126 37 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 139 166 49 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 41 48 14 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 143 143 143 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 222 222 222 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 222 222 222 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 234 234 234 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +41 48 14 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 138 164 48 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 2 2 1 169 201 60 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 175 207 62 8 9 3 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 180 180 180 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 183 183 183 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 161 161 161 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 24 24 24 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +8 9 3 175 207 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 168 200 59 1 2 0 0 0 0 0 0 0 + +0 0 0 0 0 0 28 33 10 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 149 178 53 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 208 208 208 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 143 143 143 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 110 110 110 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 53 53 53 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 151 179 53 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 24 29 9 0 0 0 0 0 0 + +0 0 0 0 0 0 59 70 21 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 119 142 42 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 242 242 242 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 110 110 110 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 80 80 80 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 77 77 77 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 119 142 42 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 56 66 20 0 0 0 0 0 0 + +0 0 0 0 0 0 90 107 32 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 88 104 31 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 17 17 17 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 77 77 77 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 60 60 60 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 84 84 84 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 88 105 31 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 87 103 31 0 0 0 0 0 0 + +0 0 0 0 0 0 114 135 40 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 56 66 20 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 42 42 42 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 48 48 48 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 53 53 53 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 88 88 88 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 57 67 20 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 111 132 39 0 0 0 0 0 0 + +0 0 0 0 0 0 136 161 48 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 26 31 9 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 66 66 66 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 13 13 13 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 60 60 60 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 77 77 77 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 26 31 9 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 134 159 47 0 0 0 0 0 0 + +0 0 0 0 0 0 159 189 56 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 175 207 62 4 5 1 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 88 88 88 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +241 241 241 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 84 84 84 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 60 60 60 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 4 5 1 175 207 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 156 185 55 0 0 0 0 0 0 + +0 0 0 6 7 2 175 208 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 156 185 55 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 110 110 110 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +208 208 208 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 119 119 119 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 34 34 34 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 157 187 55 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 175 207 62 5 6 2 0 0 0 + +0 0 0 28 33 10 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 134 159 47 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 133 133 133 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +183 183 183 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 176 176 176 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 246 246 246 2 2 2 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 135 160 47 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 25 30 9 0 0 0 + +0 0 0 49 59 17 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 111 132 39 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 157 157 157 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +161 161 161 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 3 3 3 236 236 236 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 198 198 198 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 111 132 39 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 49 59 17 0 0 0 + +0 0 0 68 81 24 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 89 106 31 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 180 180 180 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +139 139 139 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 71 71 71 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 139 139 139 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 89 106 31 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 66 78 23 0 0 0 + +0 0 0 80 96 28 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 71 84 25 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 198 198 198 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +114 114 114 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 161 161 161 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 71 71 71 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 68 81 24 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 78 93 27 0 0 0 + +0 0 0 95 113 33 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 56 66 20 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 215 215 215 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +93 93 93 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 27 27 27 249 249 249 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 239 239 239 6 6 6 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 55 65 19 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 94 111 33 0 0 0 + +0 0 0 108 128 38 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 44 52 15 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 222 222 222 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +71 71 71 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 143 143 143 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 161 161 161 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 41 49 15 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 106 126 37 0 0 0 + +0 0 0 122 145 43 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 28 34 10 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 236 236 236 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +48 48 48 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 37 37 37 249 249 249 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 53 53 53 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 28 34 10 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 120 143 42 0 0 0 + +0 0 0 135 161 48 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 14 17 5 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 249 249 249 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +34 34 34 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 187 187 187 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 208 208 208 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 14 17 5 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 133 157 47 0 0 0 + +0 0 0 147 175 52 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 175 208 62 3 4 1 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 6 6 6 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +17 17 17 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +105 106 101 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 84 84 84 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 3 3 1 175 208 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 146 173 51 0 0 0 + +0 0 0 153 181 54 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 170 202 60 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 17 17 17 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 254 254 254 +3 3 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 42 42 42 +246 246 246 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 208 208 208 2 2 2 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 168 199 59 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 151 179 53 0 0 0 + +0 0 0 157 187 55 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 165 196 58 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 34 34 34 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 241 241 241 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 21 21 21 219 219 219 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 74 74 74 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 164 195 58 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 155 184 54 0 0 0 + +0 0 0 162 192 57 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 162 192 57 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 37 37 37 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 222 222 222 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 190 190 190 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 172 172 172 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 159 189 56 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 160 190 56 0 0 0 + +0 0 0 166 197 58 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 157 187 55 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 42 42 42 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 215 215 215 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 172 172 172 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 242 242 242 27 27 27 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 155 184 54 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 164 195 58 0 0 0 + +0 0 0 170 202 60 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 153 181 54 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 42 42 42 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 208 208 208 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 3 3 3 165 165 165 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 93 93 93 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 151 179 53 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 169 201 60 0 0 0 + +0 0 0 174 207 61 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 148 175 52 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 42 42 42 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 198 198 198 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 8 8 8 172 172 172 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +172 172 172 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 146 173 51 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 174 207 61 0 0 0 + +0 0 0 174 207 61 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 148 175 52 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 48 48 48 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 190 190 190 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 17 17 17 194 194 194 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 215 215 215 +17 17 17 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 144 171 51 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 174 207 61 0 0 0 + +0 0 0 170 202 60 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 153 182 54 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 48 48 48 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 183 183 183 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +37 37 37 215 215 215 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 241 241 241 42 42 42 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 148 175 52 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 169 201 60 0 0 0 + +0 0 0 166 197 58 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 157 187 55 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 53 53 53 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 176 176 176 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 84 84 84 +241 241 241 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 249 249 249 71 71 71 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 152 180 53 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 164 195 58 0 0 0 + +0 0 0 162 192 57 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 162 193 57 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 53 53 53 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 176 176 176 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 10 10 149 149 149 254 254 254 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 254 254 254 93 93 93 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 155 184 54 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 160 190 56 0 0 0 + +0 0 0 157 187 55 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 167 198 59 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 48 48 48 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 176 176 176 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 53 53 53 215 215 215 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 114 114 114 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 160 190 56 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 155 184 54 0 0 0 + +0 0 0 153 181 54 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 171 203 60 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 42 42 42 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 176 176 176 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 17 17 17 143 143 143 252 252 252 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 254 254 254 110 110 110 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 170 202 60 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 151 179 53 0 0 0 + +0 0 0 147 175 52 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 175 208 62 4 5 1 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 34 34 34 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 180 180 180 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 1 1 93 93 93 234 234 234 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 252 252 252 93 93 93 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 3 3 1 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 146 173 51 0 0 0 + +0 0 0 135 160 47 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 17 20 6 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 24 24 24 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 180 180 180 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 53 53 53 +198 198 198 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +246 246 246 77 77 77 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 12 14 4 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 133 157 47 0 0 0 + +0 0 0 121 144 43 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 31 37 11 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 17 17 17 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 180 180 180 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 48 48 48 169 169 169 254 254 254 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 222 222 222 +53 53 53 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 24 29 9 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 120 143 42 0 0 0 + +0 0 0 108 128 38 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 44 52 15 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 8 8 8 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 190 190 190 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 48 48 48 169 169 169 254 254 254 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 190 190 190 21 21 21 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 44 52 15 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 105 125 37 0 0 0 + +0 0 0 94 111 33 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 59 70 21 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 252 252 252 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 198 198 198 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 66 66 66 183 183 183 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 252 252 252 129 129 129 2 2 2 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 63 75 22 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 92 110 32 0 0 0 + +0 0 0 80 96 28 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 75 89 26 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 246 246 246 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 208 208 208 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 13 13 13 105 106 101 +208 208 208 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 208 208 208 53 53 53 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 82 98 29 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 78 93 27 0 0 0 + +0 0 0 68 81 24 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 90 107 32 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 234 234 234 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 219 219 219 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 37 37 37 133 133 133 238 238 238 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 246 246 246 129 129 129 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 99 117 35 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 66 78 23 0 0 0 + +0 0 0 49 59 17 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 112 134 40 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 215 215 215 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 231 231 231 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 13 13 13 99 99 99 194 194 194 254 254 254 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 254 254 254 +169 169 169 34 34 34 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 119 142 42 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 47 55 16 0 0 0 + +0 0 0 26 31 9 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 136 161 48 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 194 194 194 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 242 242 242 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 66 66 66 +161 161 161 242 242 242 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 187 187 187 53 53 53 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 138 164 48 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 25 30 9 0 0 0 + +0 0 0 6 7 2 175 208 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 159 189 56 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 176 176 176 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 2 2 2 60 60 60 149 149 149 231 231 231 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 252 252 252 176 176 176 60 60 60 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 157 187 55 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 175 207 62 5 6 2 0 0 0 + +0 0 0 0 0 0 159 189 56 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 175 208 62 7 8 2 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 157 157 157 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +24 24 24 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 42 42 42 129 129 129 222 222 222 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 239 239 239 143 143 143 34 34 34 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 4 5 1 173 206 61 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 156 185 55 0 0 0 0 0 0 + +0 0 0 0 0 0 136 161 48 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 28 34 10 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 133 133 133 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +42 42 42 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 60 60 60 143 143 143 +222 222 222 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 246 246 246 169 169 169 +84 84 84 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 32 38 11 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 133 157 47 0 0 0 0 0 0 + +0 0 0 0 0 0 114 135 40 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 57 67 20 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 119 119 119 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +60 60 60 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 4 4 4 66 66 66 149 149 149 231 231 231 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 234 234 234 165 165 165 84 84 84 10 10 10 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 63 75 22 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 111 132 39 0 0 0 0 0 0 + +0 0 0 0 0 0 89 106 31 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 89 106 31 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 99 99 99 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +80 80 80 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 6 6 +77 77 77 161 161 161 236 236 236 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 234 234 234 +176 176 176 110 110 110 42 42 42 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 95 113 33 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 86 102 30 0 0 0 0 0 0 + +0 0 0 0 0 0 58 69 20 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 121 144 43 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 77 77 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +105 106 101 0 0 0 0 0 0 0 0 0 0 0 0 60 60 60 161 161 161 241 241 241 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 242 242 242 208 208 208 172 172 172 124 124 124 77 77 77 27 27 27 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 127 151 45 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 55 65 19 0 0 0 0 0 0 + +0 0 0 0 0 0 26 31 9 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 154 183 54 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 48 48 48 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +133 133 133 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 17 17 17 +37 37 37 60 60 60 77 77 77 93 93 93 114 114 114 133 133 133 154 154 154 165 165 165 +172 172 172 187 187 187 190 190 190 208 208 208 215 215 215 222 222 222 234 234 234 238 238 238 +254 254 254 239 239 239 238 238 238 238 238 238 238 238 238 238 238 238 222 222 222 215 215 215 +208 208 208 190 190 190 176 176 176 154 154 154 129 129 129 110 110 110 88 88 88 60 60 60 +24 24 24 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 159 189 56 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 23 27 8 0 0 0 0 0 0 + +0 0 0 0 0 0 1 2 0 168 200 59 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 175 208 62 12 14 4 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 17 17 17 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +165 165 165 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +14 17 5 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 168 199 59 1 1 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 139 166 49 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 44 52 15 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 241 241 241 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +194 194 194 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +47 55 16 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 138 164 48 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 108 128 38 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 82 98 29 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 208 208 208 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +222 222 222 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +80 96 28 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 106 126 37 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 75 89 26 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 124 147 44 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 180 180 180 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +252 252 250 3 3 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +124 147 44 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 75 89 26 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 37 43 13 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 164 195 58 +1 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 149 149 149 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 34 34 34 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 1 +165 196 58 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 35 41 12 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 3 3 1 168 200 59 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +31 37 11 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 13 16 5 135 161 48 100 119 35 66 78 23 +31 37 11 3 4 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 119 119 119 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 77 77 77 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 37 43 13 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 167 198 59 2 2 1 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 130 154 46 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +71 84 25 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 151 179 53 176 209 62 176 209 62 +176 209 62 173 205 61 147 175 52 117 139 41 88 105 31 59 70 21 30 35 10 1 2 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 88 88 88 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 119 119 119 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 82 98 29 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 127 151 45 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 90 107 32 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +115 137 41 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 108 128 38 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 166 197 58 +135 161 48 105 125 37 75 89 26 44 52 15 14 17 5 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 48 48 48 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 157 157 157 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 125 149 44 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 88 104 31 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 49 59 17 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +164 195 58 3 3 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 65 77 23 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 165 196 58 141 167 50 117 139 41 +88 105 31 59 70 21 35 42 12 6 7 2 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 10 10 252 252 252 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 198 198 198 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 1 167 198 59 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 47 55 16 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 10 12 4 174 207 61 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 41 49 15 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 21 25 8 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 173 206 61 152 180 53 127 151 45 103 122 36 78 93 27 +56 66 20 32 38 11 8 9 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 219 219 219 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 239 239 239 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 39 46 14 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 173 206 61 8 10 3 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 136 161 48 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 92 110 32 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 151 179 53 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 159 189 56 135 161 48 111 132 39 90 107 32 68 81 24 +49 59 17 28 33 10 6 7 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 180 180 180 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 37 37 37 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 88 105 31 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 134 159 47 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 86 102 30 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 144 171 51 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 99 117 35 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 160 190 56 139 166 49 119 142 42 99 117 35 77 92 27 +56 66 20 39 46 14 19 23 7 4 5 1 0 0 0 0 0 0 0 0 0 133 133 133 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 88 88 88 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 14 17 5 37 43 13 59 70 21 80 96 28 +103 122 36 124 147 44 146 173 51 95 113 33 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 146 173 51 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 84 99 29 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 37 43 13 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 19 23 7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 49 59 17 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 160 190 56 144 171 51 124 147 44 144 171 51 +201 207 125 216 221 200 216 221 200 231 235 222 245 247 240 252 252 250 255 255 255 255 255 255 +255 255 255 255 255 255 143 143 143 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 2 2 1 18 21 6 38 45 13 55 65 19 75 89 26 92 110 32 +111 132 39 130 154 46 148 175 52 170 202 60 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 54 64 19 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 28 34 10 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 35 41 12 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 2 0 162 192 57 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 75 89 26 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 6 2 167 198 59 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +201 207 125 201 207 125 201 207 125 97 115 34 80 96 28 66 78 23 52 62 18 39 46 14 +24 29 9 10 12 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 11 3 +21 25 8 37 43 13 51 61 18 66 78 23 82 98 29 99 117 35 112 134 40 127 151 45 +144 171 51 159 189 56 174 207 61 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 171 203 60 8 9 3 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 86 102 30 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 159 189 56 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 111 132 39 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 136 161 48 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 119 142 42 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 164 195 58 154 183 54 144 171 51 133 157 47 122 145 43 +112 134 40 103 122 36 92 110 32 82 98 29 71 84 25 59 70 21 49 59 17 39 46 14 +33 39 11 23 27 8 19 23 7 12 14 4 6 7 2 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 11 3 16 19 6 23 27 8 +35 41 12 41 48 14 47 55 16 59 70 21 66 78 23 71 84 25 82 98 29 90 107 32 +99 117 35 111 132 39 124 147 44 136 161 48 148 175 52 162 192 57 173 206 61 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 127 151 45 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 144 171 51 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 109 129 38 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 61 72 21 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 175 208 62 23 27 8 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 63 75 22 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 168 200 59 164 195 58 +155 184 54 153 181 54 141 167 50 139 166 49 129 153 45 125 149 44 117 139 41 117 139 41 +117 139 41 108 128 38 105 125 37 105 125 37 105 125 37 105 125 37 105 125 37 97 115 34 +94 111 33 94 111 33 94 111 33 94 111 33 94 111 33 86 102 30 82 98 29 86 102 30 +94 111 33 94 111 33 94 111 33 99 117 35 105 125 37 105 125 37 105 125 37 109 129 38 +117 139 41 117 139 41 117 139 41 120 143 42 129 153 45 129 153 45 129 153 45 136 161 48 +143 169 50 153 181 54 162 192 57 167 198 59 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 75 89 26 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 26 31 9 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 59 70 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 11 3 170 202 60 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 84 99 29 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 8 9 3 +168 200 59 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 175 207 62 18 21 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 86 102 30 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +169 201 60 8 10 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 121 144 43 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 146 173 51 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +117 139 41 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 131 156 46 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 144 171 51 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +118 140 42 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 61 72 21 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 32 38 11 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +56 66 20 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 71 84 25 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 37 43 13 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +59 70 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 8 10 3 +169 201 60 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 101 120 35 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +6 7 2 165 196 58 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +171 203 60 13 16 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 108 128 38 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 168 199 59 +7 8 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +117 139 41 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 166 197 58 8 9 3 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 101 120 35 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +112 134 40 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 10 12 4 168 200 59 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 114 135 40 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +57 67 20 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 68 81 24 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 31 37 11 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +44 52 15 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 75 89 26 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 55 65 19 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +4 5 1 162 192 57 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 141 167 50 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 136 161 48 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 170 202 60 +135 161 48 97 115 34 58 69 20 114 135 40 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 148 175 52 +1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 147 175 52 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 159 189 56 3 4 1 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 97 115 34 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 37 43 13 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 66 78 23 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +148 175 52 86 102 30 114 135 40 141 168 50 168 200 59 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 171 203 60 141 167 50 108 128 38 75 89 26 37 43 13 3 4 1 +0 0 0 0 0 0 7 8 2 164 195 58 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 71 84 25 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 44 52 15 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 94 111 33 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 26 31 9 175 208 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 112 134 40 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 6 7 2 162 192 57 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +170 202 60 11 13 4 0 0 0 0 0 0 0 0 0 19 23 7 41 49 15 63 75 22 +86 102 30 108 128 38 129 153 45 151 179 53 171 203 60 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 173 205 61 149 178 53 121 144 43 95 113 33 +66 78 23 32 38 11 3 4 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 68 81 24 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 159 189 56 6 7 2 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 114 135 40 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 175 208 62 25 30 9 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 133 157 47 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 173 206 61 23 27 8 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 87 103 31 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 71 84 25 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 18 21 6 41 48 14 63 75 22 +84 99 29 101 120 35 119 142 42 135 161 48 152 180 53 170 202 60 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 159 189 56 133 157 47 +105 125 37 78 93 27 52 62 18 25 30 9 3 3 1 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 141 167 50 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 84 99 29 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +21 25 8 173 205 61 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 131 156 46 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 63 75 22 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 103 122 36 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 14 16 5 169 201 60 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 135 161 48 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 11 3 28 33 10 +44 52 15 63 75 22 77 92 27 95 113 33 111 132 39 129 153 45 146 173 51 162 193 57 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 170 202 60 151 179 53 134 159 47 +112 134 40 97 115 34 77 92 27 58 69 20 37 43 13 10 12 4 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 44 52 15 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 163 193 57 10 11 3 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +104 124 37 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 61 72 21 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 6 7 2 162 193 57 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 169 201 60 +14 17 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 103 122 36 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 35 41 12 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +5 6 2 18 21 6 30 35 10 44 52 15 57 67 20 68 81 24 84 99 29 97 115 34 +109 129 38 122 145 43 134 159 47 144 171 51 154 183 54 164 195 58 175 208 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 164 195 58 152 180 53 139 166 49 127 151 45 115 137 41 103 122 36 +88 104 31 68 81 24 51 61 18 31 37 11 13 16 5 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 131 156 46 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 80 96 28 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 19 23 7 +171 203 60 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 162 192 57 6 7 2 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 89 106 31 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +90 107 32 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 24 29 9 173 205 61 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 108 128 38 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 11 3 +19 22 7 28 34 10 39 46 14 49 59 17 59 70 21 68 81 24 71 84 25 82 98 29 +84 99 29 94 111 33 99 117 35 105 125 37 112 134 40 117 139 41 125 149 44 129 153 45 +138 164 48 141 167 50 141 167 50 141 167 50 148 175 52 153 181 54 153 181 54 153 181 54 +157 187 55 164 195 58 164 195 58 164 195 58 164 195 58 164 195 58 164 195 58 164 195 58 +163 193 57 153 181 54 153 181 54 153 181 54 153 181 54 153 181 54 153 181 54 151 179 53 +141 167 50 136 161 48 129 153 45 122 145 43 117 139 41 109 129 38 105 125 37 97 115 34 +94 111 33 82 98 29 80 96 28 71 84 25 61 72 21 49 59 17 37 43 13 25 30 9 +13 16 5 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +47 55 16 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 157 187 55 6 7 2 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 101 120 35 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 87 103 31 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 14 17 5 170 202 60 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +164 195 58 12 14 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 108 128 38 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 170 202 60 14 17 5 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +135 161 48 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 65 77 23 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 17 20 6 170 202 60 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 169 201 60 14 16 5 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 105 125 37 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 94 111 33 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 21 25 8 172 204 61 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 94 111 33 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 55 65 19 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 135 161 48 1 1 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 99 117 35 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 103 122 36 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 26 31 9 175 207 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 169 201 60 17 20 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 103 122 36 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 167 198 59 13 16 5 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 7 2 153 182 54 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 173 206 61 35 41 12 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 14 17 5 169 201 60 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 175 207 62 25 30 9 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 122 145 43 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 103 122 36 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 19 22 7 168 200 59 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 92 110 32 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 89 106 31 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 90 107 32 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 101 120 35 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 119 142 42 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 38 45 13 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 173 205 61 25 30 9 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 88 104 31 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 169 201 60 19 23 7 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 25 30 9 170 202 60 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 139 166 49 3 4 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 30 35 10 173 206 61 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 175 208 62 35 42 12 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 122 145 43 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 117 139 41 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 8 2 +157 187 55 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 109 129 38 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 1 2 0 133 157 47 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +169 201 60 26 31 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 127 151 45 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 120 143 42 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 35 41 12 175 208 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 47 55 16 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +65 77 23 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 175 207 62 37 43 13 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 77 92 27 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +75 89 26 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 54 64 19 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +175 207 62 31 37 11 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 119 142 42 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 147 175 52 3 4 1 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 1 0 135 161 48 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 144 171 51 3 4 1 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 26 31 9 170 202 60 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 164 195 58 +82 98 29 71 84 25 68 81 24 59 70 21 54 64 19 37 43 13 19 23 7 4 5 1 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 4 5 1 151 179 53 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +115 137 41 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 30 35 10 +175 207 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 78 93 27 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 30 35 10 172 204 61 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 86 102 30 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 1 2 0 19 23 7 44 52 15 66 78 23 +89 106 31 111 132 39 135 161 48 164 195 58 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +162 192 57 139 166 49 111 132 39 82 98 29 56 66 20 25 30 9 0 0 0 0 0 0 +0 0 0 0 0 0 80 96 28 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 174 207 61 +28 33 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +112 134 40 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 166 198 59 17 20 6 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 90 107 32 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 171 203 60 +28 34 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 1 28 34 10 +59 70 21 94 111 33 125 149 44 151 179 53 172 204 61 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 162 192 57 121 144 43 +78 93 27 49 59 17 166 198 59 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 109 129 38 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +19 23 7 169 201 60 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 117 139 41 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 6 7 2 151 179 53 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +136 161 48 1 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 10 12 4 44 52 15 75 89 26 108 128 38 139 166 49 170 202 60 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 168 199 59 18 21 6 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 88 104 31 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 57 67 20 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 41 48 14 174 207 61 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 76 90 27 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 26 31 9 66 78 23 106 126 37 +146 173 51 175 207 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 84 99 29 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 6 7 2 155 184 54 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 162 193 57 +14 17 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 92 110 32 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 171 203 60 37 43 13 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +7 8 2 41 49 15 77 92 27 117 139 41 162 192 57 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 153 182 54 6 7 2 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 61 72 21 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +115 137 41 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 3 4 1 139 166 49 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 155 184 54 14 16 5 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 3 3 1 35 42 12 82 98 29 129 153 45 +172 204 61 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 57 67 20 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 1 1 0 135 161 48 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 57 67 20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 30 35 10 169 201 60 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 125 149 44 1 2 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +3 3 1 41 48 14 86 102 30 131 156 46 170 202 60 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 170 202 60 146 173 51 127 151 45 112 134 40 +99 117 35 86 102 30 68 81 24 54 64 19 39 46 14 25 30 9 71 84 25 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 131 156 46 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 30 35 10 172 204 61 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 162 193 57 19 22 7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 66 78 23 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 87 103 31 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 30 35 10 78 93 27 125 149 44 +168 199 59 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 160 190 56 136 161 48 112 134 40 +89 106 31 65 77 23 41 49 15 17 20 6 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 24 29 9 166 198 59 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 171 203 60 28 33 10 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 89 106 31 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 133 157 47 2 2 1 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 109 129 38 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 175 207 62 49 59 17 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 12 14 4 59 70 21 108 128 38 157 187 55 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 167 198 59 +136 161 48 104 124 37 71 84 25 39 46 14 9 11 3 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 4 5 1 139 166 49 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 86 102 30 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 5 6 2 147 175 52 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 88 105 31 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 8 2 +144 171 51 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 166 197 58 32 38 11 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 1 38 45 13 87 103 31 +136 161 48 174 207 61 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 154 183 54 121 144 43 89 106 31 57 67 20 24 29 9 1 1 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 97 115 34 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 146 173 51 4 5 1 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 41 48 14 175 207 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 174 207 61 44 52 15 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +23 27 8 162 193 57 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 159 189 56 21 25 8 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 13 16 5 63 75 22 115 137 41 163 193 57 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 170 202 60 135 161 48 97 115 34 +55 65 19 17 20 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 51 61 18 175 208 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 174 207 61 38 45 13 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 101 120 35 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 159 189 56 16 19 6 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 44 52 15 173 205 61 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 148 175 52 +13 16 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 32 38 11 +84 99 29 135 161 48 174 207 61 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 159 189 56 119 142 42 78 93 27 39 46 14 4 5 1 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 19 23 7 162 192 57 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 99 117 35 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 8 10 3 151 179 53 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 135 161 48 4 5 1 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 71 84 25 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +136 161 48 7 8 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 6 7 2 51 61 18 104 124 37 155 184 54 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 152 180 53 106 126 37 63 75 22 +21 25 8 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 7 8 2 141 167 50 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +148 175 52 8 9 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 37 43 13 +173 205 61 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 108 128 38 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 92 110 32 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 124 147 44 4 5 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +19 22 7 71 84 25 124 147 44 170 202 60 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 159 189 56 112 134 40 67 79 24 21 25 8 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 1 0 117 139 41 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 172 204 61 +35 41 12 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +86 102 30 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 76 90 27 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 1 1 0 109 129 38 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 125 149 44 6 7 2 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 30 35 10 82 98 29 135 161 48 +175 208 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 167 198 59 129 153 45 82 98 29 +35 42 12 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +88 104 31 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 80 96 28 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +2 2 1 133 157 47 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 173 206 61 +47 55 16 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 3 4 1 125 149 44 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 127 151 45 6 7 2 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 6 7 2 51 61 18 105 125 37 157 187 55 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 171 203 60 127 151 45 80 96 28 35 41 12 1 2 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 57 67 20 +175 208 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 130 154 46 1 2 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 21 25 7 165 196 58 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +164 195 58 30 35 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 8 2 131 156 46 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 130 154 46 8 9 3 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 17 20 6 68 81 24 +121 144 43 169 201 60 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 153 182 54 103 122 36 +54 64 19 8 9 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 35 41 12 168 200 59 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 164 195 58 19 22 7 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 54 64 19 175 208 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 157 187 55 21 25 7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 8 10 3 135 161 48 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 134 159 47 9 11 3 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 33 39 11 86 102 30 139 166 49 175 207 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 171 203 60 127 151 45 78 93 27 28 33 10 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 24 29 9 159 189 56 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 175 207 62 51 61 18 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 90 107 32 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 148 175 52 13 16 5 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 11 3 +138 164 48 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 143 169 50 19 22 7 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 6 2 +49 59 17 103 122 36 155 184 54 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 153 182 54 +103 122 36 54 64 19 8 9 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 18 21 6 153 182 54 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 88 104 31 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 1 2 0 125 149 44 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 138 164 48 7 8 2 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +9 11 3 131 156 46 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 156 185 55 +31 37 11 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 19 23 7 68 81 24 119 142 42 168 199 59 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 173 205 61 130 154 46 78 93 27 28 33 10 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 13 16 5 146 173 51 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 124 147 44 1 2 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 12 14 4 153 182 54 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 125 149 44 6 7 2 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 6 7 2 125 149 44 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +166 197 58 47 55 16 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +10 11 3 54 64 19 101 120 35 148 175 52 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +164 195 58 114 135 40 61 72 21 11 13 4 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 21 21 21 60 60 60 84 84 84 110 110 110 129 129 129 154 154 154 +180 180 180 198 198 198 222 222 222 222 222 222 222 222 222 222 222 222 222 222 222 236 236 236 +236 236 236 222 222 222 208 208 208 190 190 190 169 169 169 124 124 124 42 42 42 0 0 0 +0 0 0 0 0 0 8 10 3 139 166 49 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 152 180 53 12 14 4 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 33 39 11 169 201 60 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 125 149 44 6 7 2 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 4 5 1 111 132 39 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 173 205 61 67 79 24 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 9 11 3 44 52 15 88 105 31 136 161 48 +173 206 61 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 152 180 53 99 117 35 44 52 15 +3 3 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 24 24 24 71 71 71 110 110 110 154 154 154 +194 194 194 234 234 234 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 234 234 234 161 161 161 88 88 88 34 34 34 0 0 0 0 0 0 0 0 0 +0 0 0 6 7 2 130 154 46 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 168 200 59 32 38 11 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 52 62 18 174 207 61 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 127 151 45 6 7 2 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 77 92 27 175 207 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 105 125 37 4 5 1 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 1 +30 35 10 65 77 23 100 119 35 141 167 50 174 207 61 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 175 207 62 141 167 50 88 105 31 35 42 12 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 6 6 +60 60 60 110 110 110 169 169 169 222 222 222 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 215 215 215 129 129 129 +53 53 53 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +7 8 2 127 151 45 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +175 207 62 55 65 19 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 92 27 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 125 149 44 +5 6 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 61 72 21 170 202 60 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 135 160 47 17 20 6 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 21 25 8 49 59 17 77 92 27 104 124 37 135 161 48 170 202 60 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 168 200 59 119 142 42 +67 79 24 14 17 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 10 10 10 71 71 71 139 139 139 198 198 198 249 249 249 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 222 222 222 139 139 139 48 48 48 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 11 3 +135 160 47 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +75 89 26 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +101 120 35 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +141 168 50 103 122 36 82 98 29 63 75 22 41 48 14 19 23 7 2 2 1 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 39 46 14 162 192 57 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 159 189 56 41 48 14 0 0 0 +0 0 0 0 0 0 7 8 2 28 34 10 47 55 16 66 78 23 86 102 30 112 134 40 +141 167 50 168 199 59 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 160 190 56 105 125 37 51 61 18 6 7 2 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 +53 53 53 119 119 119 187 187 187 246 246 246 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +238 238 238 161 161 161 66 66 66 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 12 14 4 139 166 49 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 99 117 35 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +2 2 1 122 145 43 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 175 207 62 160 190 56 +146 173 51 130 154 46 112 134 40 99 117 35 86 102 30 76 90 27 66 78 23 57 67 20 +47 55 16 37 43 13 28 34 10 23 27 8 23 27 8 23 27 8 12 14 4 35 41 12 +154 183 54 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 173 205 61 127 151 45 +146 173 51 164 195 58 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +153 181 54 97 115 34 41 49 15 1 2 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 17 17 17 88 88 88 165 165 165 238 238 238 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 242 242 242 161 161 161 74 74 74 +4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 16 19 6 144 171 51 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 120 143 42 1 2 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 8 9 3 136 161 48 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 143 169 50 88 104 31 32 38 11 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 34 34 34 114 114 114 190 190 190 252 252 250 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 252 252 252 183 183 183 88 88 88 10 10 10 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 21 25 8 149 178 53 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 135 161 48 7 8 2 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 10 12 4 141 167 50 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 175 207 62 141 167 50 88 105 31 26 31 9 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 48 48 48 129 129 129 +215 215 215 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +215 215 215 119 119 119 27 27 27 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 38 45 13 159 189 56 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 144 171 51 12 14 4 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 14 16 5 146 173 51 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 173 206 61 135 161 48 +77 92 27 17 20 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 42 42 42 129 129 129 215 215 215 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 238 238 238 154 154 154 60 60 60 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 58 69 20 170 202 60 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 149 178 53 16 19 6 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 16 19 6 149 178 53 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 169 201 60 124 147 44 65 77 23 10 12 4 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +42 42 42 133 133 133 219 219 219 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 249 249 249 176 176 176 80 80 80 6 6 6 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 1 0 82 98 29 175 207 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 152 180 53 18 21 6 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 21 25 8 155 184 54 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +151 179 53 100 119 35 49 59 17 5 6 2 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 27 27 27 110 110 110 208 208 208 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +215 215 215 119 119 119 21 21 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 7 2 +114 135 40 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 155 184 54 21 25 8 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 21 25 8 152 180 53 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 172 204 61 129 153 45 78 93 27 26 31 9 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 17 17 17 93 93 93 187 187 187 254 254 254 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 222 222 222 143 143 143 48 48 48 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 23 27 8 139 166 49 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +151 179 53 21 25 8 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 17 20 6 +144 171 51 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 162 192 57 111 132 39 59 70 21 10 12 4 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 8 8 8 +84 84 84 180 180 180 249 249 249 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 238 238 238 161 161 161 66 66 66 1 1 1 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 55 65 19 164 195 58 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 148 175 52 +19 22 7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +14 17 5 143 169 50 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 157 187 55 114 135 40 75 89 26 +32 38 11 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 6 6 6 77 77 77 161 161 161 242 242 242 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 246 246 246 +180 180 180 84 84 84 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 4 5 1 100 119 35 175 208 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 141 168 50 14 16 5 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 11 13 4 136 161 48 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +175 207 62 144 171 51 103 122 36 63 75 22 21 25 7 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 2 2 2 66 66 66 157 157 157 238 238 238 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 252 252 250 180 180 180 93 93 93 13 13 13 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 23 27 8 139 166 49 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 135 161 48 10 12 4 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 8 9 3 121 144 43 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 168 199 59 103 122 36 86 102 30 +127 151 45 168 200 59 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 175 207 62 151 179 53 119 142 42 87 103 31 51 61 18 +11 13 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 42 42 42 +129 129 129 222 222 222 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 208 208 208 110 110 110 24 24 24 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 67 79 24 165 196 58 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 120 143 42 7 8 2 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 2 2 1 100 119 35 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 115 137 41 +13 16 5 3 4 1 39 46 14 75 89 26 103 122 36 129 153 45 157 187 55 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 166 197 58 144 171 51 118 140 42 +92 110 32 66 78 23 38 45 13 8 10 3 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 42 42 42 129 129 129 219 219 219 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 254 254 254 198 198 198 +114 114 114 34 34 34 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 19 23 7 +125 149 44 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 99 117 35 1 2 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 92 27 174 207 61 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +159 189 56 56 66 20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 11 3 +37 43 13 54 64 19 66 78 23 77 92 27 90 107 32 101 120 35 112 134 40 120 143 42 +117 139 41 117 139 41 117 139 41 114 135 40 105 125 37 105 125 37 103 122 36 90 107 32 +77 92 27 63 75 22 49 59 17 28 34 10 9 11 3 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 27 27 27 110 110 110 198 198 198 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 252 252 252 198 198 198 110 110 110 27 27 27 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 71 84 25 166 198 59 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 174 207 61 75 89 26 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 55 65 19 169 201 60 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 121 144 43 19 23 7 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 21 21 21 105 106 101 +190 190 190 252 252 252 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +246 246 246 183 183 183 99 99 99 21 21 21 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 21 25 8 129 153 45 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +168 200 59 54 64 19 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 32 38 11 +153 181 54 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 167 198 59 77 92 27 3 3 1 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 13 13 13 88 88 88 180 180 180 249 249 249 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 231 231 231 154 154 154 80 80 80 +10 10 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 6 7 2 86 102 30 169 201 60 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 152 180 53 +32 38 11 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +10 11 3 121 144 43 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 149 178 53 51 61 18 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +10 10 10 77 77 77 161 161 161 242 242 242 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 215 215 215 133 133 133 60 60 60 1 1 1 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 54 64 19 153 182 54 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 125 149 44 12 14 4 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 1 2 0 89 106 31 175 207 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 121 144 43 +25 30 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 17 17 17 99 99 99 180 180 180 +249 249 249 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 222 222 222 157 157 157 +88 88 88 21 21 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 32 38 11 +131 156 46 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 175 207 62 88 104 31 1 2 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 52 62 18 164 195 58 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +173 205 61 103 122 36 17 20 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 34 34 34 110 110 110 187 187 187 249 249 249 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 234 234 234 169 169 169 99 99 99 34 34 34 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 19 23 7 105 125 37 174 207 61 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 164 195 58 51 61 18 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 19 23 7 131 156 46 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 169 201 60 94 111 33 12 14 4 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 53 53 53 +133 133 133 208 208 208 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 222 222 222 161 161 161 +110 110 110 48 48 48 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 19 23 7 103 122 36 172 204 61 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 130 154 46 19 22 7 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 77 92 27 172 204 61 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 168 199 59 100 119 35 18 21 6 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 17 17 17 84 84 84 154 154 154 231 231 231 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 246 246 246 194 194 194 139 139 139 80 80 80 24 24 24 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 19 23 7 100 119 35 170 202 60 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +173 206 61 88 105 31 1 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 35 42 12 +149 178 53 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 170 202 60 101 120 35 +21 25 7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 +60 60 60 129 129 129 198 198 198 252 252 252 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 234 234 234 187 187 187 143 143 143 99 99 99 +53 53 53 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 26 31 9 +104 124 37 172 204 61 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 148 175 52 +35 41 12 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +8 9 3 100 119 35 175 207 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +173 206 61 117 139 41 41 48 14 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 3 3 3 48 48 48 110 110 110 180 180 180 242 242 242 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 231 231 231 198 198 198 +161 161 161 114 114 114 71 71 71 24 24 24 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 1 2 0 51 61 18 125 149 44 175 208 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 175 207 62 99 117 35 7 8 2 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 39 46 14 146 173 51 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 141 167 50 66 78 23 7 8 2 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 13 13 13 +71 71 71 129 129 129 187 187 187 242 242 242 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 241 241 241 222 222 222 198 198 198 +169 169 169 139 139 139 105 106 101 74 74 74 42 42 42 8 8 8 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 10 12 4 77 92 27 151 179 53 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 146 173 51 38 45 13 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 4 5 1 87 103 31 171 203 60 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 166 197 58 104 124 37 37 43 13 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 6 6 71 71 71 114 114 114 +119 119 119 124 124 124 119 119 119 119 119 119 119 119 119 119 119 119 105 106 101 88 88 88 +71 71 71 53 53 53 37 37 37 21 21 21 3 3 3 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 2 0 +44 52 15 108 128 38 167 198 59 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 171 203 60 86 102 30 3 4 1 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 28 34 10 133 157 47 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +144 171 51 84 99 29 23 27 8 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 32 38 11 95 113 33 156 185 55 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 131 156 46 28 33 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 59 70 21 +154 183 54 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 175 208 62 138 164 48 77 92 27 23 27 8 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 28 34 10 82 98 29 144 171 51 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 153 182 54 +58 69 20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +6 7 2 86 102 30 168 200 59 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 146 173 51 92 110 32 +39 46 14 2 2 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 8 2 51 61 18 +103 122 36 154 183 54 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 168 199 59 84 99 29 6 7 2 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 19 22 7 111 132 39 174 207 61 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 165 196 58 121 144 43 75 89 26 28 34 10 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 3 4 1 37 43 13 77 92 27 125 149 44 170 202 60 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 174 207 61 109 129 38 18 21 6 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 28 34 10 117 139 41 175 207 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 162 193 57 124 147 44 86 102 30 +47 55 16 10 11 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 17 20 6 55 65 19 +95 113 33 134 159 47 170 202 60 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 175 207 62 115 137 41 28 33 10 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 32 38 11 121 144 43 +175 208 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 175 208 62 153 181 54 121 144 43 89 106 31 58 69 20 31 37 11 6 7 2 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +14 16 5 44 52 15 71 84 25 99 117 35 127 151 45 155 184 54 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 175 208 62 +121 144 43 31 37 11 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +37 43 13 120 143 42 175 207 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +157 187 55 133 157 47 111 132 39 92 110 32 76 90 27 58 69 20 41 48 14 28 33 10 +17 20 6 7 8 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 4 1 12 14 4 18 21 6 +35 41 12 51 61 18 67 79 24 86 102 30 101 120 35 119 142 42 135 161 48 163 193 57 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 175 207 62 119 142 42 35 42 12 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 25 30 9 104 124 37 170 202 60 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 173 205 61 164 195 58 160 190 56 153 181 54 153 181 54 152 180 53 +153 181 54 159 189 56 164 195 58 169 201 60 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 169 201 60 103 122 36 25 30 9 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 14 16 5 82 98 29 159 189 56 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 162 192 57 94 111 33 17 20 6 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 6 2 59 70 21 +129 153 45 175 208 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 141 167 50 +71 84 25 7 8 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 25 30 9 88 105 31 156 185 55 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 159 189 56 100 119 35 30 35 10 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 3 4 1 55 65 19 115 137 41 168 200 59 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 168 199 59 114 135 40 55 65 19 3 4 1 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 7 2 54 64 19 +111 132 39 168 199 59 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 170 202 60 124 147 44 +65 77 23 8 10 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 9 11 3 59 70 21 111 132 39 159 189 56 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 159 189 56 109 129 38 59 70 21 8 10 3 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 30 35 10 82 98 29 129 153 45 +172 204 61 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 174 207 61 +141 167 50 94 111 33 41 49 15 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +8 9 3 41 49 15 82 98 29 124 147 44 164 195 58 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 168 200 59 135 161 48 94 111 33 54 64 19 11 13 4 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 3 3 1 35 41 12 75 89 26 106 126 37 +138 164 48 168 199 59 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 168 199 59 138 164 48 +106 126 37 75 89 26 35 41 12 2 2 1 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 1 2 0 24 29 9 57 67 20 86 102 30 111 132 39 134 159 47 157 187 55 +175 207 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 175 207 62 +156 185 55 134 159 47 111 132 39 86 102 30 56 66 20 24 29 9 1 1 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +4 5 1 25 30 9 49 59 17 66 78 23 78 93 27 92 110 32 108 128 38 120 143 42 +134 159 47 146 173 51 153 181 54 153 181 54 163 193 57 164 195 58 168 199 59 176 209 62 +176 209 62 168 199 59 164 195 58 163 193 57 153 181 54 153 181 54 146 173 51 133 157 47 +120 143 42 108 128 38 92 110 32 78 93 27 66 78 23 49 59 17 25 30 9 4 5 1 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +P3 +63 80 +255 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 1 0 +0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 +0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 +10 15 3 2 3 1 12 18 4 42 61 14 19 27 6 11 16 4 +38 55 13 10 15 3 3 4 1 10 15 3 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 3 1 +12 18 4 1 1 0 23 34 8 31 45 11 10 15 3 32 47 11 +34 49 12 3 4 1 3 4 1 3 4 1 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 10 15 3 29 42 10 26 37 9 12 18 4 +55 80 19 81 118 28 55 80 19 92 132 31 106 153 36 69 100 23 +100 144 34 80 116 27 42 61 14 81 118 28 23 34 8 27 40 9 +15 21 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 1 1 0 29 42 10 15 21 5 50 72 17 +74 107 25 45 64 15 102 148 35 80 116 27 84 121 28 111 160 38 +69 100 23 65 94 22 81 118 28 29 42 10 17 25 6 29 42 10 +23 34 8 2 3 1 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 4 1 +15 21 5 15 21 5 34 49 12 101 146 34 111 161 38 97 141 33 +97 141 33 119 172 41 117 170 40 116 167 40 118 170 40 118 171 40 +117 169 40 118 170 40 111 160 38 118 170 40 96 138 32 89 128 30 +81 118 28 11 16 4 10 15 3 1 1 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +3 4 1 3 4 1 34 49 12 101 146 34 79 115 27 111 160 38 +114 165 39 113 163 39 118 170 40 117 169 40 118 171 40 117 169 40 +116 167 40 119 172 41 113 163 39 92 132 31 105 151 36 113 163 39 +75 109 26 19 27 6 16 23 5 11 16 4 0 1 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 15 3 +80 116 27 106 153 36 105 151 36 114 165 39 118 170 40 118 171 40 +118 171 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 +117 169 40 117 169 40 117 170 40 117 169 40 118 170 40 118 170 40 +117 170 40 75 109 26 75 109 26 34 49 12 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 4 1 +64 92 22 65 94 22 100 144 34 118 171 40 118 170 40 117 169 40 +117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 +117 169 40 117 169 40 117 169 40 118 171 41 118 170 40 117 169 40 +109 158 37 105 151 36 104 150 35 47 69 16 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +42 61 14 115 167 39 118 170 40 117 169 40 117 169 40 117 169 40 +117 170 40 117 170 40 117 169 40 117 169 40 117 169 40 117 169 40 +117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 +117 169 40 117 169 40 118 170 40 96 138 32 17 25 6 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 47 69 16 +114 165 39 117 168 40 117 170 40 117 169 40 117 169 40 117 169 40 +117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 +117 169 40 117 169 40 118 170 40 117 169 40 117 169 40 117 169 40 +117 170 40 119 172 41 96 138 32 12 18 4 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 15 3 +32 47 11 105 151 36 118 170 40 117 169 40 117 169 40 116 168 40 +109 157 37 111 160 38 117 169 40 118 171 40 117 169 40 117 169 40 +117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 +117 169 40 117 169 40 117 169 40 118 171 40 69 100 23 2 3 1 +0 0 0 0 0 0 0 0 0 0 0 0 19 27 6 101 146 34 +118 171 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 +117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 170 40 +118 171 40 115 166 39 107 154 36 111 161 38 117 169 40 117 169 40 +117 169 40 118 171 40 75 109 26 19 27 6 2 3 1 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 16 23 5 +89 128 30 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 +111 160 38 92 132 31 79 115 27 96 138 32 115 166 39 119 171 41 +117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 +117 169 40 117 169 40 117 169 40 118 170 40 109 157 37 26 37 9 +0 0 0 0 0 0 0 0 0 0 0 0 64 92 22 118 171 40 +117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 +117 169 40 117 169 40 117 169 40 118 170 40 118 171 40 109 157 37 +89 128 30 81 118 28 100 144 34 115 166 39 117 169 40 117 169 40 +117 169 40 117 170 40 113 163 39 60 86 20 1 1 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +27 40 9 96 138 32 118 170 40 117 169 40 117 169 40 117 169 40 +117 170 40 117 169 40 101 146 34 67 96 23 55 80 19 84 121 28 +113 163 39 119 171 41 117 169 40 117 169 40 117 169 40 117 169 40 +117 169 40 117 169 40 117 169 40 117 169 40 119 171 41 65 94 22 +0 0 0 0 0 0 0 0 0 15 21 5 101 146 34 118 171 40 +117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 +117 169 40 118 170 40 118 171 40 104 150 35 69 100 23 53 76 18 +81 118 28 111 160 38 118 170 40 117 169 40 117 169 40 117 169 40 +117 169 40 114 165 39 69 100 23 10 15 3 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 +31 45 11 77 111 26 117 169 40 117 169 40 117 169 40 117 169 40 +117 169 40 117 169 40 118 170 40 116 168 40 92 132 31 47 69 16 +38 55 13 81 118 28 113 163 39 119 171 41 117 169 40 117 169 40 +117 169 40 117 169 40 117 169 40 117 169 40 118 171 41 92 132 31 +10 15 3 0 0 0 0 0 0 36 52 12 115 166 39 117 169 40 +117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 118 170 40 +118 171 40 102 148 35 64 92 22 34 49 12 65 94 22 106 153 36 +118 171 40 117 170 40 117 169 40 117 169 40 117 169 40 117 169 40 +118 170 40 107 154 36 55 80 19 15 21 5 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +29 42 10 101 146 34 118 171 40 117 169 40 117 169 40 117 169 40 +117 169 40 117 169 40 117 169 40 117 169 40 118 171 40 113 163 39 +75 109 26 27 40 9 36 52 12 89 128 30 116 167 40 118 171 40 +117 169 40 117 169 40 117 169 40 117 169 40 118 170 40 104 150 35 +16 23 5 0 0 0 0 0 0 53 76 18 118 171 40 117 169 40 +117 169 40 117 169 40 117 169 40 117 169 40 119 171 41 109 157 37 +67 96 23 23 34 8 42 61 14 96 138 32 118 170 40 118 170 40 +117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 +117 169 40 117 169 40 74 107 25 10 15 3 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 31 45 11 101 146 34 118 170 40 117 169 40 117 169 40 +117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 +119 171 41 102 148 35 47 69 16 14 20 5 50 72 17 102 148 35 +118 171 40 117 169 40 117 169 40 117 169 40 118 170 40 102 148 35 +15 21 5 0 0 0 0 0 0 50 72 17 118 170 40 117 169 40 +117 169 40 117 169 40 118 170 40 116 167 40 84 121 28 27 40 9 +19 27 6 74 107 25 114 165 39 118 171 40 117 169 40 117 169 40 +117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 +117 169 40 75 109 26 10 15 4 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 38 55 13 102 148 35 118 171 40 117 169 40 117 169 40 +117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 +117 169 40 118 170 40 115 167 39 77 111 26 17 25 6 19 27 6 +77 111 26 115 166 39 118 170 40 117 169 40 119 172 41 81 118 28 +3 4 1 0 0 0 0 0 0 27 40 9 111 160 38 118 170 40 +117 169 40 118 171 40 105 151 36 50 72 17 10 15 3 38 55 13 +100 144 34 118 171 40 117 169 40 117 169 40 117 169 40 117 169 40 +117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 +117 169 40 79 115 27 15 21 5 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 10 15 3 64 92 22 111 160 38 117 169 40 117 169 40 +117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 +117 169 40 117 169 40 117 169 40 118 171 40 96 138 32 32 47 11 +3 4 1 50 72 17 107 154 36 120 173 41 105 151 36 31 45 11 +0 0 0 0 0 0 0 0 0 3 4 1 65 94 22 117 169 40 +118 170 40 89 128 30 26 37 9 3 4 1 60 86 20 111 161 38 +118 171 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 +117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 +97 141 33 36 52 12 1 1 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 14 20 5 75 109 26 117 168 40 117 169 40 +117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 +117 169 40 117 169 40 117 169 40 117 169 40 118 171 40 107 154 36 +45 64 15 2 3 1 31 45 11 75 109 26 32 47 11 0 1 0 +0 0 0 0 0 0 0 0 0 0 0 0 10 15 3 55 80 19 +65 94 22 11 16 4 11 16 4 75 109 26 116 168 40 118 170 40 +117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 +117 169 40 117 169 40 117 169 40 117 169 40 118 170 40 107 154 36 +47 69 16 3 4 1 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 12 18 4 69 100 23 111 161 38 118 171 40 +117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 +117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 118 170 40 +111 160 38 50 72 17 2 3 1 2 3 1 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 +1 1 0 12 18 4 81 118 28 118 170 40 117 169 40 117 169 40 +117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 +117 169 40 117 169 40 117 169 40 117 170 40 118 171 40 101 146 34 +42 61 14 2 3 1 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 3 4 1 36 52 12 89 128 30 +117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 +117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 +118 171 41 101 146 34 14 20 5 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 47 69 16 118 170 40 117 169 40 117 169 40 117 169 40 +117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 +117 169 40 117 169 40 117 170 40 111 160 38 69 100 23 19 27 6 +0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 11 16 4 69 100 23 +115 167 39 119 172 41 117 169 40 117 169 40 117 169 40 117 169 40 +117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 +119 172 41 75 109 26 3 4 1 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 23 34 8 106 153 36 118 170 40 117 169 40 117 169 40 +117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 +117 169 40 118 170 40 119 172 41 105 151 36 42 61 14 2 3 1 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 15 21 5 +45 64 15 80 116 27 114 165 39 118 170 40 117 169 40 117 169 40 +117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 119 172 41 +97 141 33 20 30 7 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 1 1 0 53 76 18 114 165 39 118 171 40 117 169 40 +117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 +118 171 40 104 150 35 64 92 22 31 45 11 10 15 3 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 36 52 12 97 141 33 109 158 37 113 163 39 116 168 40 +117 169 40 117 170 40 118 170 40 119 172 41 115 167 39 84 121 28 +23 34 8 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 3 4 1 50 72 17 102 148 35 118 171 40 +119 171 41 118 170 40 117 169 40 117 169 40 115 166 39 111 161 38 +109 157 37 79 115 27 12 18 4 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 3 4 1 15 21 5 23 34 8 45 64 15 106 153 36 +116 167 40 111 160 38 101 146 34 79 115 27 42 61 14 10 15 3 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 1 1 0 20 30 7 60 86 20 +89 128 30 106 153 36 113 163 39 117 169 40 84 121 28 29 42 10 +19 27 6 10 15 3 2 3 1 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 16 23 5 38 55 13 +36 52 12 26 37 9 12 18 4 2 3 1 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 1 0 0 19 2 7 52 5 18 +78 7 27 88 8 31 81 7 29 56 5 19 25 2 9 3 0 1 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +3 4 1 19 27 6 31 45 11 38 55 13 32 47 11 3 4 1 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 0 1 +9 0 3 12 1 4 9 0 3 4 0 1 0 0 0 0 0 0 +0 0 0 0 0 0 28 3 10 99 9 35 156 14 55 182 16 64 +189 17 66 190 17 67 189 17 66 184 17 65 166 15 58 118 13 41 +45 4 16 3 0 1 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 11 1 4 52 5 18 101 9 35 134 12 47 +151 14 53 154 14 54 151 14 53 113 10 40 11 1 4 0 0 0 +3 0 1 67 6 24 159 14 56 190 17 67 190 17 67 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 190 17 67 191 17 67 +174 16 61 101 9 35 14 1 5 0 0 0 35 3 12 108 10 38 +122 11 43 122 11 43 112 10 39 87 8 30 50 5 17 13 1 5 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +3 0 1 56 5 19 141 13 49 182 16 64 191 17 67 191 17 67 +190 17 67 190 17 67 191 17 67 113 10 40 3 0 1 1 0 0 +79 7 28 180 16 63 190 17 67 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +189 17 66 188 17 66 122 11 43 11 1 4 41 4 14 176 16 62 +191 17 67 191 17 67 191 17 67 190 17 67 181 16 63 146 13 51 +75 7 26 10 1 4 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 1 2 +90 8 32 178 16 62 191 17 67 188 17 66 188 17 66 188 17 66 +188 17 66 190 17 67 141 13 49 22 2 8 0 0 0 41 4 14 +173 16 61 190 17 67 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 88 8 31 1 0 0 89 8 31 +185 17 65 189 17 66 188 17 66 188 17 66 189 17 66 191 17 67 +186 17 65 124 11 43 25 2 9 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 2 0 1 89 8 31 +184 17 65 189 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +190 17 67 151 14 53 34 3 12 0 0 0 0 0 0 79 7 28 +190 17 67 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 191 17 67 146 13 51 9 1 3 7 1 2 +108 10 38 187 17 66 189 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 190 17 67 141 13 49 22 2 8 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 52 5 18 176 16 62 +189 17 66 188 17 66 188 17 66 188 17 66 188 17 66 190 17 67 +151 14 53 38 3 13 0 0 0 0 0 0 0 0 0 50 5 17 +180 16 63 189 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 191 17 67 141 13 49 7 1 3 0 0 0 +11 1 4 112 10 39 187 17 66 189 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 190 17 67 113 10 40 5 0 2 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 7 1 3 132 12 46 191 17 67 +188 17 66 188 17 66 188 17 66 188 17 66 190 17 67 146 13 51 +35 3 12 0 0 0 0 0 0 0 0 0 0 0 0 5 0 2 +101 9 35 185 17 65 190 17 67 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 190 17 67 180 16 63 67 6 24 0 0 0 0 0 0 +0 0 0 11 1 4 108 10 38 186 17 65 189 17 66 188 17 66 +188 17 66 188 17 66 189 17 66 180 16 63 56 5 19 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 44 4 15 177 16 62 189 17 66 +188 17 66 188 17 66 189 17 66 189 17 66 134 12 47 28 3 10 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +8 1 3 79 7 28 159 14 56 188 17 66 191 17 67 190 17 67 +189 17 66 189 17 66 189 17 66 189 17 66 190 17 67 191 17 67 +188 17 66 158 14 55 72 7 25 4 0 1 0 0 0 0 0 0 +0 0 0 0 0 0 8 1 3 95 9 33 182 16 64 189 17 67 +188 17 66 188 17 66 188 17 66 191 17 67 122 11 43 3 0 1 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 88 8 31 190 17 67 188 17 66 +188 17 66 189 17 66 185 17 65 113 10 40 18 2 6 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 1 0 0 24 2 8 77 7 27 124 11 43 154 14 54 +168 15 59 173 16 61 173 16 61 168 15 59 154 14 54 124 11 43 +77 7 27 22 2 8 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 5 0 2 77 7 27 173 16 61 +190 17 67 188 17 66 188 17 66 190 17 67 164 15 57 23 2 8 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 1 0 0 118 13 41 191 17 67 188 17 66 +190 17 67 174 16 61 87 8 30 8 1 3 0 0 0 0 0 0 +0 0 0 0 0 0 10 1 4 29 3 10 40 4 14 36 3 13 +18 2 6 2 0 1 0 0 0 0 0 0 3 0 1 14 1 5 +26 2 9 33 3 11 32 3 11 25 2 9 13 1 5 3 0 1 +0 0 0 14 1 5 56 5 19 95 9 33 109 10 38 101 9 35 +77 7 27 35 3 12 5 0 2 0 0 0 1 0 0 56 5 19 +156 14 55 190 17 67 188 17 66 188 17 66 182 16 64 50 5 17 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 5 0 2 134 12 47 191 17 67 189 17 66 +151 14 53 52 5 18 2 0 1 0 0 0 0 0 0 1 0 0 +28 3 10 90 8 32 146 13 51 170 15 60 178 16 62 174 16 61 +158 14 55 112 10 39 40 4 14 1 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 0 1 +56 5 19 146 13 51 183 17 64 191 17 67 191 17 67 191 17 67 +188 17 66 173 16 61 122 11 43 41 4 14 1 0 0 0 0 0 +30 3 10 124 11 43 185 17 65 190 17 67 187 17 66 67 6 24 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 6 1 2 134 12 47 168 15 59 99 9 35 +21 2 7 0 0 0 0 0 0 0 0 0 6 1 2 77 7 27 +162 15 57 190 17 67 191 17 67 189 17 66 189 17 66 189 17 66 +190 17 67 191 17 67 169 15 59 75 7 26 3 0 1 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 2 0 1 79 7 28 +178 16 62 191 17 67 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 189 17 66 191 17 67 170 15 60 79 7 28 5 0 2 +0 0 0 10 1 3 78 7 27 159 14 56 188 17 66 75 7 26 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 1 0 0 35 3 12 29 3 10 2 0 1 +0 0 0 0 0 0 0 0 0 9 1 3 101 9 35 183 17 64 +190 17 67 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 190 17 67 178 16 63 67 6 23 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 52 5 18 174 16 61 +190 17 67 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 190 17 67 182 16 64 89 8 31 +4 0 1 0 0 0 0 0 0 25 2 9 73 7 26 31 3 11 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 4 0 1 98 9 34 187 17 66 189 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 190 17 67 158 14 55 25 2 9 +0 0 0 0 0 0 0 0 0 8 1 3 134 12 47 191 17 67 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 189 17 66 180 16 63 +68 6 24 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 6 1 2 19 2 7 3 0 1 0 0 0 0 0 0 +0 0 0 0 0 0 65 6 23 180 16 63 189 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 189 17 66 83 8 29 +0 0 0 0 0 0 0 0 0 41 4 14 177 16 62 189 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 190 17 67 +159 14 56 28 3 10 0 0 0 0 0 0 0 0 0 23 2 8 +41 4 14 5 0 2 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +23 2 8 113 10 40 159 14 56 65 6 23 0 0 0 0 0 0 +0 0 0 16 1 6 146 13 51 191 17 67 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 191 17 67 132 12 46 +5 0 2 0 0 0 0 0 0 77 7 27 189 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +190 17 67 98 9 34 0 0 0 0 0 0 12 1 4 134 12 47 +178 16 63 108 10 38 16 1 6 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 30 3 10 +141 13 49 190 17 67 191 17 67 134 12 47 6 1 2 0 0 0 +0 0 0 68 6 24 186 17 65 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 190 17 67 156 14 55 +14 1 5 0 0 0 0 0 0 98 9 34 191 17 67 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +190 17 67 156 14 55 19 2 7 0 0 0 47 4 16 181 16 63 +190 17 67 189 17 66 126 14 44 17 2 6 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 16 1 6 134 12 47 +191 17 67 188 17 66 190 17 67 162 15 57 19 2 7 0 0 0 +3 0 1 123 11 43 191 17 67 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 190 17 67 163 15 57 +20 2 7 0 0 0 0 0 0 101 9 35 191 17 67 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 182 16 64 52 5 18 0 0 0 73 7 26 188 17 66 +188 17 66 188 17 66 189 17 66 109 10 38 5 0 2 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 95 9 33 189 17 66 +188 17 66 188 17 66 189 17 66 171 15 60 29 3 10 0 0 0 +16 1 6 156 14 55 190 17 67 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 190 17 67 158 14 55 +17 2 6 0 0 0 0 0 0 85 8 30 190 17 67 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 189 17 66 81 7 29 0 0 0 85 8 30 190 17 67 +188 17 66 188 17 66 189 17 66 180 16 63 56 5 19 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 25 2 9 162 15 57 190 17 67 +188 17 66 188 17 66 189 17 66 173 16 61 31 3 11 0 0 0 +30 3 10 171 15 60 189 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 191 17 67 141 13 49 +7 1 2 0 0 0 0 0 0 56 5 19 183 17 64 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 191 17 67 98 9 34 0 0 0 88 8 31 190 17 67 +188 17 66 188 17 66 188 17 66 191 17 67 124 11 43 5 0 2 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 68 6 24 187 17 66 188 17 66 +188 17 66 188 17 66 189 17 66 170 15 60 28 3 10 0 0 0 +34 3 12 174 16 61 189 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 191 17 67 101 9 35 +0 0 0 0 0 0 0 0 0 21 2 7 159 14 56 190 17 67 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 191 17 67 98 9 34 0 0 0 81 7 29 189 17 66 +188 17 66 188 17 66 188 17 66 189 17 66 168 15 59 28 3 10 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 109 10 38 191 17 67 188 17 66 +188 17 66 188 17 66 190 17 67 163 15 57 21 2 7 0 0 0 +26 2 9 168 15 59 189 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 189 17 66 180 16 63 47 4 16 +0 0 0 0 0 0 0 0 0 0 0 0 108 10 38 190 17 67 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 189 17 66 78 7 27 0 0 0 68 6 24 187 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 183 17 64 56 5 19 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 3 0 1 131 12 46 191 17 67 188 17 66 +188 17 66 188 17 66 190 17 67 151 14 53 12 1 4 0 0 0 +11 1 4 146 13 51 190 17 67 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 191 17 67 126 14 44 7 1 2 +0 0 0 0 0 0 0 0 0 0 0 0 32 3 11 164 15 58 +190 17 67 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +189 17 66 178 16 62 44 4 15 0 0 0 50 5 17 182 16 64 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 72 7 25 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 5 0 2 134 12 47 191 17 67 188 17 66 +188 17 66 188 17 66 191 17 67 131 12 46 3 0 1 0 0 0 +0 0 0 101 9 35 190 17 67 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 190 17 67 170 15 60 44 4 15 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 7 27 +183 17 64 189 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +191 17 67 134 12 47 9 1 3 0 0 0 31 3 11 171 15 60 +189 17 66 188 17 66 188 17 66 188 17 66 188 17 66 72 7 25 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 2 0 1 124 11 43 191 17 67 188 17 66 +188 17 66 188 17 66 191 17 67 101 9 35 0 0 0 0 0 0 +0 0 0 35 3 12 168 15 59 190 17 67 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 189 17 66 182 16 64 77 7 27 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 1 2 +99 9 35 185 17 65 189 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 189 17 66 +177 16 62 56 5 19 0 0 0 0 0 0 13 1 5 151 14 53 +190 17 67 188 17 66 188 17 66 188 17 66 185 17 65 56 5 19 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 99 9 35 191 17 67 188 17 66 +188 17 66 188 17 66 186 17 65 65 6 23 0 0 0 0 0 0 +0 0 0 0 0 0 79 7 28 182 16 64 190 17 67 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +191 17 67 177 16 62 83 8 29 4 0 1 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +8 1 3 89 8 31 175 16 62 191 17 67 189 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 190 17 67 181 16 63 +85 8 30 3 0 1 0 0 0 0 0 0 1 0 0 118 13 41 +191 17 67 188 17 66 188 17 66 189 17 66 173 16 61 34 3 12 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 56 5 19 183 17 64 188 17 66 +188 17 66 189 17 66 169 15 59 30 3 10 0 0 0 0 0 0 +0 0 0 0 0 0 5 0 2 83 8 29 173 16 61 191 17 67 +190 17 67 189 17 66 189 17 66 190 17 67 191 17 67 187 17 66 +151 14 53 56 5 19 3 0 1 0 0 0 16 1 6 50 5 17 +79 7 28 95 9 33 95 9 33 75 7 26 41 4 14 10 1 4 +0 0 0 2 0 1 50 5 17 132 12 46 178 16 62 190 17 67 +191 17 67 191 17 67 191 17 67 186 17 65 154 14 54 68 6 24 +4 0 1 0 0 0 0 0 0 0 0 0 0 0 0 72 7 25 +187 17 66 188 17 66 188 17 66 191 17 67 141 13 49 9 1 3 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 14 1 5 151 14 53 190 17 67 +188 17 66 191 17 67 131 12 46 5 0 2 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 2 0 1 44 4 15 113 10 40 +156 14 55 173 16 61 174 16 61 164 15 58 134 12 47 77 7 27 +18 2 6 0 0 0 16 1 6 85 8 30 151 14 53 182 16 64 +189 17 66 191 17 67 190 17 67 188 17 66 177 16 62 141 13 49 +68 6 24 8 1 3 0 0 0 8 1 3 44 4 15 88 8 31 +113 10 40 122 11 43 108 10 38 67 6 24 20 2 7 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 28 3 10 +166 15 58 190 17 67 188 17 66 187 17 66 79 7 28 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 73 7 26 185 17 65 +189 17 66 184 17 65 65 6 23 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 1 +17 2 6 32 3 11 34 3 12 22 2 8 6 1 2 0 0 0 +0 0 0 38 3 13 141 13 49 188 17 66 190 17 67 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 189 17 66 191 17 67 +184 17 65 122 11 43 21 2 7 0 0 0 0 0 0 0 0 0 +0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 +108 10 38 191 17 67 191 17 67 141 13 49 16 1 6 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 8 1 3 112 10 39 +186 17 65 124 11 43 10 1 4 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +36 3 13 156 14 55 191 17 67 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +189 17 66 190 17 67 134 12 47 18 2 6 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 7 1 2 41 4 14 75 7 26 66 5 23 19 2 7 +26 2 9 144 13 50 154 14 54 40 4 14 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 13 1 5 +56 5 19 19 2 7 0 0 0 7 1 2 29 3 10 35 3 12 +19 2 7 2 0 1 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 13 1 5 +134 12 47 191 17 67 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 189 17 67 108 10 38 3 0 1 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 +40 4 14 124 11 43 177 16 62 188 17 66 187 17 66 144 13 50 +24 2 8 17 2 6 22 2 8 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 19 2 7 122 11 43 171 15 60 175 16 62 +159 14 56 112 10 39 40 4 14 2 0 1 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 72 7 25 +186 17 65 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 189 17 66 174 16 61 41 4 14 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 3 0 1 72 7 25 +168 15 59 191 17 67 189 17 66 188 17 66 188 17 66 190 17 67 +95 9 33 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 95 9 33 191 17 67 189 17 66 189 17 66 +190 17 67 191 17 67 171 15 60 90 8 32 12 1 4 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 5 0 2 132 12 46 +191 17 67 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 190 17 67 98 9 34 0 0 0 +0 0 0 0 0 0 0 0 0 5 0 2 88 8 31 180 16 63 +190 17 67 188 17 66 188 17 66 188 17 66 188 17 66 191 17 67 +146 13 51 11 1 4 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 9 1 3 144 13 50 191 17 67 188 17 66 188 17 66 +188 17 66 188 17 66 189 17 66 187 17 66 123 11 43 20 2 7 +0 0 0 0 0 0 0 0 0 0 0 0 21 2 7 163 15 57 +190 17 67 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 191 17 67 134 12 47 5 0 2 +0 0 0 0 0 0 3 0 1 88 8 31 182 16 64 189 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 189 17 66 +171 15 60 31 3 11 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 20 2 7 162 15 57 190 17 67 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 190 17 67 132 12 46 +20 2 7 0 0 0 0 0 0 0 0 0 32 3 11 173 16 61 +189 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 190 17 67 151 14 53 12 1 4 +0 0 0 0 0 0 72 7 25 180 16 63 189 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +181 16 63 47 4 16 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 21 2 7 163 15 57 190 17 67 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 190 17 67 +122 11 43 9 1 3 0 0 0 0 0 0 30 3 10 171 15 60 +189 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 190 17 67 146 13 51 10 1 4 +0 0 0 38 3 13 166 15 58 190 17 67 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +183 17 64 52 5 18 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 13 1 5 154 14 54 190 17 67 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +186 17 65 79 7 28 0 0 0 0 0 0 14 1 5 156 14 54 +190 17 67 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 191 17 67 124 11 43 2 0 1 +5 0 2 122 11 43 191 17 67 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +182 16 64 47 4 16 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 3 0 1 126 14 44 191 17 67 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +190 17 67 158 14 55 23 2 8 0 0 0 1 0 0 113 10 40 +191 17 67 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 78 7 27 0 0 0 +47 4 16 177 16 62 189 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 189 17 66 +173 16 61 34 3 12 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 85 8 30 189 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 79 7 28 0 0 0 0 0 0 47 4 16 +175 16 62 189 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 190 17 67 156 14 55 22 2 8 0 0 0 +109 10 38 191 17 67 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 190 17 67 +151 14 53 13 1 5 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 35 3 12 173 16 61 189 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 191 17 67 134 12 47 7 1 2 0 0 0 3 0 1 +99 9 35 188 17 66 189 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 189 17 66 181 16 63 68 6 24 0 0 0 18 2 6 +156 14 55 190 17 67 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 190 17 67 +101 9 35 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 3 0 1 118 13 41 191 17 67 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 189 17 66 168 15 59 28 3 10 0 0 0 0 0 0 +12 1 4 113 10 40 187 17 66 189 17 67 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +190 17 67 180 16 63 88 8 31 4 0 1 0 0 0 47 4 16 +180 16 63 189 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 190 17 67 168 15 59 +36 3 13 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 38 3 13 164 15 58 190 17 67 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 182 16 64 50 5 17 0 0 0 0 0 0 +0 0 0 11 1 4 90 8 32 169 15 59 190 17 67 190 17 67 +189 17 66 189 17 66 189 17 66 189 17 66 191 17 67 189 17 66 +158 14 55 68 6 24 4 0 1 0 0 0 0 0 0 73 7 26 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 189 17 66 185 17 65 83 8 29 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 65 6 23 174 16 61 +190 17 67 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 185 17 65 56 5 19 0 0 0 0 0 0 +0 0 0 0 0 0 2 0 1 35 3 12 99 9 35 146 13 51 +170 15 60 177 16 62 177 16 62 166 15 58 141 13 49 85 8 30 +24 2 8 0 0 0 0 0 0 0 0 0 0 0 0 85 8 30 +190 17 67 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 189 17 66 112 10 39 8 1 3 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 68 6 24 +170 15 60 191 17 67 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 182 16 64 50 5 17 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 11 1 4 +28 3 10 40 4 14 38 3 13 25 2 9 8 1 3 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 78 7 27 +189 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 189 17 66 187 17 66 113 10 40 14 1 5 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 +47 4 16 141 13 49 186 17 65 191 17 67 190 17 67 189 17 66 +189 17 66 191 17 67 156 14 55 20 2 7 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 44 4 15 +178 16 62 190 17 67 188 17 66 188 17 66 188 17 66 190 17 67 +191 17 67 173 16 61 90 8 32 10 1 4 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 14 1 5 68 6 24 131 12 46 162 15 57 174 16 61 +171 15 60 146 13 51 56 5 19 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 3 0 1 14 1 5 29 3 10 +41 4 14 47 4 16 50 5 17 45 4 16 34 3 12 18 2 6 +5 0 2 0 0 0 0 0 0 0 0 0 0 0 0 5 0 2 +90 8 32 169 15 59 185 17 65 187 17 66 182 16 64 163 15 57 +113 10 40 41 4 14 2 0 1 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 5 0 2 21 2 7 34 3 12 +29 3 10 11 1 4 0 0 0 0 0 0 0 0 0 0 0 0 +3 0 1 32 3 11 79 7 28 124 11 43 154 14 54 171 15 60 +180 16 63 182 16 64 182 16 64 180 16 63 174 16 61 159 14 56 +132 12 46 88 8 31 34 3 12 3 0 1 0 0 0 0 0 0 +3 0 1 29 3 10 56 5 19 65 6 23 50 5 17 23 2 8 +3 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 25 2 9 +109 10 38 169 15 59 189 17 66 191 17 67 190 17 67 189 17 66 +189 17 66 188 17 66 188 17 66 188 17 66 189 17 66 190 17 67 +191 17 67 190 17 67 171 15 60 98 9 34 10 1 3 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 14 1 5 141 13 49 +191 17 67 189 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 189 17 67 186 17 65 65 6 23 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 23 2 8 166 15 58 +190 17 67 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 189 17 66 176 16 62 45 4 16 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 83 8 29 +183 17 64 189 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 189 17 66 185 17 65 95 9 33 3 0 1 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 2 +85 8 30 176 16 62 191 17 67 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +191 17 67 180 16 63 95 9 33 7 1 3 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +2 0 1 52 5 18 141 13 49 185 17 65 191 17 67 189 17 67 +189 17 66 188 17 66 188 17 66 189 17 66 191 17 67 187 17 66 +146 13 51 56 5 19 4 0 1 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 14 1 5 68 6 24 131 12 46 166 15 58 +180 16 63 183 17 64 180 16 63 168 15 59 134 12 47 75 7 26 +17 2 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 5 0 2 24 2 8 +44 4 15 52 5 18 45 4 16 26 2 9 6 1 2 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 diff --git a/bsp/spacemit/dm/graphic/logo/logo-spacemit-clut224.ppm b/bsp/spacemit/dm/graphic/logo/logo-spacemit-clut224.ppm new file mode 100644 index 000000000000..785f464fa916 --- /dev/null +++ b/bsp/spacemit/dm/graphic/logo/logo-spacemit-clut224.ppm @@ -0,0 +1,1227 @@ +P3 +188 51 +255 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +2 3 1 67 81 36 123 144 74 87 104 46 2 3 1 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 3 1 67 81 36 +163 196 87 192 231 103 192 231 103 192 231 103 108 127 67 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 2 2 1 67 81 36 163 196 87 192 231 103 +192 231 103 192 231 103 192 231 103 192 231 103 159 192 85 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 1 1 0 60 70 37 154 186 83 192 231 103 192 231 103 192 231 103 +192 231 103 192 231 103 192 231 103 192 231 103 163 196 87 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 49 59 26 154 186 83 192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 +192 231 103 192 231 103 192 231 103 192 231 103 163 196 87 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 60 70 37 +154 186 83 192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 +192 231 103 192 231 103 192 231 103 192 231 103 163 196 87 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 108 127 67 192 231 103 +192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 +192 231 103 192 231 103 192 231 103 192 231 103 163 196 87 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 17 20 10 190 229 102 192 231 103 +192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 +192 231 103 192 231 103 192 231 103 192 231 103 163 196 87 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 37 44 20 192 231 103 192 231 103 +192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 +192 231 103 192 231 103 192 231 103 192 231 103 163 196 87 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 37 44 20 192 231 103 192 231 103 +192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 +192 231 103 192 231 103 192 231 103 192 231 103 163 196 87 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 54 54 54 183 183 183 +187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 +187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 +108 108 108 0 0 0 31 31 31 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 +187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 +187 187 187 187 187 187 187 187 187 187 187 187 108 108 108 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 108 108 108 186 186 186 187 187 187 187 187 187 +149 149 149 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 11 11 11 168 168 168 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 +187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 +187 187 187 187 187 187 143 143 143 0 0 0 0 0 0 146 146 146 187 187 187 187 187 187 +187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 +187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 178 178 178 0 0 0 0 0 0 +133 133 133 187 187 187 187 187 187 71 71 71 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 139 139 139 +187 187 187 187 187 187 81 81 81 0 0 0 79 79 79 195 195 195 195 195 195 153 153 153 +0 0 0 0 0 0 185 185 185 195 195 195 195 195 195 195 195 195 195 195 195 195 195 195 +195 195 195 195 195 195 195 195 195 195 195 195 195 195 195 195 195 195 195 195 195 195 195 195 +195 195 195 195 195 195 195 195 195 11 11 11 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 37 44 20 192 231 103 192 231 103 +192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 +192 231 103 192 231 103 192 231 103 192 231 103 163 196 87 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 142 142 142 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +147 147 147 0 0 0 42 42 42 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 222 222 222 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 54 54 54 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 88 88 88 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 61 61 61 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 195 195 195 0 0 0 17 17 17 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 240 240 240 0 0 0 0 0 0 +181 181 181 255 255 255 255 255 255 229 229 229 17 17 17 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 79 79 79 255 255 255 +255 255 255 255 255 255 111 111 111 0 0 0 104 104 104 255 255 255 255 255 255 202 202 202 +0 0 0 0 0 0 244 244 244 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 15 15 15 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 37 44 20 192 231 103 192 231 103 +192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 +192 231 103 192 231 103 192 231 103 192 231 103 163 196 87 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 143 143 143 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +147 147 147 0 0 0 42 42 42 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 225 225 225 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 178 178 178 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 209 209 209 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 64 64 64 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 195 195 195 0 0 0 19 19 19 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 240 240 240 0 0 0 0 0 0 +181 181 181 255 255 255 255 255 255 255 255 255 159 159 159 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 20 20 20 232 232 232 255 255 255 +255 255 255 255 255 255 111 111 111 0 0 0 104 104 104 255 255 255 255 255 255 202 202 202 +0 0 0 0 0 0 244 244 244 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 15 15 15 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 37 44 20 192 231 103 192 231 103 +192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 +192 231 103 192 231 103 192 231 103 192 231 103 159 192 85 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 143 143 143 255 255 255 +255 255 255 199 199 199 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 +51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 +29 29 29 0 0 0 8 8 8 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 +51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 +51 51 51 115 115 115 255 255 255 255 255 255 225 225 225 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 45 45 45 254 254 254 255 255 255 255 255 255 170 170 170 255 255 255 +255 255 255 255 255 255 77 77 77 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 64 64 64 255 255 255 255 255 255 244 244 244 51 51 51 51 51 51 51 51 51 +51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 +51 51 51 51 51 51 39 39 39 0 0 0 4 5 3 51 51 51 51 51 51 51 51 51 +51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 +51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 48 48 48 0 0 0 0 0 0 +181 181 181 255 255 255 255 255 255 255 255 255 255 255 255 80 80 80 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 170 170 170 255 255 255 255 255 255 +255 255 255 255 255 255 111 111 111 0 0 0 104 104 104 255 255 255 255 255 255 202 202 202 +0 0 0 0 0 0 39 39 39 43 43 43 43 43 43 43 43 43 43 43 43 43 43 43 +61 61 61 255 255 255 255 255 255 255 255 255 85 85 85 43 43 43 43 43 43 43 43 43 +43 43 43 43 43 43 43 43 43 2 2 2 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 37 44 20 192 231 103 192 231 103 +192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 +192 231 103 192 231 103 192 231 103 192 231 103 108 127 67 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 143 143 143 255 255 255 +255 255 255 185 185 185 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 80 80 80 255 255 255 255 255 255 225 225 225 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 167 167 167 255 255 255 255 255 255 230 230 230 9 9 9 203 203 203 +255 255 255 255 255 255 200 200 200 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 64 64 64 255 255 255 255 255 255 241 241 241 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +181 181 181 255 255 255 255 255 255 255 255 255 255 255 255 230 230 230 18 18 18 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 88 88 88 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 111 111 111 0 0 0 104 104 104 255 255 255 255 255 255 202 202 202 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +24 24 24 255 255 255 255 255 255 255 255 255 51 51 51 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 37 44 20 192 231 103 192 231 103 +192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 +192 231 103 192 231 103 192 231 103 123 144 74 8 9 5 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 143 143 143 255 255 255 +255 255 255 185 185 185 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 80 80 80 255 255 255 255 255 255 225 225 225 0 0 0 0 0 0 0 0 0 +0 0 0 35 35 35 251 251 251 255 255 255 255 255 255 113 113 113 0 0 0 82 82 82 +255 255 255 255 255 255 255 255 255 65 65 65 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 64 64 64 255 255 255 255 255 255 241 241 241 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +181 181 181 255 255 255 255 255 255 254 254 254 255 255 255 255 255 255 162 162 162 0 0 0 +0 0 0 0 0 0 0 0 0 21 21 21 235 235 235 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 111 111 111 0 0 0 104 104 104 255 255 255 255 255 255 202 202 202 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +24 24 24 255 255 255 255 255 255 255 255 255 51 51 51 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 37 44 20 192 231 103 192 231 103 +192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 +192 231 103 141 169 76 40 48 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 143 143 143 255 255 255 +255 255 255 204 204 204 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 +68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 +39 39 39 0 0 0 11 11 11 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 +68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 +68 68 68 125 125 125 255 255 255 255 255 255 225 225 225 0 0 0 0 0 0 0 0 0 +0 0 0 156 156 156 255 255 255 255 255 255 236 236 236 12 12 12 0 0 0 1 1 1 +209 209 209 255 255 255 255 255 255 187 187 187 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 64 64 64 255 255 255 255 255 255 241 241 241 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 67 67 67 68 68 68 68 68 68 +68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 +68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 2 2 2 0 0 0 +181 181 181 255 255 255 255 255 255 162 162 162 246 246 246 255 255 255 255 255 255 82 82 82 +0 0 0 0 0 0 0 0 0 171 171 171 255 255 255 255 255 255 204 204 204 224 224 224 +255 255 255 255 255 255 111 111 111 0 0 0 104 104 104 255 255 255 255 255 255 202 202 202 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +24 24 24 255 255 255 255 255 255 255 255 255 51 51 51 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 37 44 20 192 231 103 192 231 103 +192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 141 169 76 +40 48 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 143 143 143 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +147 147 147 0 0 0 42 42 42 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 225 225 225 0 0 0 0 0 0 0 0 0 +27 27 27 249 249 249 255 255 255 255 255 255 123 123 123 0 0 0 0 0 0 0 0 0 +92 92 92 255 255 255 255 255 255 255 255 255 57 57 57 0 0 0 0 0 0 0 0 0 +0 0 0 64 64 64 255 255 255 255 255 255 241 241 241 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 250 250 250 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 9 9 9 0 0 0 +181 181 181 255 255 255 255 255 255 124 124 124 115 115 115 255 255 255 255 255 255 231 231 231 +18 18 18 0 0 0 90 90 90 255 255 255 255 255 255 248 248 248 43 43 43 219 219 219 +255 255 255 255 255 255 111 111 111 0 0 0 104 104 104 255 255 255 255 255 255 202 202 202 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +24 24 24 255 255 255 255 255 255 255 255 255 51 51 51 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 37 44 20 192 231 103 192 231 103 +192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 145 174 77 49 59 26 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 143 143 143 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +147 147 147 0 0 0 42 42 42 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 222 222 222 0 0 0 0 0 0 0 0 0 +146 146 146 255 255 255 255 255 255 241 241 241 16 16 16 0 0 0 0 0 0 0 0 0 +3 3 2 219 219 219 255 255 255 255 255 255 178 178 178 0 0 0 0 0 0 0 0 0 +0 0 0 64 64 64 255 255 255 255 255 255 241 241 241 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 250 250 250 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 9 9 9 0 0 0 +181 181 181 255 255 255 255 255 255 124 124 124 2 2 2 194 194 194 255 255 255 255 255 255 +164 164 164 21 21 21 234 234 234 255 255 255 255 255 255 113 113 113 0 0 0 219 219 219 +255 255 255 255 255 255 111 111 111 0 0 0 104 104 104 255 255 255 255 255 255 202 202 202 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +24 24 24 255 255 255 255 255 255 255 255 255 51 51 51 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 24 31 10 192 231 103 192 231 103 +192 231 103 192 231 103 192 231 103 141 169 76 45 54 24 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 96 96 96 170 170 170 +170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 +170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 230 230 230 255 255 255 255 255 255 +147 147 147 0 0 0 42 42 42 255 255 255 255 255 255 255 255 255 173 173 173 170 170 170 +170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 +170 170 170 170 170 170 170 170 170 170 170 170 90 90 90 0 0 0 0 0 0 21 21 21 +245 245 245 255 255 255 255 255 255 133 133 133 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 103 103 103 255 255 255 255 255 255 254 254 254 49 49 49 0 0 0 0 0 0 +0 0 0 64 64 64 255 255 255 255 255 255 241 241 241 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 250 250 250 255 255 255 255 255 255 +187 187 187 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 +170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 6 6 6 0 0 0 +181 181 181 255 255 255 255 255 255 124 124 124 0 0 0 38 38 38 246 246 246 255 255 255 +255 255 255 213 213 213 255 255 255 255 255 255 195 195 195 2 2 2 0 0 0 219 219 219 +255 255 255 255 255 255 111 111 111 0 0 0 104 104 104 255 255 255 255 255 255 202 202 202 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +24 24 24 255 255 255 255 255 255 255 255 255 51 51 51 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 123 144 74 192 231 103 +192 231 103 145 174 77 45 54 24 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 181 181 181 255 255 255 255 255 255 +147 147 147 0 0 0 42 42 42 255 255 255 255 255 255 255 255 255 8 8 8 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 135 135 135 +255 255 255 255 255 255 245 245 245 21 21 21 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 7 7 7 227 227 227 255 255 255 255 255 255 167 167 167 0 0 0 0 0 0 +0 0 0 64 64 64 255 255 255 255 255 255 241 241 241 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 250 250 250 255 255 255 255 255 255 +55 55 55 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +181 181 181 255 255 255 255 255 255 124 124 124 0 0 0 0 0 0 113 113 113 255 255 255 +255 255 255 255 255 255 255 255 255 245 245 245 37 37 37 0 0 0 0 0 0 219 219 219 +255 255 255 255 255 255 111 111 111 0 0 0 104 104 104 255 255 255 255 255 255 202 202 202 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +24 24 24 255 255 255 255 255 255 255 255 255 51 51 51 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 1 40 48 21 +49 59 26 0 0 0 0 0 0 0 0 0 19 21 13 79 91 55 40 46 28 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 181 181 181 255 255 255 255 255 255 +147 147 147 0 0 0 42 42 42 255 255 255 255 255 255 255 255 255 8 8 8 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 15 15 15 239 239 239 +255 255 255 255 255 255 144 144 144 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 113 113 113 255 255 255 255 255 255 252 252 252 38 38 38 0 0 0 +0 0 0 64 64 64 255 255 255 255 255 255 241 241 241 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 250 250 250 255 255 255 255 255 255 +55 55 55 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +181 181 181 255 255 255 255 255 255 124 124 124 0 0 0 0 0 0 2 2 2 194 194 194 +255 255 255 255 255 255 255 255 255 106 106 106 0 0 0 0 0 0 0 0 0 219 219 219 +255 255 255 255 255 255 111 111 111 0 0 0 104 104 104 255 255 255 255 255 255 202 202 202 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +24 24 24 255 255 255 255 255 255 255 255 255 51 51 51 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 1 2 0 10 13 3 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 19 21 13 115 132 80 200 229 138 208 238 144 206 235 142 54 62 37 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 181 181 181 255 255 255 255 255 255 +147 147 147 0 0 0 42 42 42 255 255 255 255 255 255 255 255 255 8 8 8 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 125 125 125 255 255 255 +255 255 255 250 250 250 30 30 30 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 10 10 10 234 234 234 255 255 255 255 255 255 156 156 156 0 0 0 +0 0 0 64 64 64 255 255 255 255 255 255 241 241 241 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 250 250 250 255 255 255 255 255 255 +55 55 55 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +181 181 181 255 255 255 255 255 255 124 124 124 0 0 0 0 0 0 0 0 0 34 34 34 +242 242 242 255 255 255 190 190 190 1 1 1 0 0 0 0 0 0 0 0 0 219 219 219 +255 255 255 255 255 255 111 111 111 0 0 0 104 104 104 255 255 255 255 255 255 202 202 202 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +24 24 24 255 255 255 255 255 255 255 255 255 51 51 51 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 47 60 15 162 208 51 176 226 55 143 183 44 57 73 18 1 1 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +19 21 13 115 132 80 200 229 138 208 238 144 208 238 144 208 238 144 208 238 144 115 132 80 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 105 105 105 187 187 187 +187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 +187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 235 235 235 255 255 255 255 255 255 +147 147 147 0 0 0 42 42 42 255 255 255 255 255 255 255 255 255 8 8 8 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 11 11 11 235 235 235 255 255 255 +255 255 255 154 154 154 0 0 0 0 0 0 0 0 0 0 0 0 67 67 67 153 153 153 +153 153 153 153 153 153 153 153 153 217 217 217 255 255 255 255 255 255 249 249 249 30 30 30 +0 0 0 64 64 64 255 255 255 255 255 255 251 251 251 187 187 187 187 187 187 187 187 187 +187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 +187 187 187 187 187 187 143 143 143 0 0 0 0 0 0 250 250 250 255 255 255 255 255 255 +202 202 202 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 +187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 7 7 7 0 0 0 +181 181 181 255 255 255 255 255 255 124 124 124 0 0 0 0 0 0 0 0 0 0 0 0 +61 61 61 116 116 116 23 23 23 0 0 0 0 0 0 0 0 0 0 0 0 219 219 219 +255 255 255 255 255 255 111 111 111 0 0 0 104 104 104 255 255 255 255 255 255 202 202 202 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +24 24 24 255 255 255 255 255 255 255 255 255 51 51 51 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +4 5 3 162 208 51 176 226 55 176 226 55 176 226 55 176 226 55 144 185 45 55 71 17 +1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 8 9 5 115 132 80 +200 229 138 208 238 144 208 238 144 208 238 144 208 238 144 208 238 144 208 238 144 122 139 84 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 143 143 143 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +147 147 147 0 0 0 42 42 42 255 255 255 255 255 255 255 255 255 8 8 8 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 114 114 114 255 255 255 255 255 255 +252 252 252 37 37 37 0 0 0 0 0 0 0 0 0 0 0 0 112 112 112 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 146 146 146 +0 0 0 64 64 64 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 195 195 195 0 0 0 0 0 0 250 250 250 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 9 9 9 0 0 0 +181 181 181 255 255 255 255 255 255 124 124 124 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 219 219 219 +255 255 255 255 255 255 111 111 111 0 0 0 104 104 104 255 255 255 255 255 255 202 202 202 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +24 24 24 255 255 255 255 255 255 255 255 255 51 51 51 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +24 31 10 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 +144 185 45 55 71 17 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 156 178 108 208 238 144 +208 238 144 208 238 144 208 238 144 208 238 144 208 238 144 208 238 144 208 238 144 122 139 84 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 143 143 143 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +115 115 115 0 0 0 42 42 42 255 255 255 255 255 255 255 255 255 8 8 8 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 7 7 7 227 227 227 255 255 255 255 255 255 +164 164 164 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 112 112 112 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 247 247 247 +25 25 25 37 37 37 251 251 251 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 195 195 195 0 0 0 0 0 0 219 219 219 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 9 9 9 0 0 0 +181 181 181 255 255 255 255 255 255 124 124 124 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 219 219 219 +255 255 255 255 255 255 111 111 111 0 0 0 104 104 104 255 255 255 255 255 255 202 202 202 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +24 24 24 255 255 255 255 255 255 255 255 255 51 51 51 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +27 35 8 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 +176 226 55 176 226 55 146 187 46 59 75 18 1 1 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 28 32 19 208 238 144 208 238 144 +208 238 144 208 238 144 208 238 144 208 238 144 208 238 144 208 238 144 208 238 144 122 139 84 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 29 29 29 51 51 51 +51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 +51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 45 45 45 +1 1 1 0 0 0 8 8 8 51 51 51 51 51 51 51 51 51 2 2 2 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 16 16 16 68 68 68 68 68 68 68 68 68 +23 23 23 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 30 30 30 68 68 68 +68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 +24 24 24 0 0 0 30 30 30 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 +51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 +51 51 51 51 51 51 39 39 39 0 0 0 0 0 0 16 16 16 51 51 51 51 51 51 +51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 +51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 2 2 2 0 0 0 +48 48 48 68 68 68 68 68 68 33 33 33 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 88 88 88 +102 102 102 102 102 102 44 44 44 0 0 0 30 30 30 75 75 75 75 75 75 59 59 59 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +7 7 7 75 75 75 75 75 75 75 75 75 13 13 13 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +27 35 8 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 +176 226 55 176 226 55 176 226 55 176 226 55 144 185 45 59 75 18 1 1 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 40 46 28 208 238 144 208 238 144 +208 238 144 208 238 144 208 238 144 208 238 144 208 238 144 208 238 144 208 238 144 122 139 84 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +27 35 8 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 +176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 144 185 45 59 75 18 +1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 40 46 28 208 238 144 208 238 144 +208 238 144 208 238 144 208 238 144 208 238 144 208 238 144 208 238 144 208 238 144 122 139 84 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +27 35 8 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 +176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 +144 185 45 59 75 18 1 1 0 0 0 0 0 0 0 40 46 28 208 238 144 208 238 144 +208 238 144 208 238 144 208 238 144 208 238 144 208 238 144 208 238 144 208 238 144 79 91 55 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +27 35 8 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 +176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 +176 226 55 176 226 55 122 156 38 1 2 0 0 0 0 40 46 28 208 238 144 208 238 144 +208 238 144 208 238 144 208 238 144 208 238 144 208 238 144 208 238 144 141 169 76 3 3 2 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +27 35 8 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 +176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 +176 226 55 176 226 55 176 226 55 52 67 16 0 0 0 40 46 28 208 238 144 208 238 144 +208 238 144 208 238 144 208 238 144 208 238 144 156 178 108 60 70 37 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +27 35 8 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 +176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 +176 226 55 176 226 55 176 226 55 81 104 25 0 0 0 17 20 10 206 235 142 208 238 144 +208 238 144 208 238 144 156 178 108 54 62 37 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 75 75 75 +169 169 169 90 90 90 0 0 0 0 0 0 0 0 0 0 0 0 77 77 77 136 136 136 +54 54 54 0 0 0 0 0 0 0 0 0 50 50 50 136 136 136 82 82 82 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 31 31 31 169 169 169 132 132 132 0 0 0 +39 39 39 119 119 119 75 75 75 0 0 0 0 0 0 0 0 0 49 49 49 119 119 119 +65 65 65 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 26 26 26 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 +51 51 51 39 39 39 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 1 1 136 136 136 132 132 132 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 12 12 12 136 136 136 +120 120 120 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +27 35 8 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 +176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 +176 226 55 176 226 55 176 226 55 81 104 25 0 0 0 0 0 0 89 95 75 200 229 138 +156 178 108 54 62 37 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 112 112 112 +255 255 255 139 139 139 0 0 0 26 26 26 34 34 34 34 34 34 161 161 161 255 255 255 +122 122 122 34 34 34 34 34 34 34 34 34 116 116 116 255 255 255 168 168 168 34 34 34 +34 34 34 2 2 2 0 0 0 0 0 0 49 49 49 255 255 255 200 200 200 0 0 0 +88 88 88 255 255 255 169 169 169 17 17 17 17 17 17 17 17 17 116 116 116 255 255 255 +149 149 149 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 8 8 8 0 0 0 +0 0 0 130 130 130 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 194 194 194 4 5 3 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 +35 35 35 255 255 255 249 249 249 34 34 34 16 16 16 0 0 0 0 0 0 30 30 30 +34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 54 54 54 255 255 255 +229 229 229 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 +24 24 24 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +27 35 8 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 +176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 +176 226 55 176 226 55 176 226 55 81 104 25 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 88 88 88 +203 203 203 108 108 108 0 0 0 196 196 196 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 12 12 12 0 0 0 0 0 0 38 38 38 203 203 203 158 158 158 0 0 0 +84 84 84 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 123 123 123 0 0 0 +0 0 0 130 130 130 255 255 255 173 173 173 102 102 102 102 102 102 102 102 102 135 135 135 +255 255 255 194 194 194 29 29 29 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 122 122 122 0 0 0 106 106 106 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +254 254 254 44 44 44 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +27 35 8 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 +176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 +176 226 55 176 226 55 176 226 55 81 104 25 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 92 92 92 119 119 119 119 119 119 196 196 196 255 255 255 +153 153 153 85 85 85 85 85 85 85 85 85 147 147 147 255 255 255 200 200 200 119 119 119 +119 119 119 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +16 16 16 128 128 128 136 136 136 136 136 136 136 136 136 136 136 136 185 185 185 255 255 255 +202 202 202 136 136 136 136 136 136 136 136 136 136 136 136 136 136 136 65 65 65 0 0 0 +0 0 0 130 130 130 255 255 255 118 118 118 0 0 0 0 0 0 0 0 0 55 55 55 +255 255 255 194 194 194 13 13 13 119 119 119 119 119 119 119 119 119 119 119 119 119 119 119 +120 120 120 255 255 255 251 251 251 119 119 119 57 57 57 0 0 0 139 139 139 255 255 255 +157 157 157 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 +85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 209 209 209 +255 255 255 64 64 64 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +27 35 8 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 +176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 +176 226 55 176 226 55 176 226 55 81 104 25 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 96 96 96 170 170 170 +167 167 167 42 42 42 0 0 0 0 0 0 0 0 0 0 0 0 146 146 146 255 255 255 +102 102 102 0 0 0 0 0 0 0 0 0 95 95 95 255 255 255 154 154 154 0 0 0 +0 0 0 0 0 0 0 0 0 39 39 39 170 170 170 170 170 170 96 96 96 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 106 106 106 255 255 255 +142 142 142 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 130 130 130 255 255 255 118 118 118 0 0 0 0 0 0 0 0 0 55 55 55 +255 255 255 194 194 194 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 1 1 255 255 255 248 248 248 0 0 0 0 0 0 0 0 0 131 131 131 238 238 238 +102 102 102 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 171 171 171 +238 238 238 59 59 59 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +27 35 8 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 +176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 +176 226 55 176 226 55 176 226 55 81 104 25 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 143 143 143 255 255 255 +255 255 255 113 113 113 0 0 0 0 0 0 0 0 0 0 0 0 146 146 146 255 255 255 +102 102 102 0 0 0 0 0 0 0 0 0 95 95 95 255 255 255 154 154 154 0 0 0 +0 0 0 0 0 0 0 0 0 57 57 57 255 255 255 255 255 255 199 199 199 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 106 106 106 255 255 255 +142 142 142 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 130 130 130 255 255 255 118 118 118 0 0 0 0 0 0 0 0 0 55 55 55 +255 255 255 194 194 194 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 1 1 255 255 255 248 248 248 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 114 114 114 238 238 238 217 217 217 31 31 31 0 0 0 0 0 0 +0 0 0 0 0 0 67 67 67 234 234 234 229 229 229 55 55 55 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +20 25 6 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 +176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 +176 226 55 176 226 55 176 226 55 81 104 25 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 135 135 135 +255 255 255 114 114 114 0 0 0 13 13 13 17 17 17 17 17 17 154 154 154 255 255 255 +122 122 122 34 34 34 34 34 34 34 34 34 116 116 116 255 255 255 161 161 161 17 17 17 +17 17 17 1 1 1 0 0 0 0 0 0 49 49 49 255 255 255 199 199 199 0 0 0 +96 96 96 221 221 221 221 221 221 221 221 221 221 221 221 221 221 221 235 235 235 255 255 255 +240 240 240 221 221 221 221 221 221 221 221 221 221 221 221 221 221 221 106 106 106 0 0 0 +0 0 0 130 130 130 255 255 255 128 128 128 17 17 17 17 17 17 17 17 17 17 17 17 +17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 +18 18 18 255 255 255 248 248 248 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 95 95 95 254 254 254 239 239 239 50 50 50 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 92 92 92 253 253 253 240 240 240 52 52 52 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +1 2 0 146 187 46 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 +176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 +176 226 55 176 226 55 176 226 55 81 104 25 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 135 135 135 +255 255 255 114 114 114 0 0 0 196 196 196 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 12 12 12 0 0 0 0 0 0 49 49 49 255 255 255 199 199 199 0 0 0 +88 88 88 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 239 239 239 255 255 255 +246 246 246 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 99 99 99 0 0 0 +0 0 0 130 130 130 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 248 248 248 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +81 81 81 251 251 251 240 240 240 54 54 54 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 106 106 106 255 255 255 235 235 235 44 44 44 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 24 31 10 133 170 41 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 +176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 +176 226 55 176 226 55 176 226 55 81 104 25 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 135 135 135 +255 255 255 114 114 114 0 0 0 105 105 105 136 136 136 136 136 136 239 239 239 255 255 255 +158 158 158 136 136 136 136 136 136 136 136 136 181 181 181 255 255 255 209 209 209 136 136 136 +136 136 136 6 6 6 0 0 0 0 0 0 49 49 49 255 255 255 199 199 199 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 50 50 50 245 245 245 255 255 255 +253 253 253 81 81 81 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 130 130 130 255 255 255 209 209 209 170 170 170 170 170 170 170 170 170 170 170 170 +170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 +170 170 170 255 255 255 248 248 248 0 0 0 0 0 0 0 0 0 27 27 27 157 157 157 +249 249 249 255 255 255 200 200 200 153 153 153 153 153 153 153 153 153 153 153 153 153 153 153 +153 153 153 153 153 153 153 153 153 153 153 153 153 153 153 231 231 231 255 255 255 232 232 232 +133 133 133 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 41 53 13 133 170 41 176 226 55 176 226 55 176 226 55 +176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 +176 226 55 176 226 55 176 226 55 81 104 25 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 135 135 135 +255 255 255 114 114 114 0 0 0 0 0 0 0 0 0 90 90 90 255 255 255 230 230 230 +6 6 6 0 0 0 0 0 0 0 0 0 95 95 95 255 255 255 154 154 154 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 49 49 49 255 255 255 199 199 199 0 0 0 +0 0 0 0 0 0 0 0 0 16 16 16 128 128 128 245 245 245 255 255 255 209 209 209 +255 255 255 252 252 252 146 146 146 26 26 26 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 130 130 130 255 255 255 118 118 118 0 0 0 0 0 0 0 0 0 18 18 18 +85 85 85 65 65 65 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 1 1 255 255 255 248 248 248 0 0 0 0 0 0 0 0 0 45 45 45 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +222 222 222 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 41 53 13 133 170 41 176 226 55 +176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 +176 226 55 176 226 55 176 226 55 81 104 25 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 135 135 135 +255 255 255 114 114 114 0 0 0 3 3 2 124 124 124 251 251 251 252 252 252 80 80 80 +0 0 0 0 0 0 0 0 0 0 0 0 95 95 95 255 255 255 154 154 154 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 49 49 49 255 255 255 199 199 199 0 0 0 +0 0 0 19 19 19 131 131 131 240 240 240 255 255 255 252 252 252 139 139 139 2 2 2 +131 131 131 251 251 251 255 255 255 247 247 247 147 147 147 29 29 29 0 0 0 0 0 0 +0 0 0 130 130 130 255 255 255 118 118 118 0 0 0 0 0 0 0 0 0 55 55 55 +255 255 255 194 194 194 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 1 1 255 255 255 248 248 248 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 23 23 23 255 255 255 +225 225 225 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 41 53 13 +133 170 41 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 +176 226 55 176 226 55 176 226 55 81 104 25 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 135 135 135 +255 255 255 114 114 114 0 0 0 171 171 171 255 255 255 254 254 254 105 105 105 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 95 95 95 255 255 255 154 154 154 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 49 49 49 255 255 255 199 199 199 0 0 0 +38 38 38 242 242 242 255 255 255 255 255 255 181 181 181 54 54 54 0 0 0 0 0 0 +0 0 0 42 42 42 164 164 164 252 252 252 255 255 255 249 249 249 67 67 67 0 0 0 +0 0 0 130 130 130 255 255 255 118 118 118 0 0 0 0 0 0 0 0 0 55 55 55 +255 255 255 194 194 194 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 1 1 255 255 255 248 248 248 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 23 23 23 255 255 255 +225 225 225 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 47 60 15 139 178 43 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 +176 226 55 176 226 55 176 226 55 81 104 25 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 135 135 135 +255 255 255 114 114 114 0 0 0 88 88 88 240 240 240 85 85 85 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 95 95 95 255 255 255 154 154 154 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 49 49 49 255 255 255 199 199 199 0 0 0 +0 0 0 204 204 204 187 187 187 54 54 54 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 33 33 33 153 153 153 231 231 231 11 11 11 0 0 0 +0 0 0 130 130 130 255 255 255 118 118 118 0 0 0 0 0 0 0 0 0 55 55 55 +255 255 255 194 194 194 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 1 1 255 255 255 248 248 248 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 23 23 23 255 255 255 +225 225 225 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 52 66 16 139 178 43 176 226 55 176 226 55 176 226 55 +176 226 55 176 226 55 176 226 55 74 93 30 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 135 135 135 +255 255 255 114 114 114 0 0 0 0 0 0 20 20 20 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 19 19 19 51 51 51 31 31 31 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 49 49 49 255 255 255 199 199 199 0 0 0 +0 0 0 11 11 11 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 11 11 11 0 0 0 0 0 0 +0 0 0 130 130 130 255 255 255 118 118 118 0 0 0 0 0 0 0 0 0 55 55 55 +255 255 255 194 194 194 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 1 1 255 255 255 248 248 248 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 23 23 23 255 255 255 +225 225 225 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 52 67 16 139 178 43 176 226 55 +176 226 55 176 226 55 162 208 51 20 25 6 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 133 133 133 247 247 247 +255 255 255 246 246 246 238 238 238 238 238 238 238 238 238 238 238 238 238 238 238 238 238 238 +238 238 238 238 238 238 238 238 238 238 238 238 238 238 238 238 238 238 238 238 238 238 238 238 +238 238 238 146 146 146 0 0 0 54 54 54 241 241 241 255 255 255 251 251 251 238 238 238 +238 238 238 238 238 238 238 238 238 238 238 238 238 238 238 238 238 238 238 238 238 238 238 238 +238 238 238 238 238 238 238 238 238 238 238 238 238 238 238 238 238 238 225 225 225 0 0 0 +0 0 0 130 130 130 255 255 255 236 236 236 221 221 221 221 221 221 221 221 221 227 227 227 +255 255 255 194 194 194 0 0 0 0 0 0 30 30 30 221 221 221 221 221 221 221 221 221 +221 221 221 255 255 255 239 239 239 0 0 0 0 0 0 0 0 0 39 39 39 221 221 221 +221 221 221 221 221 221 221 221 221 221 221 221 221 221 221 221 221 221 224 224 224 255 255 255 +251 251 251 221 221 221 221 221 221 221 221 221 221 221 221 221 221 221 221 221 221 221 221 221 +213 213 213 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 52 67 16 +122 156 38 106 132 44 30 39 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 96 96 96 170 170 170 +170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 +170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 +170 170 170 104 104 104 0 0 0 39 39 39 170 170 170 170 170 170 170 170 170 170 170 170 +170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 +170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 161 161 161 0 0 0 +0 0 0 96 96 96 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 +187 187 187 99 99 99 0 0 0 0 0 0 26 26 26 187 187 187 187 187 187 187 187 187 +187 187 187 183 183 183 92 92 92 0 0 0 0 0 0 0 0 0 33 33 33 187 187 187 +187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 +187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 +181 181 181 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 diff --git a/bsp/spacemit/dm/hwcrypto/Kconfig b/bsp/spacemit/dm/hwcrypto/Kconfig new file mode 100644 index 000000000000..77c12e099977 --- /dev/null +++ b/bsp/spacemit/dm/hwcrypto/Kconfig @@ -0,0 +1,17 @@ +config RT_HWCRYPTO_SPACEMIT + bool "Spacemit Crypto Engine" + depends on RT_USING_CLK + depends on RT_USING_RESET + depends on RT_USING_HWCRYPTO + depends on RT_HWCRYPTO_USING_AES + depends on RT_HWCRYPTO_USING_AES_ECB + depends on RT_HWCRYPTO_USING_AES_CBC + default y + +config RT_HWCRYPTO_RNG_SPACEMIT + bool "Spacemit RNG Engine" + depends on RT_USING_CLK + depends on RT_USING_RESET + depends on RT_USING_HWCRYPTO + depends on RT_HWCRYPTO_USING_RNG + default y diff --git a/bsp/spacemit/dm/hwcrypto/SConscript b/bsp/spacemit/dm/hwcrypto/SConscript new file mode 100644 index 000000000000..d6348b177209 --- /dev/null +++ b/bsp/spacemit/dm/hwcrypto/SConscript @@ -0,0 +1,15 @@ +from building import * + +cwd = GetCurrentDir() +src = [] +CPPPATH = [cwd + '/../include'] + +if GetDepend(['RT_HWCRYPTO_SPACEMIT']): + src += ['hw-crypto-spacemit.c'] + +if GetDepend(['RT_HWCRYPTO_RNG_SPACEMIT']): + src += ['hw-rng-spacemit.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/spacemit/dm/hwcrypto/hw-crypto-spacemit.c b/bsp/spacemit/dm/hwcrypto/hw-crypto-spacemit.c new file mode 100644 index 000000000000..fc484dc4b0b2 --- /dev/null +++ b/bsp/spacemit/dm/hwcrypto/hw-crypto-spacemit.c @@ -0,0 +1,1189 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#include +#include + +#include "spacemit.h" + +#define SPACEMIT_AES_BUFFER_LEN (1024 * 256) + +#define WORK_BUF_SIZE 2048 +#define CTR_COUNTER_LITTLE_ENDIAN 0x0000 +#define CTR_COUNTER_BIG_ENDIAN 0x1000 +#define BYTES_TO_BITS 8 +#define SPACEMIT_SECENG_SIZE 0x3000 + +#define ENGINE_DMA_ADDR_HIGH_OFFSET 0x14c +#define SW_RESETN RT_BIT(0) +#define MASTER_CLK_EN RT_BIT(1) +#define SLAVE_CLK_EN RT_BIT(2) +#define WADDR_BIT32 RT_BIT(4) +#define RADDR_BIT32 RT_BIT(5) + +#define CE_BIU_REG_OFFSET 0x00000000L +#define CE_ADEC_REG_OFFSET 0x00000400L +#define CE_DMA_REG_OFFSET 0x00000800L +#define CE_ABUS_REG_OFFSET 0x00000c00L +#define CE_CRYPTO_REG_OFFSET 0x00001000L +#define CE_HASH_REG_OFFSET 0x00001800L + +#define CE_ADEC_CTRL 0x0000 +#define CE_ADEC_CTRL2 0x0004 +#define CE_AXI_SL_CTRL 0x0008 +#define CE_ADEC_INT 0x000c +#define CE_ADEC_INT_MSK 0x0010 +#define CE_ADEC_ACC_ERR_ADR 0x0014 +#define CE_ADEC_MP_FIFO_ERR_ADR 0x0018 + +#define CE_ABUS_BUS_CTRL 0x0000 + +#define SP_HST_INTERRUPT_MASK 0x0cc +#define SP_INTERRUPT_RST 0x218 +#define SP_INTERRUPT_MASK 0x21c +#define SP_CONTROL 0x220 + +#define CE_HASH_CONFIG_REG 0x0000 +#define CE_HASH_CONTROL_REG 0x0004 +#define CE_HASH_COMMAND_REG 0x0008 +#define CE_HASH_STATUS_REG 0x000c +#define CE_HASH_INCOME_SEG_SZ_REG 0x0010 +#define CE_HASH_TOTAL_MSG_SZ_L_REG 0x0018 +#define CE_HASH_TOTAL_MSG_SZ_H_REG 0x001c +#define CE_HASH_DIGEST_BASE 0x0020 +#define CE_HASH_DIGEST_REG(a) (CE_HASH_DIGEST_BASE + (a << 2)) +#define CE_HASH_DIGEST_H_BASE 0x0040 +#define CE_HASH_DIGEST_H_REG(a) (CE_HASH_DIGEST_H_BASE + (a << 2)) +#define CE_HASH_CONTEXTO_BASE 0x0064 +#define CE_HASH_CONTEXTO_REG(a) (CE_HASH_CONTEXTO_BASE + (a << 2)) +#define CE_HASH_CONTEXTO_H_BASE 0x0080 +#define CE_HASH_CONTEXTO_H_REG(a) (CE_HASH_CONTEXTO_H_BASE + (a << 2)) +#define CE_HASH_KEY_BASE 0x00a4 +#define CE_HASH_KEY_REG(a) (CE_HASH_KEY_BASE + (a << 2)) + +#define CE_DMA_IN_CTRL 0x0000 +#define CE_DMA_IN_STATUS 0x0004 +#define CE_DMA_IN_SRC_ADR 0x0008 +#define CE_DMA_IN_XFER_CNTR 0x000c +#define CE_DMA_IN_NX_LL_ADR 0x0010 +#define CE_DMA_IN_INT 0x0014 +#define CE_DMA_IN_INT_MASK 0x0018 +#define CE_DMA_OUT_CTRL 0x001c +#define CE_DMA_OUT_STATUS 0x0020 +#define CE_DMA_OUT_DEST_ADR 0x0024 +#define CE_DMA_OUT_XFER_CNTR 0x0028 +#define CE_DMA_OUT_NX_LL_ADR 0x002c +#define CE_DMA_OUT_INT 0x0030 +#define CE_DMA_OUT_INT_MASK 0x0034 +#define CE_DMA_AXI_CTRL 0x0038 +#define CE_DMA_IF_RCOUNT 0x003c +#define CE_DMA_IF_RD_PTR_ERR 0x0040 +#define CE_DMA_OF_SPACE 0x0044 +#define CE_DMA_OF_RD_PTR_ERR 0x0048 +#define CE_DMA_IF_RAM_BASE 0x0100 +#define CE_DMA_IF_RAM_REG(a) (CE_DMA_IF_RAM_BASE + a*0x4) +#define CE_DMA_OF_RAM_BASE 0x0300 +#define CE_DMA_OF_RAM_REG(a) (CE_DMA_OF_RAM_BASE + a*0x4) + +#define CE_BIU_HST_INTERRUPT_MASK 0x00cc +#define CE_BIU_SP_INTERRUPT_MASK 0x021c +#define CE_BIU_SP_CONTROL 0x0220 + +#define CE_CRYPTO_AES_CONFIG_REG 0x0000 +#define CE_CRYPTO_AES_CONTROL_REG 0x0004 +#define CE_CRYPTO_AES_COMMAND_REG 0x0008 +#define CE_CRYPTO_AES_STATUS_REG 0x000c +#define CE_CRYPTO_AES_INTRPT_SRC_REG 0x0010 +#define CE_CRYPTO_AES_INTRPT_SRC_EN_REG 0x0014 +#define CE_CRYPTO_AES_STREAM_SIZE_REG 0x0018 +#define CE_CRYPTO_ENGINE_SEL_REG 0x00a8 + +#define CE_CRYPTO_K2_BASE 0x0058 +#define CE_CRYPTO_K2_W_REG(a) (CE_CRYPTO_K2_BASE + a * 0x4) +#define CE_CRYPTO_K1_BASE 0x0078 +#define CE_CRYPTO_K1_W_REG(a) (CE_CRYPTO_K1_BASE + a*0x4) +#define CE_CRYPTO_IV_BASE 0x0098 +#define CE_CRYPTO_IV_REG(a) (CE_CRYPTO_IV_BASE + a*0x4) + +#define AES_INTERRUPT_FLAG RT_BIT(0) +#define AES_ERR1_INTERRUPT_FLAG RT_BIT(1) +#define AES_ERR2_INTERRUPT_FLAG RT_BIT(2) +#define AES_INTERRUPT_MASK (AES_INTERRUPT_FLAG | AES_ERR1_INTERRUPT_FLAG | \ + AES_ERR2_INTERRUPT_FLAG) + +#define BIT_DMA_INOUT_DONE RT_BIT(0) +#define BIT_DMA_INOUT_BUS_ERR RT_BIT(1) +#define BIT_DMA_INOUT_LL_ERR RT_BIT(2) +#define BIT_DMA_INOUT_PAR_ERR RT_BIT(3) +#define BIT_DMA_INOUT_PAUSE_CMPL_ERR RT_BIT(4) +#define BIT_DMA_INOUT_DATA_PAR_ERR RT_BIT(5) +#define DMA_INTERRUPT_MASK (BIT_DMA_INOUT_DONE | BIT_DMA_INOUT_BUS_ERR | \ + BIT_DMA_INOUT_LL_ERR | BIT_DMA_INOUT_PAR_ERR | \ + BIT_DMA_INOUT_PAUSE_CMPL_ERR | BIT_DMA_INOUT_DATA_PAR_ERR) + +#define BIU_MASK RT_BIT(0) +#define ADEC_MASK (RT_BIT(1) | RT_BIT(5)) + +#define AES_BLOCK_SIZE 16 + +#define ENGINE_MAX 2 + +enum adec_acc_eng +{ + /* Reset bit */ + E_ACC_ENG_DMA = 1, + E_ACC_ENG_HASH = 5, + E_ACC_ENG_CRYPTO = 3, + E_ACC_ENG_ALL, +}; + +enum abus_grp_a +{ + E_ABUS_GRP_A_HASH = 0x0, +}; + +enum abus_grp_b +{ + E_ABUS_GRP_B_AES = 0x0, + E_ABUS_GRP_B_BYPASS = 0x2, +}; + +enum abus_cross_bar +{ + E_ABUS_STRAIGHT = 0, + E_ABUS_CROSS, +}; + +enum crypto_eng_sel +{ + E_ENG_AES = 0, +}; + +enum crypto_aes_status +{ + AES_INVALID, + AES_DONE, + AES_ERROR +}; + +enum crypto_dma_status +{ + DMA_INVALID, + DMA_INOUT_DONE, + DMA_INOUT_ERROR +}; + +struct spacemit_crypto; + +struct spacemit_crypto_engine +{ + struct rt_hwcrypto_device parent; + + struct spacemit_crypto *crypto; + + int irq; + void *base; + + void *in_buffer, *out_buffer; + rt_ubase_t in_buffer_dma, out_buffer_dma; + + enum crypto_aes_status aes_status; + enum crypto_dma_status dma_in_status; + enum crypto_dma_status dma_out_status; + + struct rt_completion aes_done; + struct rt_completion dma_output_done; + struct rt_completion dma_input_done; + + struct rt_mutex lock; + + rt_uint8_t internal_working_buffer[WORK_BUF_SIZE * 2] rt_align(32); +}; + +struct spacemit_crypto +{ + struct rt_clk *clk; + struct rt_reset_control *rstc; + struct rt_syscon *ciu_regmap; + + rt_uint32_t engine_nr; + struct spacemit_crypto_engine engine[ENGINE_MAX]; +}; + +#define raw_to_spacemit_crypto_engine(raw) rt_container_of((raw)->parent.device, struct spacemit_crypto_engine, parent) + +static void dma_write32(struct spacemit_crypto_engine *ce, int offset, rt_uint32_t value) +{ + tcm_override_writel(ce->base + CE_DMA_REG_OFFSET + offset, value); +} + +static rt_uint32_t dma_read32(struct spacemit_crypto_engine *ce, int offset) +{ + return tcm_override_readl(ce->base + CE_DMA_REG_OFFSET + offset); +} + +static void biu_write32(struct spacemit_crypto_engine *ce, int offset, rt_uint32_t value) +{ + tcm_override_writel(ce->base + CE_BIU_REG_OFFSET + offset, value); +} + +static rt_uint32_t biu_read32(struct spacemit_crypto_engine *ce, int offset) +{ + return tcm_override_readl(ce->base + CE_BIU_REG_OFFSET + offset); +} + +static void adec_write32(struct spacemit_crypto_engine *ce, int offset, rt_uint32_t value) +{ + tcm_override_writel(ce->base + CE_ADEC_REG_OFFSET + offset, value); +} + +static rt_uint32_t adec_read32(struct spacemit_crypto_engine *ce, int offset) +{ + return tcm_override_readl(ce->base + CE_ADEC_REG_OFFSET + offset); +} + +static void abus_write32(struct spacemit_crypto_engine *ce, int offset, rt_uint32_t value) +{ + tcm_override_writel(ce->base + CE_ABUS_REG_OFFSET + offset, value); +} + +static rt_uint32_t abus_read32(struct spacemit_crypto_engine *ce, int offset) +{ + return tcm_override_readl(ce->base + CE_ABUS_REG_OFFSET + offset); +} + +static void crypto_write32(struct spacemit_crypto_engine *ce, int offset, rt_uint32_t value) +{ + tcm_override_writel(ce->base + CE_CRYPTO_REG_OFFSET + offset, value); +} + +static rt_uint32_t crypto_read32(struct spacemit_crypto_engine *ce, int offset) +{ + return tcm_override_readl(ce->base + CE_CRYPTO_REG_OFFSET + offset); +} + +static void dma_output_config(struct spacemit_crypto_engine *ce, int wid_ext, int wid) +{ + rt_uint32_t val; + + val = dma_read32(ce, CE_DMA_OUT_CTRL); + val &= 0x0f0f0000; + val |= (0x7 << 28) | /* Dis error check */ + ((wid_ext & 0xf) << 20) | /* Rid ext */ + (0x1 << 18) | /* Dis out-of-order */ + (0x1 << 17) | /* Data 64 Byte aligned */ + (0x1 << 15) | /* FIFO bus size 64bit */ + (0x1 << 13) | /* Burst type: Inc */ + (0x8 << 8) | /* Burst len */ + ((wid & 0xf) << 4); + + dma_write32(ce, CE_DMA_OUT_CTRL, val); +} + +static void dma_output_address(struct spacemit_crypto_engine *ce, + rt_uint32_t dst_addr, rt_uint32_t dst_size, rt_bool_t chained) +{ + if (chained) + { + dma_write32(ce, CE_DMA_OUT_NX_LL_ADR, dst_addr); + dma_write32(ce, CE_DMA_OUT_DEST_ADR, 0x0); + dma_write32(ce, CE_DMA_OUT_XFER_CNTR, 0x0); + } + else + { + dma_write32(ce, CE_DMA_OUT_NX_LL_ADR, 0x0); + dma_write32(ce, CE_DMA_OUT_DEST_ADR, dst_addr); + dma_write32(ce, CE_DMA_OUT_XFER_CNTR, dst_size); + } +} + +static void dma_output_start(struct spacemit_crypto_engine *ce) +{ + rt_uint32_t val; + + val = dma_read32(ce, CE_DMA_OUT_INT); + dma_write32(ce, CE_DMA_OUT_INT, val); + + val = dma_read32(ce, CE_DMA_OUT_CTRL); + val |= 0x1; + dma_write32(ce, CE_DMA_OUT_CTRL, val); +} + +static void dma_output_stop(struct spacemit_crypto_engine *ce) +{ + rt_uint32_t val; + + val = dma_read32(ce, CE_DMA_OUT_CTRL); + val &= ~0x1; + dma_write32(ce, CE_DMA_OUT_CTRL, val); +} + +static void dma_input_config(struct spacemit_crypto_engine *ce, int rid_ext, int rid) +{ + rt_uint32_t val; + + val = dma_read32(ce, CE_DMA_IN_CTRL); + val &= 0x0f0f0000; + val |= (0x7 << 28) | /* Dis error check */ + ((rid_ext & 0xf) << 20) | /* Rid ext */ + (0x1 << 18) | /* Dis out-of-order */ + (0x1 << 17) | /* Data 64 Byte aligned */ + (0x1 << 15) | /* FIFO bus size 64bit */ + (0x1 << 13) | /* Burst type: Inc */ + (0x8 << 8) | /* Burst len */ + ((rid & 0xf) << 4); + + dma_write32(ce, CE_DMA_IN_CTRL, val); +} + +static void dma_input_address(struct spacemit_crypto_engine *ce, + rt_uint32_t src_addr, rt_uint32_t src_size, rt_bool_t chained) +{ + if (chained) + { + dma_write32(ce, CE_DMA_IN_NX_LL_ADR, src_addr); + dma_write32(ce, CE_DMA_IN_SRC_ADR, 0x0); + dma_write32(ce, CE_DMA_IN_XFER_CNTR, 0x0); + } + else + { + dma_write32(ce, CE_DMA_IN_NX_LL_ADR, 0x0); + dma_write32(ce, CE_DMA_IN_SRC_ADR, src_addr); + dma_write32(ce, CE_DMA_IN_XFER_CNTR, src_size); + } +} + +static void dma_input_start(struct spacemit_crypto_engine *ce) +{ + rt_uint32_t val; + + val = dma_read32(ce, CE_DMA_IN_INT); + dma_write32(ce, CE_DMA_IN_INT, val); + + val = dma_read32(ce, CE_DMA_IN_CTRL); + val |= 0x1; + dma_write32(ce, CE_DMA_IN_CTRL, val); +} + +static void dma_input_stop(struct spacemit_crypto_engine *ce) +{ + rt_uint32_t val; + + val = dma_read32(ce, CE_DMA_IN_CTRL); + val &= ~0x1; + dma_write32(ce, CE_DMA_IN_CTRL, val); +} + +static rt_err_t dma_wait_int_input_finish(struct spacemit_crypto_engine *ce) +{ + rt_completion_wait(&ce->dma_input_done, RT_WAITING_FOREVER); + + if (ce->dma_in_status != DMA_INOUT_DONE) + { + return -RT_EINVAL; + } + + return RT_EOK; +} + +static rt_err_t dma_wait_int_output_finish(struct spacemit_crypto_engine *ce) +{ + rt_completion_wait(&ce->dma_output_done, RT_WAITING_FOREVER); + + if (ce->dma_out_status != DMA_INOUT_DONE) + { + return -RT_EINVAL; + } + + return RT_EOK; +} + +static void adec_biu_clear_int_flag(struct spacemit_crypto_engine *ce) +{ + volatile rt_uint32_t val; + + val = adec_read32(ce, CE_ADEC_INT); + adec_write32(ce, CE_ADEC_INT, val); + + val = biu_read32(ce, SP_INTERRUPT_RST); + biu_write32(ce, SP_INTERRUPT_RST, val); +} + +static rt_err_t adec_engine_hw_reset(struct spacemit_crypto_engine *ce, enum adec_acc_eng engine) +{ + rt_uint32_t val, tmp; + + if (engine == E_ACC_ENG_ALL) + { + tmp = 0xffff; + } + else + { + tmp = 1 << engine; + } + + val = adec_read32(ce, CE_ADEC_CTRL); + val |= tmp; + adec_write32(ce, CE_ADEC_CTRL, val); + val &= ~tmp; + adec_write32(ce, CE_ADEC_CTRL, val); + + if (engine == E_ACC_ENG_DMA) + { + rt_syscon_update_bits(ce->crypto->ciu_regmap, + ENGINE_DMA_ADDR_HIGH_OFFSET, WADDR_BIT32 | RADDR_BIT32, 0); + } + + return RT_EOK; +} + +static rt_err_t abus_set_mode(struct spacemit_crypto_engine *ce, + enum abus_grp_a grp_a_mode, enum abus_grp_b grp_b_mode, + enum abus_cross_bar input_bar, enum abus_cross_bar output_bar) +{ + uint32_t val; + + val = abus_read32(ce, CE_ABUS_BUS_CTRL); + + val &= ~(0x77 << 0x4); + val |= (grp_a_mode << 0x4) | (grp_b_mode << 0x8); + + if (input_bar == E_ABUS_STRAIGHT) + { + val &= ~(0x1 << 0x0); + } + else if (input_bar == E_ABUS_CROSS) + { + val |= 0x1 << 0x0; + } + else + { + return -RT_EINVAL; + } + + if (output_bar == E_ABUS_STRAIGHT) + { + val &= ~(0x1 << 0x2); + } + else if (output_bar == E_ABUS_CROSS) + { + val |= 0x1 << 0x2; + } + else + { + return -RT_EINVAL; + } + + abus_write32(ce, CE_ABUS_BUS_CTRL, val); + + return RT_EOK; +} + +static void enable_biu_mask(struct spacemit_crypto_engine *ce) +{ + rt_uint32_t val; + val = biu_read32(ce, SP_INTERRUPT_MASK); + val &=~BIU_MASK; + biu_write32(ce, SP_INTERRUPT_MASK, val); +} + +static void enable_adec_mask(struct spacemit_crypto_engine *ce) +{ + rt_uint32_t val; + val = adec_read32(ce, CE_ADEC_INT_MSK); + val &=~ADEC_MASK; + adec_write32(ce, CE_ADEC_INT_MSK, val); +} + +static void enable_engine_irq(struct spacemit_crypto_engine *ce) +{ + rt_uint32_t val; + + /* Clear aes INT */ + val = crypto_read32(ce, CE_CRYPTO_AES_INTRPT_SRC_REG); + crypto_write32(ce, CE_CRYPTO_AES_INTRPT_SRC_REG, val); + + val = crypto_read32(ce, CE_CRYPTO_AES_INTRPT_SRC_EN_REG); + val |= AES_INTERRUPT_MASK; + crypto_write32(ce, CE_CRYPTO_AES_INTRPT_SRC_EN_REG, val); + + val = dma_read32(ce, CE_DMA_OUT_INT_MASK); + val &= ~DMA_INTERRUPT_MASK; + dma_write32(ce, CE_DMA_OUT_INT_MASK, val); + + val = dma_read32(ce, CE_DMA_IN_INT_MASK); + val &= ~DMA_INTERRUPT_MASK; + dma_write32(ce, CE_DMA_IN_INT_MASK, val); +} + +static rt_err_t select_engine_crypto(struct spacemit_crypto_engine *ce, + enum crypto_eng_sel engine) +{ + rt_uint32_t val; + + val = crypto_read32(ce, CE_CRYPTO_ENGINE_SEL_REG); + val &= ~0x3; + + switch (engine) + { + case E_ENG_AES: val |= 0x1; break; + default: + return -RT_EINVAL; + } + + crypto_write32(ce, CE_CRYPTO_ENGINE_SEL_REG, val); + + return RT_EOK; +} + +static void crypto_aes_sw_reset(struct spacemit_crypto_engine *ce) +{ + crypto_write32(ce, CE_CRYPTO_AES_CONTROL_REG, 0x1); + crypto_write32(ce, CE_CRYPTO_AES_CONTROL_REG, 0x0); +} + +static void crypto_aes_start(struct spacemit_crypto_engine *ce) +{ + crypto_write32(ce, CE_CRYPTO_AES_COMMAND_REG, 0x1); +} + +static rt_err_t crypto_aes_wait(struct spacemit_crypto_engine *ce) +{ + rt_completion_wait(&ce->aes_done, RT_WAITING_FOREVER); + + if (ce->aes_status != AES_DONE) + { + return -RT_EINVAL; + } + + return RT_EOK; +} + +static rt_err_t crypto_aes_set_mode(struct spacemit_crypto_engine *ce, + struct hwcrypto_symmetric *symmetric_ctx, + struct hwcrypto_symmetric_info *symmetric_info, + rt_bool_t use_rkey) +{ + rt_uint32_t val; + + select_engine_crypto(ce, E_ENG_AES); + + val = crypto_read32(ce, CE_CRYPTO_AES_CONFIG_REG); + val &= ~(0x7 << 0x3); + + switch (symmetric_ctx->parent.type) + { + case HWCRYPTO_TYPE_AES_ECB: val |= 0x0 << 0x3; break; + case HWCRYPTO_TYPE_AES_CBC: val |= 0x1 << 0x3; break; + default: + break; + } + + val &= ~(0x3 << 0x1); + + switch (symmetric_ctx->key_bitlen) + { + case 128: val |= 0x0 << 0x1; break; + case 192: val |= 0x2 << 0x1; break; + case 256: val |= 0x1 << 0x1; break; + default: + return -RT_EINVAL; + } + + val &= ~(0x1 << 0x0); + + if (symmetric_info->mode == HWCRYPTO_MODE_DECRYPT) + { + val |= 0x1 << 0x0; + } + else + { + val |= 0x0 << 0x0; + } + + val &= ~(0x1 << 0x6); + + if (!use_rkey) + { + val |= 0x0 << 0x6; + } + else + { + val |= 0x1 << 0x6; + } + + crypto_write32(ce, CE_CRYPTO_AES_CONFIG_REG, val); + + return RT_EOK; +} + +static rt_err_t crypto_aes_set_key1(struct spacemit_crypto_engine *ce, + const rt_uint8_t *key, rt_uint16_t keylen) +{ + rt_uint32_t val, key_end; + + if (!key) + { + return RT_EOK; + } + + switch (keylen) + { + case 128: key_end = 4; break; + case 192: key_end = 6; break; + case 256: key_end = 8; break; + default: + return -RT_EINVAL; + } + + for (int reg_index = 0; reg_index < 8; ++reg_index) + { + if (reg_index < key_end) + { + val = ((key[0 + (reg_index << 2)] & 0xff) << 0) | + ((key[1 + (reg_index << 2)] & 0xff) << 8) | + ((key[2 + (reg_index << 2)] & 0xff) << 16) | + ((key[3 + (reg_index << 2)] & 0xff) << 24); + } + else + { + val = 0; + } + + crypto_write32(ce, CE_CRYPTO_K1_W_REG(reg_index), val); + } + + return RT_EOK; +} + + +static void crypto_aes_set_iv(struct spacemit_crypto_engine *ce, const rt_uint8_t *iv) +{ + rt_uint32_t val; + + for (int reg_index = 0; reg_index < 4; ++reg_index) + { + val = ((iv[(reg_index << 2) + 0] & 0xff) << 0) | + ((iv[(reg_index << 2) + 1] & 0xff) << 8) | + ((iv[(reg_index << 2) + 2] & 0xff) << 16) | + ((iv[(reg_index << 2) + 3] & 0xff) << 24); + + crypto_write32(ce, CE_CRYPTO_IV_REG(reg_index), val); + } +} + +static rt_err_t aes_process(struct spacemit_crypto_engine *ce, + struct hwcrypto_symmetric *symmetric_ctx, + struct hwcrypto_symmetric_info *symmetric_info, + rt_uint8_t *buf_in, rt_uint8_t *buf_out, rt_size_t blocks) +{ + rt_err_t err; + rt_uint32_t val; + rt_ubase_t dma_addr_in_low, dma_addr_in_high; + rt_ubase_t dma_addr_out_low, dma_addr_out_high; + struct spacemit_crypto *crypto = ce->crypto; + + rt_memcpy(ce->in_buffer, buf_in, blocks << 4); + + dma_addr_in_high = rt_upper_32_bits(ce->in_buffer_dma); + dma_addr_in_low = rt_lower_32_bits(ce->in_buffer_dma); + dma_addr_out_high = rt_upper_32_bits(ce->out_buffer_dma); + dma_addr_out_low = rt_lower_32_bits(ce->out_buffer_dma); + + /* Reset the HW before using it */ + adec_engine_hw_reset(ce, E_ACC_ENG_DMA); + adec_engine_hw_reset(ce, E_ACC_ENG_CRYPTO); + abus_set_mode(ce, E_ABUS_GRP_A_HASH, E_ABUS_GRP_B_AES, E_ABUS_STRAIGHT, E_ABUS_STRAIGHT); + crypto_aes_sw_reset(ce); + + rt_syscon_read(crypto->ciu_regmap, ENGINE_DMA_ADDR_HIGH_OFFSET, &val); + switch (ce - ce->crypto->engine) + { + case 0: + val &= ~(WADDR_BIT32 | RADDR_BIT32); + val |= ((dma_addr_out_high & 0x1) << 4 | (dma_addr_in_high & 0x1) << 5); + break; + + case 1: + val &= ~0xff00; + val |= ((dma_addr_out_high & 0xf) << 8 | (dma_addr_in_high & 0xf) << 12);; + break; + + default: + return -RT_EINVAL; + } + rt_syscon_write(crypto->ciu_regmap, ENGINE_DMA_ADDR_HIGH_OFFSET, val); + + if (ce->in_buffer_dma & 0x3 || ce->out_buffer_dma & 0x3) + { + return -RT_EINVAL; + } + + enable_biu_mask(ce); + enable_adec_mask(ce); + enable_engine_irq(ce); + + dma_input_config(ce, 0, 0); + dma_output_config(ce, 0, 1); + + dma_input_address(ce, dma_addr_in_low, blocks << 2, RT_FALSE); + dma_output_address(ce, dma_addr_out_low, blocks << 2, RT_FALSE); + + /* Process KEY */ + if ((err = crypto_aes_set_mode(ce, symmetric_ctx, symmetric_info, RT_FALSE))) + { + return err; + } + + if ((err = crypto_aes_set_key1(ce, symmetric_ctx->key, symmetric_ctx->key_bitlen))) + { + return err; + } + + /* Process IV */ + switch (symmetric_ctx->parent.type) + { + case HWCRYPTO_TYPE_AES_CBC: + crypto_aes_set_iv(ce, symmetric_ctx->iv); + break; + + default: + break; + } + + crypto_write32(ce, CE_CRYPTO_AES_STREAM_SIZE_REG, blocks << 4); + + dma_input_start(ce); + dma_output_start(ce); + crypto_aes_start(ce); + + if ((err = dma_wait_int_input_finish(ce))) + { + return err; + } + + if ((err = crypto_aes_wait(ce))) + { + return err; + } + + if ((err = dma_wait_int_output_finish(ce))) + { + return err; + } + + /* Readback IV after operation */ + switch (symmetric_ctx->parent.type) + { + case HWCRYPTO_TYPE_AES_CBC: + crypto_aes_set_iv(ce, symmetric_ctx->iv); + break; + + default: + break; + } + + rt_memcpy(buf_out, ce->out_buffer, blocks << 4); + + return RT_EOK; +} + +static rt_err_t spacemit_crypto_symmetric_crypt( + struct hwcrypto_symmetric *symmetric_ctx, + struct hwcrypto_symmetric_info *symmetric_info) +{ + rt_err_t err; + rt_uint32_t blocks; + rt_uint8_t *buf_in, *buf_out; + struct spacemit_crypto_engine *ce = raw_to_spacemit_crypto_engine(symmetric_ctx); + + if (!symmetric_ctx->iv_len) + { + symmetric_ctx->iv_len = sizeof(symmetric_ctx->iv); + rt_memset(symmetric_ctx->iv, 0, symmetric_ctx->iv_len); + } + + switch (symmetric_ctx->parent.type) + { + case HWCRYPTO_TYPE_AES_ECB: + case HWCRYPTO_TYPE_AES_CBC: + break; + default: + return -RT_ENOSYS; + } + + if (symmetric_info->mode != HWCRYPTO_MODE_ENCRYPT && + symmetric_info->mode != HWCRYPTO_MODE_DECRYPT) + { + return -RT_ENOSYS; + } + + buf_in = (void *)symmetric_info->in; + buf_out = symmetric_info->out; + blocks = symmetric_info->length / AES_BLOCK_SIZE; + + rt_mutex_take(&ce->lock, RT_WAITING_FOREVER); + + if ((rt_ubase_t)buf_in & 0x3 || (rt_ubase_t)buf_out & 0x3) + { + int len_bytes = 0, step_bytes = 0; + rt_uint8_t *in_cpy, *out_cpy, *in_work, *out_work; + rt_uint8_t *aligned_buf_1 = &ce->internal_working_buffer[0]; + rt_uint8_t *aligned_buf_2 = &ce->internal_working_buffer[WORK_BUF_SIZE]; + + len_bytes = blocks << 4; + in_cpy = (rt_uint8_t *)buf_in; + out_cpy = (rt_uint8_t *)buf_out; + + while (len_bytes) + { + step_bytes = len_bytes > WORK_BUF_SIZE ? WORK_BUF_SIZE : len_bytes; + + if ((rt_ubase_t)buf_in & 0x3) + { + rt_memcpy(aligned_buf_1, in_cpy, step_bytes); + in_work = aligned_buf_1; + } + else + { + in_work = in_cpy; + } + + len_bytes -= step_bytes; + in_cpy += step_bytes; + + if ((rt_ubase_t)buf_out & 0x3) + { + rt_memset(aligned_buf_2, 0x0, WORK_BUF_SIZE); + out_work = aligned_buf_2; + } + else + { + out_work = out_cpy; + } + + if ((err = aes_process(ce, symmetric_ctx, symmetric_info, in_work, out_work, step_bytes >> 4))) + { + goto _out_lock; + } + + if ((rt_ubase_t)buf_out & 0x3) + { + rt_memcpy(out_cpy, aligned_buf_2, step_bytes); + } + + out_cpy += step_bytes; + } + } + else + { + err = aes_process(ce, symmetric_ctx, symmetric_info, buf_in, buf_out, blocks); + } + +_out_lock: + rt_mutex_release(&ce->lock); + + return err; +} + +static const struct hwcrypto_symmetric_ops spacemit_crypto_symmetric_ops = +{ + .crypt = spacemit_crypto_symmetric_crypt, +}; + +static rt_err_t spacemit_crypto_create(struct rt_hwcrypto_ctx *ctx) +{ + struct hwcrypto_symmetric *crypto_symmetric; + + if ((ctx->type & HWCRYPTO_MAIN_TYPE_MASK) != HWCRYPTO_TYPE_AES) + { + return -RT_ENOSYS; + } + + crypto_symmetric = rt_container_of(ctx, struct hwcrypto_symmetric, parent); + + crypto_symmetric->ops = &spacemit_crypto_symmetric_ops; + + return RT_EOK; +} + +static void spacemit_crypto_destroy(struct rt_hwcrypto_ctx *ctx) +{ + if (!ctx->contex) + { + return; + } + + if ((ctx->type & HWCRYPTO_MAIN_TYPE_MASK) == HWCRYPTO_TYPE_AES) + { + rt_free(ctx->contex); + } +} + +static rt_err_t spacemit_crypto_copy(struct rt_hwcrypto_ctx *des, + const struct rt_hwcrypto_ctx *src) +{ + if ((src->type & HWCRYPTO_MAIN_TYPE_MASK) != HWCRYPTO_TYPE_AES) + { + return -RT_ENOSYS; + } + + return RT_EOK; +} + +static void spacemit_crypto_reset(struct rt_hwcrypto_ctx *ctx) +{ +} + +static const struct rt_hwcrypto_ops spacemit_crypto_ops = +{ + .create = spacemit_crypto_create, + .destroy = spacemit_crypto_destroy, + .copy = spacemit_crypto_copy, + .reset = spacemit_crypto_reset, +}; + +static void spacemit_crypto_isr(int irq, void *param) +{ + volatile rt_uint32_t val_aes; + struct spacemit_crypto_engine *ce = param; + + /* AES */ + val_aes = crypto_read32(ce, CE_CRYPTO_AES_INTRPT_SRC_REG); + + if (val_aes & AES_INTERRUPT_MASK) + { + crypto_write32(ce, CE_CRYPTO_AES_INTRPT_SRC_REG, val_aes); + adec_biu_clear_int_flag(ce); + + ce->aes_status = (val_aes & AES_INTERRUPT_FLAG) ? AES_DONE : AES_ERROR; + rt_completion_done(&ce->aes_done); + + return; + } + + /* DMA output */ + val_aes = dma_read32(ce, CE_DMA_OUT_INT); + + if (val_aes & DMA_INTERRUPT_MASK) + { + dma_output_stop(ce); + dma_write32(ce, CE_DMA_OUT_INT, val_aes); + adec_biu_clear_int_flag(ce); + + ce->dma_out_status = (val_aes & BIT_DMA_INOUT_DONE) ? DMA_INOUT_DONE : DMA_INOUT_ERROR; + rt_completion_done(&ce->dma_output_done); + + return; + } + + /* DMA input */ + val_aes = dma_read32(ce, CE_DMA_IN_INT); + + if (val_aes & DMA_INTERRUPT_MASK) + { + dma_input_stop(ce); + dma_write32(ce, CE_DMA_IN_INT, val_aes); + adec_biu_clear_int_flag(ce); + + ce->dma_in_status = (val_aes & BIT_DMA_INOUT_DONE) ? DMA_INOUT_DONE : DMA_INOUT_ERROR; + rt_completion_done(&ce->dma_input_done); + + return; + } +} + +static void spacemit_crypto_free(struct spacemit_crypto *crypto, struct rt_device *dev) +{ + if (!rt_is_err_or_null(crypto->clk)) + { + rt_clk_disable_unprepare(crypto->clk); + rt_clk_put(crypto->clk); + } + + if (!rt_is_err_or_null(crypto->rstc)) + { + /* RESET_AES is shared with the eFuse and RNG blocks. */ + rt_reset_control_put(crypto->rstc); + } + + for (int i = 0; i < crypto->engine_nr; ++i) + { + struct spacemit_crypto_engine *ce = &crypto->engine[i]; + + if (ce->base) + { + rt_iounmap(ce->base); + } + + if (ce->in_buffer) + { + rt_dma_free_coherent(dev, SPACEMIT_AES_BUFFER_LEN, ce->in_buffer, ce->in_buffer_dma); + } + + if (ce->out_buffer) + { + rt_dma_free_coherent(dev, SPACEMIT_AES_BUFFER_LEN, ce->out_buffer, ce->out_buffer_dma); + } + + if (ce->crypto) + { + rt_mutex_detach(&ce->lock); + + if (rt_device_find(rt_dm_dev_get_name(&ce->parent.parent))) + { + rt_hw_interrupt_mask(ce->irq); + rt_pic_detach_irq(ce->irq, ce); + + rt_device_unregister(&ce->parent.parent); + } + } + } + + rt_free(crypto); +} + +static rt_err_t spacemit_crypto_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + char name[32]; + struct rt_device *dev = &pdev->parent; + struct spacemit_crypto *crypto = rt_calloc(1, sizeof(*crypto)); + + if (!crypto) + { + return -RT_ENOMEM; + } + + if ((err = rt_dm_dev_prop_read_u32(dev, "num-engines", &crypto->engine_nr))) + { + goto _fail; + } + + if (!(crypto->ciu_regmap = rt_syscon_find_by_ofw_compatible("spacemit,ciu"))) + { + err = -RT_EIO; + goto _fail; + } + + crypto->clk = rt_clk_get_by_index(dev, 0); + if (rt_is_err(crypto->clk)) + { + err = rt_ptr_err(crypto->clk); + goto _fail; + } + rt_clk_prepare_enable(crypto->clk); + + crypto->rstc = rt_reset_control_get_by_index(dev, 0); + if (rt_is_err(crypto->rstc)) + { + err = rt_ptr_err(crypto->rstc); + goto _fail; + } + rt_reset_control_deassert(crypto->rstc); + + for (int i = 0; i < crypto->engine_nr; ++i) + { + rt_uint32_t addr_range[2]; + struct spacemit_crypto_engine *ce = &crypto->engine[i]; + + rt_snprintf(name, sizeof(name), "spacemit-crypto-engine-%d", i); + + if ((err = rt_dm_dev_prop_read_u32_array_index(dev, name, 0, 2, &addr_range[0])) <= 0) + { + goto _fail; + } + + if (!(ce->base = rt_ioremap((void *)(rt_ubase_t)addr_range[0], addr_range[1]))) + { + err = -RT_EIO; + goto _fail; + } + + if ((ce->irq = rt_dm_dev_get_irq(dev, i)) < 0) + { + err = ce->irq; + goto _fail; + } + + ce->in_buffer = rt_dma_alloc_coherent(dev, SPACEMIT_AES_BUFFER_LEN, &ce->in_buffer_dma); + if (!ce->in_buffer) + { + err = -RT_ENOMEM; + goto _fail; + } + + ce->out_buffer = rt_dma_alloc_coherent(dev, SPACEMIT_AES_BUFFER_LEN, &ce->out_buffer_dma); + if (!ce->out_buffer) + { + err = -RT_ENOMEM; + goto _fail; + } + + ce->crypto = crypto; + + rt_completion_init(&ce->aes_done); + rt_completion_init(&ce->dma_output_done); + rt_completion_init(&ce->dma_input_done); + + rt_snprintf(name, sizeof(name), "%s%d", RT_HWCRYPTO_DEFAULT_NAME, i); + rt_mutex_init(&ce->lock, name, RT_IPC_FLAG_PRIO); + + ce->parent.ops = &spacemit_crypto_ops; + ce->parent.id = __LINE__; + + if ((err = rt_hwcrypto_register(&ce->parent, name))) + { + goto _fail; + } + + rt_hw_interrupt_install(ce->irq, spacemit_crypto_isr, ce, name); + rt_hw_interrupt_umask(ce->irq); + } + + rt_syscon_update_bits(crypto->ciu_regmap, ENGINE_DMA_ADDR_HIGH_OFFSET, + SW_RESETN | MASTER_CLK_EN | SLAVE_CLK_EN, + SW_RESETN | MASTER_CLK_EN | SLAVE_CLK_EN); + + dev->user_data = crypto; + + return RT_EOK; + +_fail: + spacemit_crypto_free(crypto, dev); + + return err; +} + +static rt_err_t spacemit_crypto_remove(struct rt_platform_device *pdev) +{ + struct rt_device *dev = &pdev->parent; + struct spacemit_crypto *crypto = dev->user_data; + + spacemit_crypto_free(crypto, dev); + + return RT_EOK; +} + +static const struct rt_ofw_node_id spacemit_crypto_ofw_ids[] = +{ + { .compatible = "spacemit,crypto_engine" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver spacemit_crypto_driver = +{ + .name = "hwcrypto-spacemit", + .ids = spacemit_crypto_ofw_ids, + + .probe = spacemit_crypto_probe, + .remove = spacemit_crypto_remove, +}; +RT_PLATFORM_DRIVER_EXPORT(spacemit_crypto_driver); diff --git a/bsp/spacemit/dm/hwcrypto/hw-rng-spacemit.c b/bsp/spacemit/dm/hwcrypto/hw-rng-spacemit.c new file mode 100644 index 000000000000..682f3810057e --- /dev/null +++ b/bsp/spacemit/dm/hwcrypto/hw-rng-spacemit.c @@ -0,0 +1,353 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#include +#include + +#include "spacemit.h" + +#define DBG_TAG "hwrng.spacemit" +#define DBG_LVL DBG_INFO +#include + +#define RNG_BYTE_CNT 0x04 +#define RNG_SRC_ADDR 0x14 +#define RNG_DEST_ADDR 0x24 +#define RNG_NEXT_DESC_PTR 0x34 +#define RNG_SQU_CTRL 0x44 +#define RNG_CURR_DESC_PTR 0x74 +#define RNG_INT_MASK 0x84 +#define RNG_REST_SEL 0x94 +#define RNG_INT_STATUS 0xa4 +#define RNG_CTRL 0xc0 +#define RNG_DATA 0xc4 +#define RNG_SEED_VAL 0xc8 +#define RNG_CTRL_EXT 0xd0 + +#define SQU_CTRL_FIFO_CLR RT_BIT(30) +#define SQU_CTRL_ENABLE_DMA 0x03c60383 +#define RNG_INT_DONE_MASK RT_BIT(0) +#define RESET_SEL_MASK RT_BIT(0) +#define CTRL_RNG_EN RT_BIT(0) +#define CTRL_RNG_VALID RT_BIT(31) +#define CTRL_RNG_SEED_VALID RT_BIT(30) +#define CTRL_RNG_SEED_EN RT_BIT(1) +#define RNG_REG_SEL RT_BIT(4) +#define RNG_REG_LDO_PU RT_BIT(6) +#define RNG_SUCCESS 0x55 +#define RNG_FAIL 0xaa + +#define DMA_MAX_SIZE 0xfff0 +#define RNG_TIMEOUT_MS 100 +#define RNG_POLL_DELAY_US 200 +#define RNG_RETRY_COUNT 2 + +struct spacemit_rng +{ + struct rt_hwcrypto_device parent; + + void *base; + struct rt_clk *clk; + struct rt_reset_control *rstc; + + struct rt_mutex lock; + rt_bool_t lock_ready; + rt_bool_t clk_enabled; +}; + +static void spacemit_rng_clr_fifo(struct spacemit_rng *rng) +{ + rt_uint32_t val; + + val = HWREG32(rng->base + RNG_SQU_CTRL); + val |= SQU_CTRL_FIFO_CLR; + HWREG32(rng->base + RNG_SQU_CTRL) = val; +} + +static void spacemit_rng_reset_status(struct spacemit_rng *rng) +{ + rt_uint32_t val; + + /* Clear squ fifo */ + spacemit_rng_clr_fifo(rng); + + /* Clear rng and seed ctrl bit */ + val = HWREG32(rng->base + RNG_CTRL); + val &= ~(CTRL_RNG_EN | CTRL_RNG_VALID); + val &= ~(CTRL_RNG_SEED_EN | CTRL_RNG_SEED_VALID); + HWREG32(rng->base + RNG_CTRL) = val; +} + +static rt_err_t spacemit_rng_wait_valid(struct spacemit_rng *rng, + rt_uint32_t mask) +{ + rt_tick_t start = rt_tick_get(); + rt_tick_t timeout = rt_tick_from_millisecond(RNG_TIMEOUT_MS); + + do { + if (HWREG32(rng->base + RNG_CTRL) & mask) + { + return RT_EOK; + } + + if ((rt_tick_t)(rt_tick_get() - start) >= timeout) + { + return -RT_ETIMEOUT; + } + + rt_hw_us_delay(RNG_POLL_DELAY_US); + } while (RT_TRUE); +} + +static rt_err_t spacemit_rng_reset_seed(struct spacemit_rng *rng) +{ + rt_uint32_t val; + + for (int i = 0; i < RNG_RETRY_COUNT; ++i) + { + spacemit_rng_reset_status(rng); + + /* Generate software seed */ + HWREG32(rng->base + RNG_SEED_VAL) = rt_tick_get() + i; + + val = HWREG32(rng->base + RNG_CTRL); + val |= CTRL_RNG_SEED_EN; + HWREG32(rng->base + RNG_CTRL) = val; + + if (!spacemit_rng_wait_valid(rng, CTRL_RNG_SEED_VALID)) + { + return RT_EOK; + } + + LOG_W("RNG seed generation timed out, retry %d/%d", + i + 1, RNG_RETRY_COUNT); + } + + spacemit_rng_reset_status(rng); + + return -RT_ETIMEOUT; +} + +static rt_uint32_t spacemit_rng_rand(struct hwcrypto_rng *ctx) +{ + rt_err_t err; + rt_uint32_t val = 0; + struct spacemit_rng *rng = rt_container_of(ctx->parent.device, struct spacemit_rng, parent); + + if ((err = rt_mutex_take(&rng->lock, RT_WAITING_FOREVER))) + { + LOG_E("take RNG lock failed: %s", rt_strerror(err)); + return 0; + } + + for (int i = 0; i < RNG_RETRY_COUNT; ++i) + { + if ((err = spacemit_rng_reset_seed(rng))) + { + LOG_E("RNG seed generation failed: %s", rt_strerror(err)); + break; + } + + /* Generate random value */ + val = HWREG32(rng->base + RNG_CTRL); + val |= CTRL_RNG_EN; + HWREG32(rng->base + RNG_CTRL) = val; + + if (!spacemit_rng_wait_valid(rng, CTRL_RNG_VALID)) + { + spacemit_rng_clr_fifo(rng); + val = HWREG32(rng->base + RNG_DATA); + goto _unlock; + } + + LOG_W("RNG value generation timed out, retry %d/%d", + i + 1, RNG_RETRY_COUNT); + } + + val = 0; + LOG_E("RNG value generation failed: ETIMOUT"); + +_unlock: + spacemit_rng_reset_status(rng); + rt_mutex_release(&rng->lock); + + return val; +} + +static const struct hwcrypto_rng_ops rng_ops = +{ + .update = spacemit_rng_rand, +}; + +static rt_err_t spacemit_rng_create(struct rt_hwcrypto_ctx *ctx) +{ + if ((ctx->type & HWCRYPTO_MAIN_TYPE_MASK) == HWCRYPTO_TYPE_RNG) + { + struct hwcrypto_rng *rng; + + ctx->contex = RT_NULL; + + rng = rt_container_of(ctx, struct hwcrypto_rng, parent); + rng->ops = &rng_ops; + + return RT_EOK; + } + + return -RT_ENOSYS; +} + +static void spacemit_rng_destroy(struct rt_hwcrypto_ctx *ctx) +{ +} + +static rt_err_t spacemit_rng_copy(struct rt_hwcrypto_ctx *des, + const struct rt_hwcrypto_ctx *src) +{ + if ((src->type & HWCRYPTO_MAIN_TYPE_MASK) == HWCRYPTO_TYPE_RNG) + { + return RT_EOK; + } + + return -RT_ENOSYS; +} + +static void spacemit_rng_reset(struct rt_hwcrypto_ctx *ctx) +{ +} + +static const struct rt_hwcrypto_ops spacemit_rng_ops = +{ + .create = spacemit_rng_create, + .destroy = spacemit_rng_destroy, + .copy = spacemit_rng_copy, + .reset = spacemit_rng_reset, +}; + +static void spacemit_crypto_free(struct spacemit_rng *rng) +{ + if (rng->base) + { + rt_iounmap(rng->base); + } + + if (!rt_is_err_or_null(rng->rstc)) + { + /* RESET_AES is shared with the crypto and eFuse blocks. */ + rt_reset_control_put(rng->rstc); + } + + if (!rt_is_err_or_null(rng->clk)) + { + if (rng->clk_enabled) + { + rt_clk_disable_unprepare(rng->clk); + } + rt_clk_put(rng->clk); + } + + if (rng->lock_ready) + { + rt_mutex_detach(&rng->lock); + } + + rt_free(rng); +} + +static rt_err_t spacemit_rng_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + struct rt_device *dev = &pdev->parent; + struct spacemit_rng *rng = rt_calloc(1, sizeof(*rng)); + + if (!rng) + { + return -RT_ENOMEM; + } + + if ((err = rt_mutex_init(&rng->lock, "hwrng", RT_IPC_FLAG_PRIO))) + { + goto _fail; + } + rng->lock_ready = RT_TRUE; + + rng->clk = rt_clk_get_by_index(dev, 0); + if (rt_is_err_or_null(rng->clk)) + { + err = rng->clk ? rt_ptr_err(rng->clk) : -RT_ENOENT; + goto _fail; + } + if ((err = rt_clk_prepare_enable(rng->clk))) + { + goto _fail; + } + rng->clk_enabled = RT_TRUE; + + rng->rstc = rt_reset_control_get_by_index(dev, 0); + if (rt_is_err_or_null(rng->rstc)) + { + err = rng->rstc ? rt_ptr_err(rng->rstc) : -RT_ENOENT; + goto _fail; + } + if ((err = rt_reset_control_deassert(rng->rstc))) + { + goto _fail; + } + + rng->base = rt_dm_dev_iomap(dev, 0); + if (!rng->base) + { + err = -RT_EIO; + goto _fail; + } + + rng->parent.ops = &spacemit_rng_ops; + rng->parent.id = __LINE__; + + if ((err = rt_hwcrypto_register(&rng->parent, "hwrng"))) + { + goto _fail; + } + + dev->user_data = rng; + + return RT_EOK; + +_fail: + spacemit_crypto_free(rng); + + return err; +} + +static rt_err_t spacemit_rng_remove(struct rt_platform_device *pdev) +{ + struct spacemit_rng *rng = pdev->parent.user_data; + + rt_device_unregister(&rng->parent.parent); + + spacemit_crypto_free(rng); + + return RT_EOK; +} + +static const struct rt_ofw_node_id spacemit_rng_ofw_ids[] = +{ + { .compatible = "spacemit,hw_crng" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver spacemit_rng_driver = +{ + .name = "hwrng-spacemit", + .ids = spacemit_rng_ofw_ids, + + .probe = spacemit_rng_probe, + .remove = spacemit_rng_remove, +}; +RT_PLATFORM_DRIVER_EXPORT(spacemit_rng_driver); diff --git a/bsp/spacemit/dm/i2c/Kconfig b/bsp/spacemit/dm/i2c/Kconfig new file mode 100644 index 000000000000..b8821169dbcb --- /dev/null +++ b/bsp/spacemit/dm/i2c/Kconfig @@ -0,0 +1,3 @@ +config RT_I2C_SPACEMIT_K1X + bool "Spacemit k1x I2C controller" + default n diff --git a/bsp/spacemit/dm/i2c/SConscript b/bsp/spacemit/dm/i2c/SConscript new file mode 100644 index 000000000000..3f36c4f80bdd --- /dev/null +++ b/bsp/spacemit/dm/i2c/SConscript @@ -0,0 +1,13 @@ +from building import * + +group = [] +src = [] +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../include'] + +if GetDepend(['RT_I2C_SPACEMIT_K1X']): + src += ['i2c-k1x.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/spacemit/dm/i2c/i2c-k1x.c b/bsp/spacemit/dm/i2c/i2c-k1x.c new file mode 100644 index 000000000000..ed4b32f9c43f --- /dev/null +++ b/bsp/spacemit/dm/i2c/i2c-k1x.c @@ -0,0 +1,1411 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#include +#include +#include + +#define DBG_TAG "i2c.rk3x" +#define DBG_LVL DBG_INFO +#include + +#include + +/* Spacemit i2c registers */ +#define REG_CR 0x0 /* Control Register */ +#define REG_SR 0x4 /* Status Register */ +#define REG_SAR 0x8 /* Slave Address Register */ +#define REG_DBR 0xc /* Data Buffer Register */ +#define REG_LCR 0x10 /* Load Count Register */ +#define REG_WCR 0x14 /* Wait Count Register */ +#define REG_RST_CYC 0x18 /* Bus reset cycle counter */ +#define REG_BMR 0x1c /* Bus monitor register */ +#define REG_WFIFO 0x20 /* Write FIFO Register */ +#define REG_WFIFO_WPTR 0x24 /* Write FIFO Write Pointer Register */ +#define REG_WFIFO_RPTR 0x28 /* Write FIFO Read Pointer Register */ +#define REG_RFIFO 0x2c /* Read FIFO Register */ +#define REG_RFIFO_WPTR 0x30 /* Read FIFO Write Pointer Register */ +#define REG_RFIFO_RPTR 0x34 /* Read FIFO Read Pointer Register */ + +/* Register REG_CR fields */ +#define CR_START RT_BIT(0) /* Start bit */ +#define CR_STOP RT_BIT(1) /* Stop bit */ +#define CR_ACKNAK RT_BIT(2) /* Send ACK(0) or NAK(1) */ +#define CR_TB RT_BIT(3) /* Transfer byte bit */ +#define CR_TXBEGIN RT_BIT(4) /* Transaction begin */ +#define CR_FIFOEN RT_BIT(5) /* Enable FIFO mode */ +#define CR_GPIOEN RT_BIT(6) /* Enable GPIO mode for SCL in HS */ +#define CR_DMAEN RT_BIT(7) /* Enable DMA for TX and RX FIFOs */ +#define CR_MODE_FAST RT_BIT(8) /* Bus mode (master operation) */ +#define CR_MODE_HIGH RT_BIT(9) /* Bus mode (master operation) */ +#define CR_UR RT_BIT(10) /* Unit reset */ +#define CR_RSTREQ RT_BIT(11) /* I2c bus reset request */ +#define CR_MA RT_BIT(12) /* Master abort */ +#define CR_SCLE RT_BIT(13) /* Master clock enable */ +#define CR_IUE RT_BIT(14) /* Unit enable */ +#define CR_HS_STRETCH RT_BIT(16) /* I2C hs stretch */ +#define CR_ALDIE RT_BIT(18) /* Enable arbitration interrupt */ +#define CR_DTEIE RT_BIT(19) /* Enable tx interrupts */ +#define CR_DRFIE RT_BIT(20) /* Enable rx interrupts */ +#define CR_GCD RT_BIT(21) /* General call disable */ +#define CR_BEIE RT_BIT(22) /* Enable bus error ints */ +#define CR_SADIE RT_BIT(23) /* Slave address detected int enable */ +#define CR_SSDIE RT_BIT(24) /* Slave STOP detected int enable */ +#define CR_MSDIE RT_BIT(25) /* Master STOP detected int enable */ +#define CR_MSDE RT_BIT(26) /* Master STOP detected enable */ +#define CR_TXDONEIE RT_BIT(27) /* Transaction done int enable */ +#define CR_TXEIE RT_BIT(28) /* Transmit FIFO empty int enable */ +#define CR_RXHFIE RT_BIT(29) /* Receive FIFO half-full int enable */ +#define CR_RXFIE RT_BIT(30) /* Receive FIFO full int enable */ +#define CR_RXOVIE RT_BIT(31) /* Receive FIFO overrun int enable */ + +/* Register REG_SR fields */ +#define SR_RWM RT_BIT(13) /* Read/write mode */ +#define SR_ACKNAK RT_BIT(14) /* ACK/NACK status */ +#define SR_UB RT_BIT(15) /* Unit busy */ +#define SR_IBB RT_BIT(16) /* I2c bus busy */ +#define SR_EBB RT_BIT(17) /* Early bus busy */ +#define SR_ALD RT_BIT(18) /* Arbitration loss detected */ +#define SR_ITE RT_BIT(19) /* Tx buffer empty */ +#define SR_IRF RT_BIT(20) /* Rx buffer full */ +#define SR_GCAD RT_BIT(21) /* General call address detected */ +#define SR_BED RT_BIT(22) /* Bus error no ACK/NAK */ +#define SR_SAD RT_BIT(23) /* Slave address detected */ +#define SR_SSD RT_BIT(24) /* Slave stop detected */ +#define SR_MSD RT_BIT(26) /* Master stop detected */ +#define SR_TXDONE RT_BIT(27) /* Transaction done */ +#define SR_TXE RT_BIT(28) /* Tx FIFO empty */ +#define SR_RXHF RT_BIT(29) /* Rx FIFO half-full */ +#define SR_RXF RT_BIT(30) /* Rx FIFO full */ +#define SR_RXOV RT_BIT(31) /* RX FIFO overrun */ + +/* Register REG_LCR fields */ +#define LCR_SLV 0x000001ff /* SLV: bit[8:0] */ +#define LCR_FLV 0x0003fe00 /* FLV: bit[17:9] */ +#define LCR_HLVH 0x07fc0000 /* HLVH: bit[26:18] */ +#define LCR_HLVL 0xf8000000 /* HLVL: bit[31:27] */ + +/* Register REG_WCR fields */ +#define WCR_COUNT 0x0000001f /* COUNT: bit[4:0] */ +#define WCR_COUNT1 0x000003e0 /* HS_COUNT1: bit[9:5] */ +#define WCR_COUNT2 0x00007c00 /* HS_COUNT2: bit[14:10] */ + +/* Register REG_BMR fields */ +#define BMR_SDA RT_BIT(0) /* SDA line level */ +#define BMR_SCL RT_BIT(1) /* SCL line level */ + +/* Register REG_WFIFO fields */ +#define WFIFO_DATA_MSK 0x000000ff /* data: bit[7:0] */ +#define WFIFO_CTRL_MSK 0x000003e0 /* control: bit[11:8] */ +#define WFIFO_CTRL_START RT_BIT(8) /* start bit */ +#define WFIFO_CTRL_STOP RT_BIT(9) /* stop bit */ +#define WFIFO_CTRL_ACKNAK RT_BIT(10) /* send ACK(0) or NAK(1) */ +#define WFIFO_CTRL_TB RT_BIT(11) /* transfer byte bit */ + +#define USEC_PER_SEC 1000000L +#define USEC_PER_MSEC 1000L +#define I2C_SMBUS_BLOCK_MAX 32 + +/* Status register init value */ +#define SPACEMIT_I2C_INT_STATUS_MASK 0xfffc0000 /* SR bits[31:18] */ +#define SPACEMIT_I2C_INT_CTRL_MASK (CR_ALDIE | CR_DTEIE | CR_DRFIE | CR_BEIE | CR_TXDONEIE | \ + CR_TXEIE | CR_RXHFIE | CR_RXFIE | CR_RXOVIE | CR_MSDIE) + +/* I2C transfer mode */ +enum spacemit_i2c_xfer_mode +{ + SPACEMIT_I2C_MODE_INTERRUPT, + SPACEMIT_I2C_MODE_FIFO, + SPACEMIT_I2C_MODE_DMA, + SPACEMIT_I2C_MODE_PIO, + SPACEMIT_I2C_MODE_INVALID, +}; + +/* I2C transfer phase during transaction */ +enum spacemit_i2c_xfer_phase +{ + SPACEMIT_I2C_XFER_MASTER_CODE, + SPACEMIT_I2C_XFER_SLAVE_ADDR, + SPACEMIT_I2C_XFER_BODY, + SPACEMIT_I2C_XFER_IDLE, +}; + +/* i2c controller FIFO depth */ +#define SPACEMIT_I2C_RX_FIFO_DEPTH 8 +#define SPACEMIT_I2C_TX_FIFO_DEPTH 8 + +/* i2c bus recover timeout: us */ +#define SPACEMIT_I2C_BUS_RECOVER_TIMEOUT 100000 + +/* i2c bus active timeout: us */ +#define SPACEMIT_I2C_BUS_ACTIVE_TIMEOUT 100000 + +/* scatter list size for DMA mode, equals to max number of i2c messages */ +#define SPACEMIT_I2C_SCATTERLIST_SIZE 42 + +/* for DMA mode, limit one message's length less than 512 bytes */ +#define SPACEMIT_I2C_MAX_MSG_LEN 512 +#define SPACEMIT_I2C_DMA_TX_BUF_LEN ((SPACEMIT_I2C_MAX_MSG_LEN + 2) * SPACEMIT_I2C_SCATTERLIST_SIZE) +#define SPACEMIT_I2C_DMA_RX_BUF_LEN (SPACEMIT_I2C_MAX_MSG_LEN * SPACEMIT_I2C_SCATTERLIST_SIZE) + +#define SPACEMIT_I2C_APB_CLOCK_26M 26000000 +#define SPACEMIT_I2C_APB_CLOCK_52M 52000000 + +#define I2C_SDA_GLITCH_FIX_BYPASS RT_BIT(7) + +/* i2c-spacemit driver's main struct */ +struct spacemit_i2c +{ + struct rt_i2c_bus_device parent; + + int irq; + void *regs; + struct rt_clk *clk; + struct rt_reset_control *rstc; + + rt_uint32_t drv_retries; + + rt_bool_t clk_always_on; + rt_bool_t dma_disable; + + /* Speed mode selection */ + rt_bool_t fast_mode; + rt_bool_t high_mode; + + /* APB clock */ + rt_uint32_t apb_clock; + + /* Master code for high-speed mode */ + rt_uint8_t master_code; + rt_uint32_t clk_rate; + rt_uint32_t i2c_lcr; + rt_uint32_t i2c_wcr; + + /* Slave address with read/write flag */ + rt_uint32_t slave_addr_rw; + + struct rt_i2c_msg *msgs; + int num; + + struct rt_i2c_msg *cur_msg; + int msg_idx; + + rt_uint8_t *msg_buf; + rt_bool_t is_rx; + rt_size_t rx_cnt; + rt_size_t tx_cnt; + int rx_total; + rt_bool_t is_xfer_start; + + struct rt_completion complete; + struct rt_spinlock fifo_lock; + + rt_tick_t timeout; + enum spacemit_i2c_xfer_mode xfer_mode; + enum spacemit_i2c_xfer_phase phase; + rt_uint32_t i2c_ctrl_reg_value; + rt_uint32_t i2c_status; + rt_uint32_t i2c_err; +}; + +#define raw_to_spacemit_i2c(raw) rt_container_of(raw, struct spacemit_i2c, parent) + +static rt_err_t spacemit_i2c_byte_xfer(struct spacemit_i2c *i2c); +static rt_err_t spacemit_i2c_byte_xfer_next_msg(struct spacemit_i2c *i2c); + +rt_inline rt_uint32_t spacemit_i2c_read(struct spacemit_i2c *i2c, int offset) +{ + return HWREG32(i2c->regs + offset); +} + +rt_inline void spacemit_i2c_write(struct spacemit_i2c *i2c, int offset, rt_uint32_t val) +{ + HWREG32(i2c->regs + offset) = val; +} + +static void spacemit_i2c_enable(struct spacemit_i2c *i2c) +{ + spacemit_i2c_write(i2c, REG_CR, spacemit_i2c_read(i2c, REG_CR) | CR_IUE); +} + +static void spacemit_i2c_disable(struct spacemit_i2c *i2c) +{ + i2c->i2c_ctrl_reg_value = spacemit_i2c_read(i2c, REG_CR) & ~CR_IUE; + spacemit_i2c_write(i2c, REG_CR, i2c->i2c_ctrl_reg_value); +} + +static void spacemit_i2c_flush_fifo_buffer(struct spacemit_i2c *i2c) +{ + /* Flush REG_WFIFO_WPTR and REG_WFIFO_RPTR */ + spacemit_i2c_write(i2c, REG_WFIFO_WPTR, 0); + spacemit_i2c_write(i2c, REG_WFIFO_RPTR, 0); + + /* Flush REG_RFIFO_WPTR and REG_RFIFO_RPTR */ + spacemit_i2c_write(i2c, REG_RFIFO_WPTR, 0); + spacemit_i2c_write(i2c, REG_RFIFO_RPTR, 0); +} + +static void spacemit_i2c_controller_reset(struct spacemit_i2c *i2c) +{ + /* Controller reset */ + spacemit_i2c_write(i2c, REG_CR, CR_UR); + rt_hw_us_delay(5); + spacemit_i2c_write(i2c, REG_CR, 0); + + /* Set load counter register */ + if (i2c->i2c_lcr) + { + spacemit_i2c_write(i2c, REG_LCR, i2c->i2c_lcr); + } + + /* Set wait counter register */ + if (i2c->i2c_wcr) + { + spacemit_i2c_write(i2c, REG_WCR, i2c->i2c_wcr); + } +} + +static void spacemit_i2c_bus_reset(struct spacemit_i2c *i2c) +{ + rt_uint32_t bus_status, val; + + /* If bus is locked, reset unit. 0: locked */ + bus_status = spacemit_i2c_read(i2c, REG_BMR); + if (!(bus_status & BMR_SDA) || !(bus_status & BMR_SCL)) + { + spacemit_i2c_controller_reset(i2c); + rt_hw_us_delay(15); + } + + for (int clk_cnt = 0; clk_cnt < 9; ++clk_cnt) + { + /* check whether the SDA is still locked by slave */ + bus_status = spacemit_i2c_read(i2c, REG_BMR); + if (bus_status & BMR_SDA) + { + break; + } + + /* If still locked, send one clk to slave to request release */ + val = spacemit_i2c_read(i2c, REG_RST_CYC); + spacemit_i2c_write(i2c, REG_RST_CYC, val | 0x1); + spacemit_i2c_write(i2c, REG_CR, CR_RSTREQ); + rt_hw_us_delay(25); + } +} + +static void spacemit_i2c_reset(struct spacemit_i2c *i2c) +{ + spacemit_i2c_controller_reset(i2c); +} + +static rt_err_t spacemit_i2c_recover_bus_busy(struct spacemit_i2c *i2c) +{ + rt_err_t err; + int cnt, timeout = i2c->high_mode ? 1000 : 1500; /* us */ + + cnt = SPACEMIT_I2C_BUS_RECOVER_TIMEOUT / timeout; + + if (!(spacemit_i2c_read(i2c, REG_SR) & (SR_UB | SR_IBB))) + { + return RT_EOK; + } + + /* Wait unit and bus to recover idle */ + while (spacemit_i2c_read(i2c, REG_SR) & (SR_UB | SR_IBB)) + { + if (cnt-- <= 0) + { + break; + } + + rt_hw_us_delay((timeout / 2 + timeout) / 2); + } + + if (cnt <= 0) + { + /* Reset controller */ + spacemit_i2c_reset(i2c); + err = -RT_EIO; + } + else + { + err = RT_EOK; + } + + return err; +} + +static void spacemit_i2c_check_bus_release(struct spacemit_i2c *i2c) +{ + /* In case bus is not released after transfer completes */ + if (spacemit_i2c_read(i2c, REG_SR) & SR_EBB) + { + spacemit_i2c_bus_reset(i2c); + rt_hw_us_delay(120); + } +} + +static void spacemit_i2c_unit_init(struct spacemit_i2c *i2c) +{ + rt_uint32_t cr_val = 0; + + /* + * Unmask interrupt bits for all xfer mode: + * bus error, arbitration loss detected. + * For transaction complete signal, we use master stop + * interrupt, so we don't need to unmask CR_TXDONEIE. + */ + cr_val |= CR_BEIE | CR_ALDIE; + + if (i2c->xfer_mode == SPACEMIT_I2C_MODE_INTERRUPT) + { + /* + * Unmask interrupt bits for interrupt xfer mode: DBR rx full. + * For tx empty interrupt CR_DTEIE, we only need to enable when + * trigger byte transfer to start data sending. + */ + cr_val |= CR_DRFIE; + } + else if (i2c->xfer_mode == SPACEMIT_I2C_MODE_FIFO) + { + /* Enable i2c FIFO mode*/ + cr_val |= CR_FIFOEN; + } + else if (i2c->xfer_mode == SPACEMIT_I2C_MODE_DMA) + { + /* Enable i2c DMA mode*/ + cr_val |= CR_DMAEN | CR_FIFOEN; + } + + /* Set speed bits */ + if (i2c->fast_mode) + { + cr_val |= CR_MODE_FAST; + } + if (i2c->high_mode) + { + cr_val |= CR_MODE_HIGH | CR_GPIOEN; + } + + /* Disable response to general call */ + cr_val |= CR_GCD; + + /* Enable SCL clock output */ + cr_val |= CR_SCLE; + + /* Enable master stop detected */ + cr_val |= CR_MSDE | CR_MSDIE; + + /* Disable int to use pio xfer mode*/ + if (i2c->xfer_mode == SPACEMIT_I2C_MODE_PIO) + { + cr_val &= ~(CR_ALDIE | CR_BEIE | CR_MSDIE | CR_DTEIE); + } + + spacemit_i2c_write(i2c, REG_CR, cr_val); +} + +static void spacemit_i2c_trigger_byte_xfer(struct spacemit_i2c *i2c) +{ + rt_uint32_t cr_val; + + /* Send start pulse */ + cr_val = spacemit_i2c_read(i2c, REG_CR); + cr_val &= ~CR_STOP; + if (i2c->xfer_mode == SPACEMIT_I2C_MODE_PIO) + { + cr_val |= CR_START | CR_TB; + } + else + { + cr_val |= CR_START | CR_TB | CR_DTEIE; + } + spacemit_i2c_write(i2c, REG_CR, cr_val); +} + +rt_inline void spacemit_i2c_clear_int_status(struct spacemit_i2c *i2c, rt_uint32_t mask) +{ + spacemit_i2c_write(i2c, REG_SR, mask & SPACEMIT_I2C_INT_STATUS_MASK); +} + +static rt_bool_t spacemit_i2c_is_last_byte_to_send(struct spacemit_i2c *i2c) +{ + return i2c->tx_cnt == i2c->cur_msg->len && i2c->msg_idx == i2c->num - 1; +} + +static rt_bool_t spacemit_i2c_is_last_byte_to_receive(struct spacemit_i2c *i2c) +{ + return i2c->rx_cnt == i2c->cur_msg->len - 1 && i2c->msg_idx == i2c->num - 1; +} + +static void spacemit_i2c_mark_rw_flag(struct spacemit_i2c *i2c) +{ + if (i2c->cur_msg->flags & RT_I2C_RD) + { + i2c->is_rx = RT_TRUE; + i2c->slave_addr_rw = ((i2c->cur_msg->addr & 0x7f) << 1) | 1; + } + else + { + i2c->is_rx = RT_FALSE; + i2c->slave_addr_rw = (i2c->cur_msg->addr & 0x7f) << 1; + } +} + +static void spacemit_i2c_byte_xfer_send_master_code(struct spacemit_i2c *i2c) +{ + rt_uint32_t cr_val = spacemit_i2c_read(i2c, REG_CR); + + i2c->phase = SPACEMIT_I2C_XFER_MASTER_CODE; + + spacemit_i2c_write(i2c, REG_DBR, i2c->master_code); + + cr_val &= ~(CR_STOP | CR_ALDIE); + + /* High mode: enable gpio to let I2C core generates SCL clock */ + cr_val |= CR_GPIOEN | CR_START | CR_TB | CR_DTEIE; + spacemit_i2c_write(i2c, REG_CR, cr_val); +} + +static void spacemit_i2c_byte_xfer_send_slave_addr(struct spacemit_i2c *i2c) +{ + i2c->phase = SPACEMIT_I2C_XFER_SLAVE_ADDR; + + /* Write slave address to DBR for interrupt mode */ + spacemit_i2c_write(i2c, REG_DBR, i2c->slave_addr_rw); + + spacemit_i2c_trigger_byte_xfer(i2c); +} + +static rt_err_t spacemit_i2c_byte_xfer_body(struct spacemit_i2c *i2c) +{ + rt_err_t err = RT_EOK; + rt_uint32_t cr_val = spacemit_i2c_read(i2c, REG_CR); + + cr_val &= ~(CR_TB | CR_ACKNAK | CR_STOP | CR_START); + i2c->phase = SPACEMIT_I2C_XFER_BODY; + + if (i2c->i2c_status & SR_IRF) /* Receive full */ + { + /* If current is transmit mode, ignore this signal */ + if (!i2c->is_rx) + { + return RT_EOK; + } + + if (i2c->rx_cnt < i2c->cur_msg->len) + { + *i2c->msg_buf++ = spacemit_i2c_read(i2c, REG_DBR); + i2c->rx_cnt++; + } + + /* If transfer completes, ISR will handle it */ + if (i2c->i2c_status & (SR_MSD | SR_ACKNAK)) + { + return RT_EOK; + } + + /* Trigger next byte receive */ + if (i2c->rx_cnt < i2c->cur_msg->len) + { + /* Send stop pulse for last byte of last msg */ + if (spacemit_i2c_is_last_byte_to_receive(i2c)) + { + cr_val |= CR_STOP | CR_ACKNAK; + } + + cr_val |= CR_ALDIE | CR_TB; + spacemit_i2c_write(i2c, REG_CR, cr_val); + } + else if (i2c->msg_idx < i2c->num - 1) + { + err = spacemit_i2c_byte_xfer_next_msg(i2c); + } + } + else if (i2c->i2c_status & SR_ITE) /* Transmit empty */ + { + /* MSD comes with ITE */ + if (i2c->i2c_status & SR_MSD) + { + return err; + } + + if (i2c->i2c_status & SR_RWM) /* Receive mode */ + { + /* If current is transmit mode, ignore this signal */ + if (!i2c->is_rx) + { + return RT_EOK; + } + + if (spacemit_i2c_is_last_byte_to_receive(i2c)) + { + cr_val |= CR_STOP | CR_ACKNAK; + } + + /* Trigger next byte receive */ + cr_val |= CR_ALDIE | CR_TB; + + /* + * Mask transmit empty interrupt to avoid useless tx + * interrupt signal after switch to receive mode, the + * next expected is receive full interrupt signal. + */ + cr_val &= ~CR_DTEIE; + spacemit_i2c_write(i2c, REG_CR, cr_val); + } + else /* Transmit mode */ + { + /* If current is receive mode, ignore this signal */ + if (i2c->is_rx) + { + return RT_EOK; + } + + if (i2c->tx_cnt < i2c->cur_msg->len) + { + spacemit_i2c_write(i2c, REG_DBR, *i2c->msg_buf++); + i2c->tx_cnt++; + + /* Send stop pulse for last byte of last msg */ + if (spacemit_i2c_is_last_byte_to_send(i2c)) + { + cr_val |= CR_STOP; + } + + cr_val |= CR_ALDIE | CR_TB; + spacemit_i2c_write(i2c, REG_CR, cr_val); + } + else if (i2c->msg_idx < i2c->num - 1) + { + err = spacemit_i2c_byte_xfer_next_msg(i2c); + } + } + } + + return err; +} + +static rt_err_t spacemit_i2c_byte_xfer_next_msg(struct spacemit_i2c *i2c) +{ + if (i2c->msg_idx == i2c->num - 1) + { + return RT_EOK; + } + + i2c->msg_idx++; + i2c->cur_msg = i2c->msgs + i2c->msg_idx; + i2c->msg_buf = i2c->cur_msg->buf; + i2c->rx_cnt = 0; + i2c->tx_cnt = 0; + i2c->i2c_err = 0; + i2c->i2c_status = 0; + i2c->phase = SPACEMIT_I2C_XFER_IDLE; + + spacemit_i2c_mark_rw_flag(i2c); + + return spacemit_i2c_byte_xfer(i2c); +} + +static void spacemit_i2c_fifo_xfer_fill_buffer(struct spacemit_i2c *i2c) +{ + rt_ubase_t level; + int data_cnt = 0, finish, count = 0, fill = 0; + rt_uint32_t data = 0, data_buf[SPACEMIT_I2C_TX_FIFO_DEPTH * 2]; + + while (i2c->msg_idx < i2c->num) + { + spacemit_i2c_mark_rw_flag(i2c); + + if (i2c->is_rx) + { + finish = i2c->rx_cnt; + } + else + { + finish = i2c->tx_cnt; + } + + /* Write master code to fifo buffer */ + if (i2c->high_mode && i2c->is_xfer_start) + { + data = i2c->master_code; + data |= WFIFO_CTRL_TB | WFIFO_CTRL_START; + data_buf[data_cnt++] = data; + + fill += 2; + count = rt_min_t(rt_size_t, i2c->cur_msg->len - finish, SPACEMIT_I2C_TX_FIFO_DEPTH - fill); + } + else + { + fill += 1; + count = rt_min_t(rt_size_t, i2c->cur_msg->len - finish, SPACEMIT_I2C_TX_FIFO_DEPTH - fill); + } + + i2c->is_xfer_start = RT_FALSE; + fill += count; + data = i2c->slave_addr_rw; + data |= WFIFO_CTRL_TB | WFIFO_CTRL_START; + + /* Write slave address to fifo buffer */ + data_buf[data_cnt++] = data; + + if (i2c->is_rx) + { + i2c->rx_cnt += count; + + if (i2c->rx_cnt == i2c->cur_msg->len && i2c->msg_idx == i2c->num - 1) + { + count -= 1; + } + + while (count > 0) + { + data = *i2c->msg_buf | WFIFO_CTRL_TB; + data_buf[data_cnt++] = data; + i2c->msg_buf++; + count--; + } + + if (i2c->rx_cnt == i2c->cur_msg->len && i2c->msg_idx == i2c->num - 1) + { + data = *i2c->msg_buf++; + data = i2c->slave_addr_rw | WFIFO_CTRL_TB | WFIFO_CTRL_STOP | WFIFO_CTRL_ACKNAK; + data_buf[data_cnt++] = data; + } + } + else + { + i2c->tx_cnt += count; + if (spacemit_i2c_is_last_byte_to_send(i2c)) + { + count -= 1; + } + + while (count > 0) + { + data = *i2c->msg_buf | WFIFO_CTRL_TB; + data_buf[data_cnt++] = data; + i2c->msg_buf++; + count--; + } + if (spacemit_i2c_is_last_byte_to_send(i2c)) + { + data = *i2c->msg_buf | WFIFO_CTRL_TB | WFIFO_CTRL_STOP; + data_buf[data_cnt++] = data; + } + } + + if (i2c->tx_cnt == i2c->cur_msg->len || i2c->rx_cnt == i2c->cur_msg->len) + { + i2c->msg_idx++; + if (i2c->msg_idx == i2c->num) + { + break; + } + + i2c->cur_msg = i2c->msgs + i2c->msg_idx; + i2c->msg_buf = i2c->cur_msg->buf; + i2c->rx_cnt = 0; + i2c->tx_cnt = 0; + } + + if (fill == SPACEMIT_I2C_TX_FIFO_DEPTH) + { + break; + } + } + + level = rt_spin_lock_irqsave(&i2c->fifo_lock); + + for (int i = 0; i < data_cnt; ++i) + { + spacemit_i2c_write(i2c, REG_WFIFO, data_buf[i]); + } + + rt_spin_unlock_irqrestore(&i2c->fifo_lock, level); +} + +static void spacemit_i2c_fifo_xfer_copy_buffer(struct spacemit_i2c *i2c) +{ + int idx = 0, cnt = 0; + struct rt_i2c_msg *msg; + + /* Copy the rx FIFO buffer to msg */ + while (idx < i2c->num) + { + msg = i2c->msgs + idx; + if (msg->flags & RT_I2C_RD) + { + cnt = msg->len; + while (cnt > 0) + { + *(msg->buf + msg->len - cnt) = spacemit_i2c_read(i2c, REG_RFIFO); + cnt--; + } + } + idx++; + } +} + +static rt_err_t spacemit_i2c_fifo_xfer(struct spacemit_i2c *i2c) +{ + rt_err_t err = RT_EOK; + + spacemit_i2c_fifo_xfer_fill_buffer(i2c); + + if ((err = rt_completion_wait(&i2c->complete, i2c->timeout))) + { + spacemit_i2c_bus_reset(i2c); + goto _err_out; + } + + if (i2c->i2c_err) + { + err = -RT_ERROR; + spacemit_i2c_flush_fifo_buffer(i2c); + goto _err_out; + } + + spacemit_i2c_fifo_xfer_copy_buffer(i2c); + +_err_out: + return err; +} + +static rt_err_t spacemit_i2c_byte_xfer(struct spacemit_i2c *i2c) +{ + rt_err_t err = RT_EOK; + + if (i2c->i2c_err) + { + return -RT_ERROR; + } + + if (i2c->phase == SPACEMIT_I2C_XFER_IDLE) + { + if (i2c->high_mode && i2c->is_xfer_start) + { + spacemit_i2c_byte_xfer_send_master_code(i2c); + } + else + { + spacemit_i2c_byte_xfer_send_slave_addr(i2c); + } + + i2c->is_xfer_start = RT_FALSE; + } + else if (i2c->phase == SPACEMIT_I2C_XFER_MASTER_CODE) + { + spacemit_i2c_byte_xfer_send_slave_addr(i2c); + } + else + { + err = spacemit_i2c_byte_xfer_body(i2c); + } + + return err; +} + +static void spacemit_i2c_choose_xfer_mode(struct spacemit_i2c *i2c) +{ + unsigned long timeout; + int idx = 0, cnt = 0, freq; + rt_bool_t block = RT_FALSE; + + /* Scan msgs */ + if (i2c->high_mode) + { + cnt++; + } + + i2c->rx_total = 0; + + while (idx < i2c->num) + { + cnt += (i2c->msgs + idx)->len + 1; + + if ((i2c->msgs + idx)->flags & RT_I2C_RD) + { + i2c->rx_total += (i2c->msgs + idx)->len; + } + + idx++; + } + + if (i2c->dma_disable || block) + { + i2c->xfer_mode = SPACEMIT_I2C_MODE_INTERRUPT; + } + else + { + if (cnt <= SPACEMIT_I2C_TX_FIFO_DEPTH) + { + i2c->xfer_mode = SPACEMIT_I2C_MODE_FIFO; + } + else + { + i2c->xfer_mode = SPACEMIT_I2C_MODE_DMA; + } + + /* Flush fifo buffer */ + spacemit_i2c_flush_fifo_buffer(i2c); + } + + /* + * if total message length is too large to over the allocated MDA + * total buf length, use interrupt mode. This may happens in the + * syzkaller test. + */ + if (cnt > (SPACEMIT_I2C_MAX_MSG_LEN * SPACEMIT_I2C_SCATTERLIST_SIZE) || + i2c->rx_total > SPACEMIT_I2C_DMA_RX_BUF_LEN) + { + i2c->xfer_mode = SPACEMIT_I2C_MODE_INTERRUPT; + } + + /* calculate timeout */ + if (i2c->high_mode) + { + freq = 1500000; + } + else if (i2c->fast_mode) + { + freq = 400000; + } + else + { + freq = 100000; + } + + timeout = cnt * 9 * USEC_PER_SEC / freq; + + if (i2c->xfer_mode == SPACEMIT_I2C_MODE_INTERRUPT || + i2c->xfer_mode == SPACEMIT_I2C_MODE_PIO) + { + timeout += (cnt - 1) * 220; + } + + timeout /= USEC_PER_MSEC; + + if (i2c->xfer_mode == SPACEMIT_I2C_MODE_INTERRUPT) + { + i2c->timeout = rt_tick_from_millisecond(timeout + 500); + } + else + { + i2c->timeout = rt_tick_from_millisecond(timeout + 100); + } +} + +static void spacemit_i2c_init_xfer_params(struct spacemit_i2c *i2c) +{ + /* Initialize transfer parameters */ + i2c->msg_idx = 0; + i2c->cur_msg = i2c->msgs; + i2c->msg_buf = i2c->cur_msg->buf; + i2c->rx_cnt = 0; + i2c->tx_cnt = 0; + i2c->i2c_err = 0; + i2c->i2c_status = 0; + i2c->phase = SPACEMIT_I2C_XFER_IDLE; + + /* Only send master code once for high speed mode */ + i2c->is_xfer_start = RT_TRUE; +} + +rt_used +static rt_ssize_t spacemit_i2c_pio_xfer(struct spacemit_i2c *i2c) +{ + rt_ssize_t res; + int xfer_try = 0; + rt_uint32_t status; + signed long timeout; + +_xfer_retry: + /* calculate timeout */ + spacemit_i2c_choose_xfer_mode(i2c); + i2c->xfer_mode = SPACEMIT_I2C_MODE_PIO; + timeout = i2c->timeout * (1000U / RT_TICK_PER_SECOND) * USEC_PER_MSEC; + + if (!i2c->clk_always_on) + { + rt_clk_enable(i2c->clk); + } + + spacemit_i2c_controller_reset(i2c); + rt_hw_us_delay(2); + + spacemit_i2c_unit_init(i2c); + + spacemit_i2c_clear_int_status(i2c, SPACEMIT_I2C_INT_STATUS_MASK); + + spacemit_i2c_init_xfer_params(i2c); + + spacemit_i2c_mark_rw_flag(i2c); + + spacemit_i2c_enable(i2c); + + if ((res = spacemit_i2c_byte_xfer(i2c)) < 0) + { + goto _out; + } + + while (i2c->num > 0 && timeout > 0) + { + status = spacemit_i2c_read(i2c, REG_SR); + spacemit_i2c_clear_int_status(i2c, status); + i2c->i2c_status = status; + + /* Bus error, arbitration lost */ + i2c->i2c_err = status & (SR_BED | SR_ALD); + if (i2c->i2c_err) + { + res = -RT_ERROR; + break; + } + + /* Receive full */ + if (status & SR_IRF) + { + if ((res = spacemit_i2c_byte_xfer(i2c)) < 0) + { + break; + } + } + + /* Transmit empty */ + if (status & SR_ITE) + { + if ((res = spacemit_i2c_byte_xfer(i2c)) < 0) + { + break; + } + } + + /* Transaction done */ + if (status & SR_MSD) + { + break; + } + + rt_hw_us_delay(10); + timeout -= 10; + } + + spacemit_i2c_disable(i2c); + + if (!i2c->clk_always_on) + { + rt_clk_disable(i2c->clk); + } + + if (timeout <= 0) + { + spacemit_i2c_bus_reset(i2c); + rt_hw_us_delay(100); + res = -RT_ETIMEOUT; + goto _out; + } + + /* Process i2c error */ + if (i2c->i2c_err) + { + res = -RT_EIO; + } + +_out: + xfer_try++; + /* Retry i2c transfer 3 times for timeout and bus busy */ + if ((res == -RT_ETIMEOUT || res == -RT_EIO) && xfer_try <= i2c->drv_retries) + { + rt_hw_us_delay(150); + res = 0; + goto _xfer_retry; + } + + return res < 0 ? res : i2c->num; +} + +static rt_ssize_t spacemit_i2c_xfer(struct rt_i2c_bus_device *bus, + struct rt_i2c_msg msgs[], rt_uint32_t num) +{ + int xfer_try = 0; + rt_ssize_t res = 0; + rt_bool_t clk_directly = RT_FALSE; + struct spacemit_i2c *i2c = raw_to_spacemit_i2c(bus); + + i2c->msgs = msgs; + i2c->num = num; + +_xfer_retry: + /* If unit keeps the last control status, don't need to do reset */ + if (spacemit_i2c_read(i2c, REG_CR) != i2c->i2c_ctrl_reg_value) + { + /* Controller & bus reset */ + spacemit_i2c_reset(i2c); + } + + /* Choose transfer mode */ + spacemit_i2c_choose_xfer_mode(i2c); + + /* Unit init */ + spacemit_i2c_unit_init(i2c); + + /* Clear all interrupt status */ + spacemit_i2c_clear_int_status(i2c, SPACEMIT_I2C_INT_STATUS_MASK); + + spacemit_i2c_init_xfer_params(i2c); + + res = spacemit_i2c_read(i2c, REG_RST_CYC); + spacemit_i2c_write(i2c, REG_RST_CYC, I2C_SDA_GLITCH_FIX_BYPASS | res); + + spacemit_i2c_mark_rw_flag(i2c); + + spacemit_i2c_enable(i2c); + + /* Wait for bus busy */ + if ((res = spacemit_i2c_recover_bus_busy(i2c))) + { + goto _err_recover; + } + + /* Msg transmit */ + if (i2c->xfer_mode == SPACEMIT_I2C_MODE_INTERRUPT) + { + res = spacemit_i2c_byte_xfer(i2c); + } + else if (i2c->xfer_mode == SPACEMIT_I2C_MODE_FIFO) + { + res = spacemit_i2c_fifo_xfer(i2c); + } + else + { + /* DMA */ + res = -RT_ENOSYS; + } + + if (res < 0) + { + if (res != -RT_ETIMEOUT) + { + res = -RT_EINVAL; + } + goto _err_xfer; + } + + if (i2c->xfer_mode == SPACEMIT_I2C_MODE_INTERRUPT) + { + if ((res = rt_completion_wait(&i2c->complete, i2c->timeout))) + { + spacemit_i2c_bus_reset(i2c); + spacemit_i2c_reset(i2c); + goto _timeout_xfex; + } + } + +_err_xfer: + if (!res) + { + spacemit_i2c_check_bus_release(i2c); + } + +_err_recover: +_timeout_xfex: + /* Disable spacemit i2c */ + spacemit_i2c_disable(i2c); + + /* Process i2c error */ + if (i2c->i2c_err) + { + if (i2c->i2c_err & (SR_BED | SR_ALD)) + { + spacemit_i2c_reset(i2c); + } + + /* Try transfer again */ + if (i2c->i2c_err & (SR_RXOV | SR_ALD)) + { + spacemit_i2c_flush_fifo_buffer(i2c); + } + + res = -RT_EIO; + } + + xfer_try++; + /* Retry i2c transfer 3 times for timeout and bus busy */ + if ((res == -RT_ETIMEOUT || res == -RT_EIO) && xfer_try <= i2c->drv_retries) + { + rt_hw_us_delay(175); + res = 0; + goto _xfer_retry; + } + + if (clk_directly) + { + /* If clock is enabled directly, here disable it */ + rt_clk_disable(i2c->clk); + } + + return res < 0 ? res : num; +} + +const static struct rt_i2c_bus_device_ops spacemit_i2c_ops = +{ + .master_xfer = spacemit_i2c_xfer, +}; + +static void spacemit_i2c_isr(int irq, void *param) +{ + rt_ssize_t res = 0; + rt_uint32_t status, ctrl; + struct spacemit_i2c *i2c = param; + + /* Record i2c status */ + status = spacemit_i2c_read(i2c, REG_SR); + i2c->i2c_status = status; + + /* Check if a valid interrupt status */ + if (!status) + { + return; + } + + /* Bus error, rx overrun, arbitration lost */ + i2c->i2c_err = status & (SR_BED | SR_RXOV | SR_ALD); + + /* Clear interrupt status bits[31:18]*/ + spacemit_i2c_clear_int_status(i2c, status); + + /* Error happens */ + if (i2c->i2c_err) + { + goto _err_out; + } + + /* Process interrupt mode */ + if (i2c->xfer_mode == SPACEMIT_I2C_MODE_INTERRUPT) + { + res = spacemit_i2c_byte_xfer(i2c); + } + +_err_out: + /* Send transaction complete signal: error happens, detect master stop */ + if (i2c->i2c_err || res < 0 || (status & SR_MSD)) + { + /* + * Here the transaction is already done, we don't need any + * other interrupt signals from now, in case any interrupt + * happens before spacemit_i2c_xfer to disable irq and i2c unit, + * we mask all the interrupt signals and clear the interrupt status. + */ + ctrl = spacemit_i2c_read(i2c, REG_CR); + ctrl &= ~SPACEMIT_I2C_INT_CTRL_MASK; + spacemit_i2c_write(i2c, REG_CR, ctrl); + + spacemit_i2c_clear_int_status(i2c, SPACEMIT_I2C_INT_STATUS_MASK); + + rt_completion_done(&i2c->complete); + } +} + +static void spacemit_i2c_free(struct spacemit_i2c *i2c, struct rt_device *dev) +{ + if (i2c->regs) + { + rt_iounmap(i2c->regs); + } + + if (!rt_is_err_or_null(i2c->rstc)) + { + rt_reset_control_assert(i2c->rstc); + rt_reset_control_put(i2c->rstc); + } + + if (!rt_is_err_or_null(i2c->clk)) + { + rt_clk_disable_unprepare(i2c->clk); + rt_clk_put(i2c->clk); + } + + rt_free(i2c); +} + +static rt_err_t spacemit_i2c_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + const char *dev_name; + struct rt_device *dev = &pdev->parent; + struct spacemit_i2c *i2c = rt_calloc(1, sizeof(*i2c)); + + if (!i2c) + { + return -RT_ENOMEM; + } + + i2c->regs = rt_dm_dev_iomap(dev, 0); + if (!i2c->regs) + { + err = -RT_EIO; + goto _fail; + } + + i2c->irq = rt_dm_dev_get_irq(dev, 0); + if (i2c->irq < 0) + { + err = i2c->irq; + goto _fail; + } + + i2c->rstc = rt_reset_control_get_by_index(dev, 0); + if (rt_is_err(i2c->rstc)) + { + goto _fail; + } + + /* Reset the i2c controller */ + rt_reset_control_assert(i2c->rstc); + rt_hw_us_delay(200); + rt_reset_control_deassert(i2c->rstc); + + /* Enable fast speed mode */ + i2c->fast_mode = rt_dm_dev_prop_read_bool(dev, "spacemit,i2c-fast-mode"); + /* Enable high speed mode */ + i2c->high_mode = rt_dm_dev_prop_read_bool(dev, "spacemit,i2c-high-mode"); + + if (i2c->high_mode) + { + /* Get master code for high speed mode */ + if (rt_dm_dev_prop_read_u8(dev, "spacemit,i2c-master-code", &i2c->master_code)) + { + i2c->master_code = 0x0e; + LOG_W("Failed to get i2c master code, use default: %#x", i2c->master_code); + } + } + + if ((err = rt_dm_dev_prop_read_u32(dev, "spacemit,i2c-clk-rate", &i2c->clk_rate))) + { + goto _fail; + } + + if ((err = rt_dm_dev_prop_read_u32(dev, "spacemit,i2c-lcr", &i2c->i2c_lcr))) + { + goto _fail; + } + + if ((err = rt_dm_dev_prop_read_u32(dev, "spacemit,i2c-wcr", &i2c->i2c_wcr))) + { + goto _fail; + } + + if ((err = rt_dm_dev_prop_read_u32(dev, "spacemit,adapter-id", (rt_uint32_t *)&pdev->dev_id))) + { + pdev->dev_id = -1; + } + + /* Disable DMA transfer mode, default: interrupt mode */ + i2c->dma_disable = RT_TRUE; + i2c->xfer_mode = i2c->dma_disable ? SPACEMIT_I2C_MODE_INTERRUPT : SPACEMIT_I2C_MODE_DMA; + + i2c->drv_retries = 3; + + /* The clock will always on and not use runtime mechanism */ + i2c->clk_always_on = rt_dm_dev_prop_read_bool(dev, "spacemit,clk-always-on"); + + /* APB clock: 26MHz or 52MHz */ + if ((err = rt_dm_dev_prop_read_u32(dev, "spacemit,apb_clock", &i2c->apb_clock))) + { + goto _fail; + } + else if (i2c->apb_clock != SPACEMIT_I2C_APB_CLOCK_26M && + i2c->apb_clock != SPACEMIT_I2C_APB_CLOCK_52M) + { + err = -RT_EINVAL; + goto _fail; + } + + i2c->clk = rt_clk_get_by_index(dev, 0); + if (rt_is_err(i2c->clk)) + { + err = rt_ptr_err(i2c->clk); + goto _fail; + } + rt_clk_prepare_enable(i2c->clk); + + rt_completion_init(&i2c->complete); + rt_spin_lock_init(&i2c->fifo_lock); + + if (pdev->dev_id >= 0) + { + rt_dm_dev_set_name(&i2c->parent.parent, "i2c%d", pdev->dev_id); + } + else + { + rt_dm_dev_set_name_auto(&i2c->parent.parent, "i2c"); + } + dev_name = rt_dm_dev_get_name(&i2c->parent.parent); + + rt_hw_interrupt_install(i2c->irq, spacemit_i2c_isr, i2c, dev_name); + rt_hw_interrupt_umask(i2c->irq); + + dev->user_data = i2c; + + i2c->parent.ops = &spacemit_i2c_ops; + i2c->parent.parent.ofw_node = dev->ofw_node; + + if ((err = rt_i2c_bus_device_register(&i2c->parent, dev_name))) + { + goto _free_irq; + } + + rt_dm_dev_bind_fwdata(dev, RT_NULL, i2c); + + return RT_EOK; + +_free_irq: + rt_hw_interrupt_mask(i2c->irq); + rt_pic_detach_irq(i2c->irq, i2c); + +_fail: + spacemit_i2c_free(i2c, dev); + + return err; +} + +static rt_err_t spacemit_i2c_remove(struct rt_platform_device *pdev) +{ + struct rt_device *dev = &pdev->parent; + struct spacemit_i2c *i2c = dev->user_data; + + rt_hw_interrupt_mask(i2c->irq); + rt_pic_detach_irq(i2c->irq, i2c); + + rt_device_unregister(&i2c->parent.parent); + + spacemit_i2c_free(i2c, dev); + + return RT_EOK; +} + +static const struct rt_ofw_node_id spacemit_i2c_ofw_ids[] = +{ + { .compatible = "spacemit,k1x-i2c" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver spacemit_i2c_driver = +{ + .name = "spacemit-k1x-i2c", + .ids = spacemit_i2c_ofw_ids, + + .probe = spacemit_i2c_probe, + .remove = spacemit_i2c_remove, +}; +RT_PLATFORM_DRIVER_EXPORT(spacemit_i2c_driver); diff --git a/bsp/spacemit/dm/include/dt-bindings/clock/k1x.h b/bsp/spacemit/dm/include/dt-bindings/clock/k1x.h new file mode 100644 index 000000000000..9e2a5e0f8000 --- /dev/null +++ b/bsp/spacemit/dm/include/dt-bindings/clock/k1x.h @@ -0,0 +1,242 @@ +/* + * Copyright (c) 2006-2025, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __DT_BINDINGS_CLOCK_K1X_H__ +#define __DT_BINDINGS_CLOCK_K1X_H__ + +#define CLK_PLL2 0 +#define CLK_PLL3 1 +#define CLK_PLL1_D2 2 +#define CLK_PLL1_D3 3 +#define CLK_PLL1_D4 4 +#define CLK_PLL1_D5 5 +#define CLK_PLL1_D6 6 +#define CLK_PLL1_D7 7 +#define CLK_PLL1_D8 8 +#define CLK_PLL1_D11 9 +#define CLK_PLL1_D13 10 +#define CLK_PLL1_D23 11 +#define CLK_PLL1_D64 12 +#define CLK_PLL1_D10_AUD 13 +#define CLK_PLL1_D100_AUD 14 +#define CLK_PLL2_D1 15 +#define CLK_PLL2_D2 16 +#define CLK_PLL2_D3 17 +#define CLK_PLL2_D4 18 +#define CLK_PLL2_D5 19 +#define CLK_PLL2_D6 20 +#define CLK_PLL2_D7 21 +#define CLK_PLL2_D8 22 +#define CLK_PLL3_D1 23 +#define CLK_PLL3_D2 24 +#define CLK_PLL3_D3 25 +#define CLK_PLL3_D4 26 +#define CLK_PLL3_D5 27 +#define CLK_PLL3_D6 28 +#define CLK_PLL3_D7 29 +#define CLK_PLL3_D8 30 +#define CLK_PLL1_307P2 31 +#define CLK_PLL1_76P8 32 +#define CLK_PLL1_61P44 33 +#define CLK_PLL1_153P6 34 +#define CLK_PLL1_102P4 35 +#define CLK_PLL1_51P2 36 +#define CLK_PLL1_51P2_AP 37 +#define CLK_PLL1_57P6 38 +#define CLK_PLL1_25P6 39 +#define CLK_PLL1_12P8 40 +#define CLK_PLL1_12P8_WDT 41 +#define CLK_PLL1_6P4 42 +#define CLK_PLL1_3P2 43 +#define CLK_PLL1_1P6 44 +#define CLK_PLL1_0P8 45 +#define CLK_PLL1_351 46 +#define CLK_PLL1_409P6 47 +#define CLK_PLL1_204P8 48 +#define CLK_PLL1_491 49 +#define CLK_PLL1_245P76 50 +#define CLK_PLL1_614 51 +#define CLK_PLL1_47P26 52 +#define CLK_PLL1_31P5 53 +#define CLK_PLL1_819 54 +#define CLK_PLL1_1228 55 +#define CLK_SLOW_UART1 56 +#define CLK_SLOW_UART2 57 +#define CLK_UART1 58 +#define CLK_UART2 59 +#define CLK_UART3 60 +#define CLK_UART4 61 +#define CLK_UART5 62 +#define CLK_UART6 63 +#define CLK_UART7 64 +#define CLK_UART8 65 +#define CLK_UART9 66 +#define CLK_GPIO 67 +#define CLK_PWM0 68 +#define CLK_PWM1 69 +#define CLK_PWM2 70 +#define CLK_PWM3 71 +#define CLK_PWM4 72 +#define CLK_PWM5 73 +#define CLK_PWM6 74 +#define CLK_PWM7 75 +#define CLK_PWM8 76 +#define CLK_PWM9 77 +#define CLK_PWM10 78 +#define CLK_PWM11 79 +#define CLK_PWM12 80 +#define CLK_PWM13 81 +#define CLK_PWM14 82 +#define CLK_PWM15 83 +#define CLK_PWM16 84 +#define CLK_PWM17 85 +#define CLK_PWM18 86 +#define CLK_PWM19 87 +#define CLK_SSP3 88 +#define CLK_RTC 89 +#define CLK_TWSI0 90 +#define CLK_TWSI1 91 +#define CLK_TWSI2 92 +#define CLK_TWSI4 93 +#define CLK_TWSI5 94 +#define CLK_TWSI6 95 +#define CLK_TWSI7 96 +#define CLK_TWSI8 97 +#define CLK_TIMERS1 98 +#define CLK_TIMERS2 99 +#define CLK_AIB 100 +#define CLK_ONEWIRE 101 +#define CLK_SSPA0 102 +#define CLK_SSPA1 103 +#define CLK_DRO 104 +#define CLK_IR 105 +#define CLK_TSEN 106 +#define CLK_IPC_AP2AUD 107 +#define CLK_CAN0 108 +#define CLK_CAN0_BUS 109 +#define CLK_WDT 110 +#define CLK_RIPC 111 +#define CLK_JPG 112 +#define CLK_JPF_4KAFBC 113 +#define CLK_JPF_2KAFBC 114 +#define CLK_CCIC2PHY 115 +#define CLK_CCIC3PHY 116 +#define CLK_CSI 117 +#define CLK_CAMM0 118 +#define CLK_CAMM1 119 +#define CLK_CAMM2 120 +#define CLK_ISP_CPP 121 +#define CLK_ISP_BUS 122 +#define CLK_ISP 123 +#define CLK_DPU_MCLK 124 +#define CLK_DPU_ESC 125 +#define CLK_DPU_BIT 126 +#define CLK_DPU_PXCLK 127 +#define CLK_DPU_HCLK 128 +#define CLK_DPU_SPI 129 +#define CLK_DPU_SPI_HBUS 130 +#define CLK_DPU_SPIBUS 131 +#define CLK_SPU_SPI_ACLK 132 +#define CLK_V2D 133 +#define CLK_CCIC_4X 134 +#define CLK_CCIC1PHY 135 +#define CLK_SDH_AXI 136 +#define CLK_SDH0 137 +#define CLK_SDH1 138 +#define CLK_SDH2 139 +#define CLK_USB_P1 140 +#define CLK_USB_AXI 141 +#define CLK_USB30 142 +#define CLK_QSPI 143 +#define CLK_QSPI_BUS 144 +#define CLK_DMA 145 +#define CLK_AES 146 +#define CLK_VPU 147 +#define CLK_GPU 148 +#define CLK_EMMC 149 +#define CLK_EMMC_X 150 +#define CLK_AUDIO 151 +#define CLK_HDMI 152 +#define CLK_CCI550 153 +#define CLK_PMUA_ACLK 154 +#define CLK_CPU_C0_HI 155 +#define CLK_CPU_C0_CORE 156 +#define CLK_CPU_C0_ACE 157 +#define CLK_CPU_C0_TCM 158 +#define CLK_CPU_C1_HI 159 +#define CLK_CPU_C1_CORE 160 +#define CLK_CPU_C1_ACE 161 +#define CLK_PCIE0 162 +#define CLK_PCIE1 163 +#define CLK_PCIE2 164 +#define CLK_EMAC0_BUS 165 +#define CLK_EMAC0_PTP 166 +#define CLK_EMAC1_BUS 167 +#define CLK_EMAC1_PTP 168 + +#define CLK_SEC_UART1 169 +#define CLK_SEC_SSP2 170 +#define CLK_SEC_TWSI3 171 +#define CLK_SEC_RTC 172 +#define CLK_SEC_TIMERS0 173 +#define CLK_SEC_KPC 174 +#define CLK_SEC_GPIO 175 + +#define CLK_APB 176 + +#define CLK_PLL3_80 177 +#define CLK_PLL3_40 178 +#define CLK_PLL3_20 179 + +#define CLK_SLOW_UART 180 + +#define CLK_I2S_SYSCLK 181 +#define CLK_I2S_BCLK 182 +#define CLK_RCPU_HDMIAUDIO 183 +#define CLK_RCPU_CAN 184 +#define CLK_RCPU_CAN_BUS 185 + +#define CLK_RCPU_I2C0 186 +#define CLK_RCPU_SSP0 187 +#define CLK_RCPU_IR 188 +#define CLK_RCPU_UART0 189 +#define CLK_RCPU_UART1 190 + +#define CLK_DPLL1 191 +#define CLK_DPLL2 192 + +#define CLK_DFC_LVL0 193 +#define CLK_DFC_LVL1 194 +#define CLK_DFC_LVL2 195 +#define CLK_DFC_LVL3 196 +#define CLK_DFC_LVL4 197 +#define CLK_DFC_LVL5 198 +#define CLK_DFC_LVL6 199 +#define CLK_DFC_LVL7 200 +#define CLK_DDR 201 + +#define CLK_RCPU2_PWM0 202 +#define CLK_RCPU2_PWM1 203 +#define CLK_RCPU2_PWM2 204 +#define CLK_RCPU2_PWM3 205 +#define CLK_RCPU2_PWM4 206 +#define CLK_RCPU2_PWM5 207 +#define CLK_RCPU2_PWM6 208 +#define CLK_RCPU2_PWM7 209 +#define CLK_RCPU2_PWM8 210 +#define CLK_RCPU2_PWM9 211 + +#define CLK_AUDIO_APB 212 +#define CLK_AUDIO_AXI 213 + +#define CLK_PM_MN_SRC 214 +#define CLK_PM_MN 215 +#define CLK_PM_MN2_SRC 216 +#define CLK_PM_MN2 217 + +#define CLK_MAX_NO 218 + +#endif /* __DT_BINDINGS_CLOCK_K1X_H__ */ diff --git a/bsp/spacemit/dm/include/dt-bindings/pinctrl/k1x.h b/bsp/spacemit/dm/include/dt-bindings/pinctrl/k1x.h new file mode 100644 index 000000000000..101fcba595d7 --- /dev/null +++ b/bsp/spacemit/dm/include/dt-bindings/pinctrl/k1x.h @@ -0,0 +1,211 @@ +/* + * Copyright (c) 2006-2025, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __DT_BINDINGS_PINCTRL_K1X_H__ +#define __DT_BINDINGS_PINCTRL_K1X_H__ + +/* Pin offset */ +#define PINID(x) ((x) + 1) + +#define GPIO_00 PINID(0) +#define GPIO_01 PINID(1) +#define GPIO_02 PINID(2) +#define GPIO_03 PINID(3) +#define GPIO_04 PINID(4) +#define GPIO_05 PINID(5) +#define GPIO_06 PINID(6) +#define GPIO_07 PINID(7) +#define GPIO_08 PINID(8) +#define GPIO_09 PINID(9) +#define GPIO_10 PINID(10) +#define GPIO_11 PINID(11) +#define GPIO_12 PINID(12) +#define GPIO_13 PINID(13) +#define GPIO_14 PINID(14) +#define GPIO_15 PINID(15) +#define GPIO_16 PINID(16) +#define GPIO_17 PINID(17) +#define GPIO_18 PINID(18) +#define GPIO_19 PINID(19) +#define GPIO_20 PINID(20) +#define GPIO_21 PINID(21) +#define GPIO_22 PINID(22) +#define GPIO_23 PINID(23) +#define GPIO_24 PINID(24) +#define GPIO_25 PINID(25) +#define GPIO_26 PINID(26) +#define GPIO_27 PINID(27) +#define GPIO_28 PINID(28) +#define GPIO_29 PINID(29) +#define GPIO_30 PINID(30) +#define GPIO_31 PINID(31) + +#define GPIO_32 PINID(32) +#define GPIO_33 PINID(33) +#define GPIO_34 PINID(34) +#define GPIO_35 PINID(35) +#define GPIO_36 PINID(36) +#define GPIO_37 PINID(37) +#define GPIO_38 PINID(38) +#define GPIO_39 PINID(39) +#define GPIO_40 PINID(40) +#define GPIO_41 PINID(41) +#define GPIO_42 PINID(42) +#define GPIO_43 PINID(43) +#define GPIO_44 PINID(44) +#define GPIO_45 PINID(45) +#define GPIO_46 PINID(46) +#define GPIO_47 PINID(47) +#define GPIO_48 PINID(48) +#define GPIO_49 PINID(49) +#define GPIO_50 PINID(50) +#define GPIO_51 PINID(51) +#define GPIO_52 PINID(52) +#define GPIO_53 PINID(53) +#define GPIO_54 PINID(54) +#define GPIO_55 PINID(55) +#define GPIO_56 PINID(56) +#define GPIO_57 PINID(57) +#define GPIO_58 PINID(58) +#define GPIO_59 PINID(59) +#define GPIO_60 PINID(60) +#define GPIO_61 PINID(61) +#define GPIO_62 PINID(62) +#define GPIO_63 PINID(63) + +#define GPIO_64 PINID(64) +#define GPIO_65 PINID(65) +#define GPIO_66 PINID(66) +#define GPIO_67 PINID(67) +#define GPIO_68 PINID(68) +#define GPIO_69 PINID(69) +#define PRI_TDI PINID(70) +#define PRI_TMS PINID(71) +#define PRI_TCK PINID(72) +#define PRI_TDO PINID(73) +#define GPIO_74 PINID(74) +#define GPIO_75 PINID(75) +#define GPIO_76 PINID(76) +#define GPIO_77 PINID(77) +#define GPIO_78 PINID(78) +#define GPIO_79 PINID(79) +#define GPIO_80 PINID(80) +#define GPIO_81 PINID(81) +#define GPIO_82 PINID(82) +#define GPIO_83 PINID(83) +#define GPIO_84 PINID(84) +#define GPIO_85 PINID(85) + +#define QSPI_DAT0 PINID(89) +#define QSPI_DAT1 PINID(90) +#define QSPI_DAT2 PINID(91) +#define QSPI_DAT3 PINID(92) +#define QSPI_CSI PINID(93) +#define QSPI_CLK PINID(94) + +#define MMC1_DAT3 PINID(109) +#define MMC1_DAT2 PINID(110) +#define MMC1_DAT1 PINID(111) +#define MMC1_DAT0 PINID(112) +#define MMC1_CMD PINID(113) +#define MMC1_CLK PINID(114) +#define GPIO_110 PINID(115) +#define PWR_SCL PINID(116) +#define PWR_SDA PINID(117) +#define VCXO_EN PINID(118) +#define DVL0 PINID(119) +#define DVL1 PINID(120) +#define PMIC_INT_N PINID(121) +#define GPIO_86 PINID(122) +#define GPIO_87 PINID(123) +#define GPIO_88 PINID(124) +#define GPIO_89 PINID(125) +#define GPIO_90 PINID(126) +#define GPIO_91 PINID(127) +#define GPIO_92 PINID(128) + +#define GPIO_111 PINID(130) +#define GPIO_112 PINID(131) +#define GPIO_113 PINID(132) +#define GPIO_114 PINID(133) +#define GPIO_115 PINID(134) +#define GPIO_116 PINID(135) +#define GPIO_117 PINID(136) +#define GPIO_118 PINID(137) +#define GPIO_119 PINID(138) +#define GPIO_120 PINID(139) +#define GPIO_121 PINID(140) +#define GPIO_122 PINID(141) +#define GPIO_123 PINID(142) +#define GPIO_124 PINID(143) +#define GPIO_125 PINID(144) +#define GPIO_126 PINID(145) +#define GPIO_127 PINID(146) + +#define EMMC_D0 PINID(147) +#define EMMC_D1 PINID(148) +#define EMMC_D2 PINID(149) +#define EMMC_D3 PINID(150) +#define EMMC_D4 PINID(151) +#define EMMC_D5 PINID(152) +#define EMMC_D6 PINID(153) +#define EMMC_D7 PINID(154) +#define EMMC_DS PINID(155) +#define EMMC_CLK PINID(156) +#define EMMC_CMD PINID(157) + +/* Pin mux */ +#define MUX_MODE0 0 +#define MUX_MODE1 1 +#define MUX_MODE2 2 +#define MUX_MODE3 3 +#define MUX_MODE4 4 +#define MUX_MODE5 5 +#define MUX_MODE6 6 +#define MUX_MODE7 7 + +/* Strong pull resistor */ +#define SPU_EN (1 << 3) + +/* Edge detect */ +#define EDGE_NONE (1 << 6) +#define EDGE_RISE (1 << 4) +#define EDGE_FALL (1 << 5) +#define EDGE_BOTH (3 << 4) + +/* Slew rate output control */ +#define SLE_EN (1 << 7) + +/* Schmitter trigger input threshhold */ +#define ST00 (0 << 8) +#define ST01 (1 << 8) +#define ST02 (2 << 8) +#define ST03 (3 << 8) + +/* Driver strength*/ +#define PAD_1V8_DS0 (0 << 11) +#define PAD_1V8_DS1 (1 << 11) +#define PAD_1V8_DS2 (2 << 11) +#define PAD_1V8_DS3 (3 << 11) + +/* Ds2 ---> bit10, ds1 ----> bit12, ds0 ----> bit11 */ +#define PAD_3V_DS0 (0 << 10) /* bit[12:10] 000 */ +#define PAD_3V_DS1 (2 << 10) /* bit[12:10] 010 */ +#define PAD_3V_DS2 (4 << 10) /* bit[12:10] 100 */ +#define PAD_3V_DS3 (6 << 10) /* bit[12:10] 110 */ +#define PAD_3V_DS4 (1 << 10) /* bit[12:10] 001 */ +#define PAD_3V_DS5 (3 << 10) /* bit[12:10] 011 */ +#define PAD_3V_DS6 (5 << 10) /* bit[12:10] 101 */ +#define PAD_3V_DS7 (7 << 10) /* bit[12:10] 111 */ + +/* Pull up/down */ +#define PULL_DIS (0 << 13) /* bit[15:13] 000 */ +#define PULL_UP (6 << 13) /* bit[15:13] 110 */ +#define PULL_DOWN (5 << 13) /* bit[15:13] 101 */ + +#define K1X_PADCONF(pinid, conf, mux) ((pinid) * 4) (conf) (mux) + +#endif /* __DT_BINDINGS_PINCTRL_K1X_H__ */ diff --git a/bsp/spacemit/dm/include/dt-bindings/power/k1x_pmu.h b/bsp/spacemit/dm/include/dt-bindings/power/k1x_pmu.h new file mode 100644 index 000000000000..7281265d26cf --- /dev/null +++ b/bsp/spacemit/dm/include/dt-bindings/power/k1x_pmu.h @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2006-2025, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __DT_BINDINGS_POWER_K1X_PMU_H__ +#define __DT_BINDINGS_POWER_K1X_PMU_H__ + +#define K1X_PMU_BUS_PWR_DOMAIN 0 +#define K1X_PMU_VPU_PWR_DOMAIN 1 +#define K1X_PMU_GPU_PWR_DOMAIN 2 +#define K1X_PMU_LCD_PWR_DOMAIN 3 +#define K1X_PMU_ISP_PWR_DOMAIN 4 +#define K1X_PMU_AUD_PWR_DOMAIN 5 +#define K1X_PMU_GNSS_PWR_DOMAIN 6 +#define K1X_PMU_HDMI_PWR_DOMAIN 7 +#define K1X_PMU_DUMMY_PWR_DOMAIN 8 + +#endif /* __DT_BINDINGS_POWER_K1X_PMU_H__ */ diff --git a/bsp/spacemit/dm/include/dt-bindings/reset/k1x.h b/bsp/spacemit/dm/include/dt-bindings/reset/k1x.h new file mode 100644 index 000000000000..5c9164a4a5a9 --- /dev/null +++ b/bsp/spacemit/dm/include/dt-bindings/reset/k1x.h @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2006-2025, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __DT_BINDINGS_RESET_K1X_H__ +#define __DT_BINDINGS_RESET_K1X_H__ + +/* APBC */ +#define RESET_UART1 1 +#define RESET_UART2 2 +#define RESET_GPIO 3 +#define RESET_PWM0 4 +#define RESET_PWM1 5 +#define RESET_PWM2 6 +#define RESET_PWM3 7 +#define RESET_PWM4 8 +#define RESET_PWM5 9 +#define RESET_PWM6 10 +#define RESET_PWM7 11 +#define RESET_PWM8 12 +#define RESET_PWM9 13 +#define RESET_PWM10 14 +#define RESET_PWM11 15 +#define RESET_PWM12 16 +#define RESET_PWM13 17 +#define RESET_PWM14 18 +#define RESET_PWM15 19 +#define RESET_PWM16 20 +#define RESET_PWM17 21 +#define RESET_PWM18 22 +#define RESET_PWM19 23 +#define RESET_SSP3 24 +#define RESET_UART3 25 +#define RESET_RTC 26 +#define RESET_TWSI0 27 + +#define RESET_TIMERS1 28 +#define RESET_AIB 29 +#define RESET_TIMERS2 30 +#define RESET_ONEWIRE 31 +#define RESET_SSPA0 32 +#define RESET_SSPA1 33 +#define RESET_DRO 34 +#define RESET_IR 35 +#define RESET_TWSI1 36 + +#define RESET_TSEN 37 +#define RESET_TWSI2 38 +#define RESET_TWSI4 39 +#define RESET_TWSI5 40 +#define RESET_TWSI6 41 +#define RESET_TWSI7 42 +#define RESET_TWSI8 43 +#define RESET_IPC_AP2AUD 44 +#define RESET_UART4 45 +#define RESET_UART5 46 +#define RESET_UART6 47 +#define RESET_UART7 48 +#define RESET_UART8 49 +#define RESET_UART9 50 +#define RESET_CAN0 51 + +/* MPMU */ +#define RESET_WDT 52 + +/* APMU */ +#define RESET_JPG 53 +#define RESET_CSI 54 +#define RESET_CCIC2_PHY 55 +#define RESET_CCIC3_PHY 56 +#define RESET_ISP 57 +#define RESET_ISP_AHB 58 +#define RESET_ISP_CI 59 +#define RESET_ISP_CPP 60 +#define RESET_LCD 61 +#define RESET_DSI_ESC 62 +#define RESET_V2D 63 +#define RESET_MIPI 64 +#define RESET_LCD_SPI 65 +#define RESET_LCD_SPI_BUS 66 +#define RESET_LCD_SPI_HBUS 67 +#define RESET_LCD_MCLK 68 +#define RESET_CCIC_4X 69 +#define RESET_CCIC1_PHY 70 +#define RESET_SDH_AXI 71 +#define RESET_SDH0 72 +#define RESET_SDH1 73 +#define RESET_USB_AXI 74 +#define RESET_USBP1_AXI 75 +#define RESET_USB3_0 76 +#define RESET_QSPI 77 +#define RESET_QSPI_BUS 78 +#define RESET_DMA 79 +#define RESET_AES 80 +#define RESET_VPU 81 +#define RESET_GPU 82 +#define RESET_SDH2 83 +#define RESET_MC 84 +#define RESET_EM_AXI 85 +#define RESET_EM 86 +#define RESET_AUDIO_SYS 87 +#define RESET_HDMI 88 +#define RESET_PCIE0 89 +#define RESET_PCIE1 90 +#define RESET_PCIE2 91 +#define RESET_EMAC0 92 +#define RESET_EMAC1 93 + +/* APBC2 */ +#define RESET_SEC_UART1 94 +#define RESET_SEC_SSP2 95 +#define RESET_SEC_TWSI3 96 +#define RESET_SEC_RTC 97 +#define RESET_SEC_TIMERS0 98 +#define RESET_SEC_KPC 99 +#define RESET_SEC_GPIO 100 + +#define RESET_RCPU_HDMIAUDIO 101 +#define RESET_RCPU_CAN 102 + +#define RESET_RCPU_I2C0 103 +#define RESET_RCPU_SSP0 104 +#define RESET_RCPU_IR 105 +#define RESET_RCPU_UART0 106 +#define RESET_RCPU_UART1 107 + +#define RESET_RCPU2_PWM0 108 +#define RESET_RCPU2_PWM1 109 +#define RESET_RCPU2_PWM2 110 +#define RESET_RCPU2_PWM3 111 +#define RESET_RCPU2_PWM4 112 +#define RESET_RCPU2_PWM5 113 +#define RESET_RCPU2_PWM6 114 +#define RESET_RCPU2_PWM7 115 +#define RESET_RCPU2_PWM8 116 +#define RESET_RCPU2_PWM9 117 + +#define RESET_NUMBER 118 + +#endif /* __DT_BINDINGS_RESET_K1X_H__ */ diff --git a/bsp/spacemit/dm/include/firmware-spacemit.h b/bsp/spacemit/dm/include/firmware-spacemit.h new file mode 100644 index 000000000000..54379e1211fd --- /dev/null +++ b/bsp/spacemit/dm/include/firmware-spacemit.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#ifndef __FIRMWARE_SPACEMIT_H__ +#define __FIRMWARE_SPACEMIT_H__ + +#ifdef __ASSEMBLY__ +#include + +.macro SPACEMIT_FIRMWARE_DEFINE name + .align RISCV_SZPTR +firmware_\name: + .ascii "\name" "\0" +firmware_\name\()_start: + .incbin "\name" +firmware_\name\()_end: +.endm + +.macro SPACEMIT_FIRMWARE_REF name + RISCV_PTR firmware_\name + RISCV_PTR firmware_\name\()_start + RISCV_PTR firmware_\name\()_end +.endm + +.macro SPACEMIT_FIRMWARE_START + .align RISCV_SZPTR + .globl spacemit_firmwares_start +spacemit_firmwares_start: +.endm + +.macro SPACEMIT_FIRMWARE_END + .globl spacemit_firmwares_end +spacemit_firmwares_end: +.endm +#else +#include + +rt_bool_t spacemit_firmware_find(const char *name, rt_ubase_t *out_base, rt_size_t *out_size); +rt_err_t spacemit_firmware_load_elf(const char *name, rt_ubase_t phy_addr); + +#endif /* __ASSEMBLY__ */ + +#endif /* __FIRMWARE_SPACEMIT_H__ */ diff --git a/bsp/spacemit/dm/include/jpu.h b/bsp/spacemit/dm/include/jpu.h new file mode 100644 index 000000000000..fe648df5af42 --- /dev/null +++ b/bsp/spacemit/dm/include/jpu.h @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#ifndef __JPU_H__ +#define __JPU_H__ + +#include +#include + +#define JPU_NAME "jpu" +#define JPU_BUFFER_MAX_SIZE (32U * 1024U * 1024U) +#define JPU_STREAM_PADDING 1024U + +#define JPU_HUFF_TABLE_NUM 4 +#define JPU_HUFF_BITS_NUM 16 +#define JPU_HUFF_VALUES_NUM 162 +#define JPU_QUANT_COMPONENT_NUM 3 +#define JPU_QUANT_VALUES_NUM 64 + +enum jpu_format +{ + JPU_FORMAT_420 = 0, + JPU_FORMAT_422, + JPU_FORMAT_440, + JPU_FORMAT_444, + JPU_FORMAT_400, +}; + +struct jpu_dec_tables +{ + uint8_t huff_bits[JPU_HUFF_TABLE_NUM][JPU_HUFF_BITS_NUM]; + uint8_t huff_values[JPU_HUFF_TABLE_NUM][JPU_HUFF_VALUES_NUM]; + uint16_t quant[JPU_QUANT_COMPONENT_NUM][JPU_QUANT_VALUES_NUM]; +}; + +struct jpu_buffer +{ + uint32_t size; + uint64_t phys_addr; + void *virt_addr; +}; + +/* + * width, height and format are inputs. The remaining fields are returned by + * JPU_QUERY_FRAME and describe the decoder's planar output buffer. + */ +struct jpu_frame_info +{ + uint16_t width; + uint16_t height; + uint8_t format; + uint8_t reserved[3]; + + uint16_t aligned_width; + uint16_t aligned_height; + uint16_t y_stride; + uint16_t c_stride; + uint16_t c_height; + uint16_t reserved2; + uint32_t size; +}; + +struct jpu_decode_request +{ + struct jpu_frame_info frame; + struct jpu_dec_tables tables; + + uint64_t stream_phys; + uint64_t frame_phys; + uint32_t stream_size; + uint32_t stream_capacity; + uint32_t frame_capacity; + uint32_t entropy_offset; + uint16_t restart_interval; + uint8_t components; + uint8_t dc_selector[3]; + uint8_t ac_selector[3]; + + uint32_t irq_status; + uint32_t picture_status; + uint32_t error_mcu; + uint32_t cycles; +}; + +#define JPU_IOC_MAGIC 'J' + +#define JPU_DECODE _IOWR(JPU_IOC_MAGIC, 0, struct jpu_decode_request) +#define JPU_QUERY_FRAME _IOWR(JPU_IOC_MAGIC, 1, struct jpu_frame_info) +#define JPU_ALLOC_BUFFER _IOWR(JPU_IOC_MAGIC, 2, struct jpu_buffer) +#define JPU_FREE_BUFFER _IOW(JPU_IOC_MAGIC, 3, struct jpu_buffer) +#define JPU_RESET _IO(JPU_IOC_MAGIC, 5) +#define JPU_GET_MMU_VERSION _IOR(JPU_IOC_MAGIC, 7, uint32_t) + +#endif /* __JPU_H__ */ diff --git a/bsp/spacemit/dm/include/k1-cru.h b/bsp/spacemit/dm/include/k1-cru.h new file mode 100644 index 000000000000..d53950633a2c --- /dev/null +++ b/bsp/spacemit/dm/include/k1-cru.h @@ -0,0 +1,232 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#ifndef __K1_CLK_RST_H__ +#define __K1_CLK_RST_H__ + +#include +#include +#include + +/* APBS register offset */ +/* PLL1 */ +#define APB_SPARE1_REG 0x100 +#define APB_SPARE2_REG 0x104 +#define APB_SPARE3_REG 0x108 +/* PLL2 */ +#define APB_SPARE7_REG 0x118 +#define APB_SPARE8_REG 0x11c +#define APB_SPARE9_REG 0x120 +/* PLL3 */ +#define APB_SPARE10_REG 0x124 +#define APB_SPARE11_REG 0x128 +#define APB_SPARE12_REG 0x12c +/* end of APBS register offset */ + +/* APBC register offset */ +#define APBC_UART1_CLK_RST 0x0 +#define APBC_UART2_CLK_RST 0x4 +#define APBC_GPIO_CLK_RST 0x8 +#define APBC_PWM0_CLK_RST 0xc +#define APBC_PWM1_CLK_RST 0x10 +#define APBC_PWM2_CLK_RST 0x14 +#define APBC_PWM3_CLK_RST 0x18 +#define APBC_TWSI8_CLK_RST 0x20 +#define APBC_UART3_CLK_RST 0x24 +#define APBC_RTC_CLK_RST 0x28 +#define APBC_TWSI0_CLK_RST 0x2c +#define APBC_TWSI1_CLK_RST 0x30 +#define APBC_TIMERS1_CLK_RST 0x34 +#define APBC_TWSI2_CLK_RST 0x38 +#define APBC_AIB_CLK_RST 0x3c +#define APBC_TWSI4_CLK_RST 0x40 +#define APBC_TIMERS2_CLK_RST 0x44 +#define APBC_ONEWIRE_CLK_RST 0x48 +#define APBC_TWSI5_CLK_RST 0x4c +#define APBC_DRO_CLK_RST 0x58 +#define APBC_IR_CLK_RST 0x5c +#define APBC_TWSI6_CLK_RST 0x60 +#define APBC_COUNTER_CLK_SEL 0x64 +#define APBC_TWSI7_CLK_RST 0x68 +#define APBC_TSEN_CLK_RST 0x6c + +#define APBC_UART4_CLK_RST 0x70 +#define APBC_UART5_CLK_RST 0x74 +#define APBC_UART6_CLK_RST 0x78 +#define APBC_SSP3_CLK_RST 0x7c + +#define APBC_SSPA0_CLK_RST 0x80 +#define APBC_SSPA1_CLK_RST 0x84 + +#define APBC_IPC_AP2AUD_CLK_RST 0x90 +#define APBC_UART7_CLK_RST 0x94 +#define APBC_UART8_CLK_RST 0x98 +#define APBC_UART9_CLK_RST 0x9c + +#define APBC_CAN0_CLK_RST 0xa0 +#define APBC_PWM4_CLK_RST 0xa8 +#define APBC_PWM5_CLK_RST 0xac +#define APBC_PWM6_CLK_RST 0xb0 +#define APBC_PWM7_CLK_RST 0xb4 +#define APBC_PWM8_CLK_RST 0xb8 +#define APBC_PWM9_CLK_RST 0xbc +#define APBC_PWM10_CLK_RST 0xc0 +#define APBC_PWM11_CLK_RST 0xc4 +#define APBC_PWM12_CLK_RST 0xc8 +#define APBC_PWM13_CLK_RST 0xcc +#define APBC_PWM14_CLK_RST 0xd0 +#define APBC_PWM15_CLK_RST 0xd4 +#define APBC_PWM16_CLK_RST 0xd8 +#define APBC_PWM17_CLK_RST 0xdc +#define APBC_PWM18_CLK_RST 0xe0 +#define APBC_PWM19_CLK_RST 0xe4 +/* End of APBC register offset */ + +/* MPMU register offset */ +#define MPMU_POSR 0x10 +#define POSR_PLL1_LOCK RT_BIT(27) +#define POSR_PLL2_LOCK RT_BIT(28) +#define POSR_PLL3_LOCK RT_BIT(29) + +#define MPMU_VRCR 0x18 +#define MPMU_VRCR_REQ_EN0 RT_BIT(0) +#define MPMU_VRCR_REQ_EN2 RT_BIT(2) +#define MPMU_VRCR_REQ_POL2 RT_BIT(6) +#define MPMU_VRCR_VCXO_OUT_REQ_EN2 RT_BIT(14) + +#define MPMU_WDTPCR 0x200 +#define MPMU_RIPCCR 0x210 +#define MPMU_ACGR 0x1024 +#define MPMU_SUCCR 0x14 +#define MPMU_ISCCR 0x44 +#define MPMU_SUCCR_1 0x10b0 +#define MPMU_APBCSCR 0x1050 + +#define MPMU_PM_MN 0x10a4 +#define MPMU_PM_MN_GPCR2 0x48 +#define MPMU_PM_MN_GPCR 0x30 +/* End of MPMU register offset */ + +/* APMU register offset */ +#define APMU_JPG_CLK_RES_CTRL 0x20 +#define APMU_CSI_CCIC2_CLK_RES_CTRL 0x24 +#define APMU_ISP_CLK_RES_CTRL 0x38 +#define APMU_LCD_CLK_RES_CTRL1 0x44 +#define APMU_LCD_SPI_CLK_RES_CTRL 0x48 +#define APMU_LCD_CLK_RES_CTRL2 0x4c +#define APMU_CCIC_CLK_RES_CTRL 0x50 +#define APMU_SDH0_CLK_RES_CTRL 0x54 +#define APMU_SDH1_CLK_RES_CTRL 0x58 +#define APMU_USB_CLK_RES_CTRL 0x5c +#define APMU_QSPI_CLK_RES_CTRL 0x60 +#define APMU_USB_CLK_RES_CTRL 0x5c +#define APMU_DMA_CLK_RES_CTRL 0x64 +#define APMU_AES_CLK_RES_CTRL 0x68 +#define APMU_VPU_CLK_RES_CTRL 0xa4 +#define APMU_GPU_CLK_RES_CTRL 0xcc +#define APMU_SDH2_CLK_RES_CTRL 0xe0 +#define APMU_PMUA_MC_CTRL 0xe8 +#define APMU_PMU_CC2_AP 0x100 +#define APMU_PMUA_EM_CLK_RES_CTRL 0x104 + +#define APMU_AUDIO_CLK_RES_CTRL 0x14c +#define APMU_HDMI_CLK_RES_CTRL 0x1b8 +#define APMU_CCI550_CLK_CTRL 0x300 +#define APMU_ACLK_CLK_CTRL 0x388 +#define APMU_CPU_C0_CLK_CTRL 0x38c +#define APMU_CPU_C1_CLK_CTRL 0x390 + +#define APMU_PCIE_CLK_RES_CTRL_0 0x3cc +#define APMU_PCIE_CLK_RES_CTRL_1 0x3d4 +#define APMU_PCIE_CLK_RES_CTRL_2 0x3dc + +#define APMU_EMAC0_CLK_RES_CTRL 0x3e4 +#define APMU_EMAC1_CLK_RES_CTRL 0x3ec + +#define APMU_DFC_AP 0x180 +#define APMU_DFC_STATUS 0x188 + +#define APMU_DFC_LEVEL0 0x190 +#define APMU_DFC_LEVEL1 0x194 +#define APMU_DFC_LEVEL2 0x198 +#define APMU_DFC_LEVEL3 0x19c +#define APMU_DFC_LEVEL4 0x1a0 +#define APMU_DFC_LEVEL5 0x1a4 +#define APMU_DFC_LEVEL6 0x1a8 +#define APMU_DFC_LEVEL7 0x1ac + +#define APMU_DPLL1_CLK_CTRL1 0x39c +#define APMU_DPLL1_CLK_CTRL2 0x3a0 +#define APMU_DPLL2_CLK_CTRL1 0x3a8 +#define APMU_DPLL2_CLK_CTRL2 0x3ac +/* End of APMU register offset */ + +/* APBC2 register offset */ +#define APBC2_UART1_CLK_RST 0x00 +#define APBC2_SSP2_CLK_RST 0x04 +#define APBC2_TWSI3_CLK_RST 0x08 +#define APBC2_RTC_CLK_RST 0x0c +#define APBC2_TIMERS0_CLK_RST 0x10 +#define APBC2_KPC_CLK_RST 0x14 +#define APBC2_GPIO_CLK_RST 0x1c +/* End of APBC2 register offset */ + +/* RCPU register offset */ +#define RCPU_HDMI_CLK_RST 0x2044 +#define RCPU_CAN_CLK_RST 0x4c +#define RCPU_I2C0_CLK_RST 0x30 + +#define RCPU_SSP0_CLK_RST 0x28 +#define RCPU_IR_CLK_RST 0x48 +#define RCPU_UART0_CLK_RST 0xd8 +#define RCPU_UART1_CLK_RST 0x3c +/* End of RCPU register offset */ + +/* RCPU2 register offset */ +#define RCPU2_PWM0_CLK_RST 0x00 +#define RCPU2_PWM1_CLK_RST 0x04 +#define RCPU2_PWM2_CLK_RST 0x08 +#define RCPU2_PWM3_CLK_RST 0x0c +#define RCPU2_PWM4_CLK_RST 0x10 +#define RCPU2_PWM5_CLK_RST 0x14 +#define RCPU2_PWM6_CLK_RST 0x18 +#define RCPU2_PWM7_CLK_RST 0x1c +#define RCPU2_PWM8_CLK_RST 0x20 +#define RCPU2_PWM9_CLK_RST 0x24 +/* End of RCPU2 register offset */ + +/* AUDPMU register offset */ +#define AUDPMU_AUDIO_BUS_CLK_CTRL 0x38 +/* end of AUDPMU register offset */ + +enum cru_type +{ + CRU_BASE_TYPE_MPMU = 0, + CRU_BASE_TYPE_APMU, + CRU_BASE_TYPE_APBC, + CRU_BASE_TYPE_APBS, + CRU_BASE_TYPE_CIU, + CRU_BASE_TYPE_DCIU, + CRU_BASE_TYPE_DDRC, + CRU_BASE_TYPE_APBC2, + CRU_BASE_TYPE_RCPU, + CRU_BASE_TYPE_RCPU2, + CRU_BASE_TYPE_AUDPMU, + CRU_BASE_TYPE_AUDC, + CRU_BASE_TYPE_MAX, +}; + +#ifdef __CCU_H__ +RT_DEFINE_SPINLOCK(k1_cru_lock); +#else +extern struct rt_spinlock k1_cru_lock; +#endif + +#endif /* __K1_CLK_RST_H__ */ diff --git a/bsp/spacemit/dm/include/k1-tcm.h b/bsp/spacemit/dm/include/k1-tcm.h new file mode 100644 index 000000000000..6a135eed30a4 --- /dev/null +++ b/bsp/spacemit/dm/include/k1-tcm.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#ifndef __K1_TCM_H__ +#define __K1_TCM_H__ + +#include +#include + +void *tcm_alloc_cpu(int cpuid, rt_size_t size); +void tcm_free_cpu(int cpuid, void *ptr); + +rt_inline void *tcm_alloc(rt_size_t size) +{ + return tcm_alloc_cpu(rt_hw_cpu_id(), size); +} + +rt_inline void tcm_free(void *ptr) +{ + return tcm_free_cpu(rt_hw_cpu_id(), ptr); +} + +#endif /* __K1_TCM_H__ */ diff --git a/bsp/spacemit/dm/include/k1x-rproc.h b/bsp/spacemit/dm/include/k1x-rproc.h new file mode 100644 index 000000000000..7f6acf87568b --- /dev/null +++ b/bsp/spacemit/dm/include/k1x-rproc.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#ifndef __K1X_RPROC_H__ +#define __K1X_RPROC_H__ + +#include + +rt_err_t spacemit_k1x_rproc_boot(const char *fw_name); +void spacemit_k1x_rproc_dump_status(void); + +#endif /* __K1X_RPROC_H__ */ diff --git a/bsp/spacemit/dm/include/mfd/pm853.h b/bsp/spacemit/dm/include/mfd/pm853.h new file mode 100644 index 000000000000..8ab8d6919385 --- /dev/null +++ b/bsp/spacemit/dm/include/mfd/pm853.h @@ -0,0 +1,336 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#ifndef __PM853_H__ +#define __PM853_H__ + +enum +{ + PM853_ID_DCDC1, + PM853_ID_DCDC2, + PM853_ID_DCDC3, + PM853_ID_DCDC4, + PM853_ID_DCDC5, + PM853_ID_LDO1, + PM853_ID_LDO2, + PM853_ID_LDO3, + PM853_ID_LDO4, + PM853_ID_LDO5, + PM853_ID_LDO6, + PM853_ID_LDO7, + PM853_ID_LDO8, + PM853_ID_LDO9, + PM853_ID_LDO10, + PM853_ID_LDO11, + PM853_ID_LDO12, + PM853_ID_LDO13, + PM853_ID_LDO14, + PM853_ID_LDO15, + PM853_ID_LDO16, + PM853_ID_LDO17, + PM853_ID_LDO18, + PM853_ID_LDO19, + PM853_ID_LDO20, + PM853_ID_LDO21, + PM853_ID_LDO22, + PM853_ID_LDO5_SW, +}; + +#define PM853_LDO_BUCK_EN_REG0 0x11 +#define PM853_LDO_BUCK_EN_REG1 0x12 +#define PM853_LDO_BUCK_EN_REG2 0x13 +#define PM853_LDO_BUCK_EN_REG3 0x14 + +#define PM853_BUCK1_EN_MSK 0x1 +#define PM853_BUCK2_EN_MSK 0x2 +#define PM853_BUCK3_EN_MSK 0x4 +#define PM853_BUCK4_EN_MSK 0x8 +#define PM853_BUCK5_EN_MSK 0x10 + +#define PM853_LDO1_EN_MSK 0x20 +#define PM853_LDO2_EN_MSK 0x40 +#define PM853_LDO3_EN_MSK 0x80 +#define PM853_LDO4_EN_MSK 0x1 +#define PM853_LDO5_EN_MSK 0x2 +#define PM853_LDO6_EN_MSK 0x4 +#define PM853_LDO7_EN_MSK 0x8 +#define PM853_LDO8_EN_MSK 0x10 +#define PM853_LDO9_EN_MSK 0x20 +#define PM853_LDO10_EN_MSK 0x40 +#define PM853_LDO11_EN_MSK 0x80 +#define PM853_LDO12_EN_MSK 0x1 +#define PM853_LDO13_EN_MSK 0x2 +#define PM853_LDO14_EN_MSK 0x4 +#define PM853_LDO15_EN_MSK 0x8 +#define PM853_LDO16_EN_MSK 0x10 +#define PM853_LDO17_EN_MSK 0x20 +#define PM853_LDO18_EN_MSK 0x40 +#define PM853_LDO19_EN_MSK 0x80 +#define PM853_LDO20_EN_MSK 0x1 +#define PM853_LDO21_EN_MSK 0x2 +#define PM853_LDO22_EN_MSK 0x4 +#define PM853_SW_EN_MSK 0x8 + + +#define PM853_BUCK1_VSEL_REG 0x30 +#define PM853_BUCK2_VSEL_REG 0x50 +#define PM853_BUCK3_VSEL_REG 0x60 +#define PM853_BUCK4_VSEL_REG 0x80 +#define PM853_BUCK5_VSEL_REG 0x90 + +#define PM853_BUCK1_VSEL_MSK 0x7f +#define PM853_BUCK2_VSEL_MSK 0x7f +#define PM853_BUCK3_VSEL_MSK 0x7f +#define PM853_BUCK4_VSEL_MSK 0x7f +#define PM853_BUCK5_VSEL_MSK 0x7f + +#define PM853_LDO_VSEL_MSK 0xf +#define PM853_LDO1_VSEL_REG 0xb1 +#define PM853_LDO2_VSEL_REG 0xb4 +#define PM853_LDO3_VSEL_REG 0xb7 +#define PM853_LDO4_VSEL_REG 0xba +#define PM853_LDO5_VSEL_REG 0xbd +#define PM853_LDO6_VSEL_REG 0xc0 +#define PM853_LDO7_VSEL_REG 0xc3 +#define PM853_LDO8_VSEL_REG 0xc6 +#define PM853_LDO9_VSEL_REG 0xc9 +#define PM853_LDO10_VSEL_REG 0xcc +#define PM853_LDO11_VSEL_REG 0xcf +#define PM853_LDO12_VSEL_REG 0xd2 +#define PM853_LDO13_VSEL_REG 0xd5 +#define PM853_LDO14_VSEL_REG 0xd8 +#define PM853_LDO15_VSEL_REG 0xdb +#define PM853_LDO16_VSEL_REG 0xde +#define PM853_LDO17_VSEL_REG 0xe1 +#define PM853_LDO18_VSEL_REG 0xe4 +#define PM853_LDO19_VSEL_REG 0xe7 +#define PM853_LDO20_VSEL_REG 0xea +#define PM853_LDO21_VSEL_REG 0xed +#define PM853_LDO22_VSEL_REG 0xf0 + +#define SPACEMIT_PM853_MAX_REG 0xf1 + +#define PM853_DESC(_id, _match, _supply, _nv, _vr, _vm, _er, _em, _lr) \ + SPACEMIT_PMIC_REGULATOR_DESC_COMMON(_id, _match, _supply, _nv, _vr, _vm, _er, _em, _lr, pmic_dcdc_ldo_ops) + +#define PM853_DESC_SWITCH(_id, _match, _supply, _ereg, _emask) \ + SPACEMIT_PMIC_REGULATOR_DESC_SWITCH_COM(_id, _match, _supply, _ereg, _emask, 0, 0, pmic_switch_ops) + +#ifdef __SPACEMIT_REGULATOR_INTERNAL +static const struct spacemit_pmic_regulator_range pm853_buck_ranges1[] = +{ + SPACEMIT_PMIC_REGULATOR_RANGE(480000, 0x0, 0x50, 10000), + SPACEMIT_PMIC_REGULATOR_RANGE(1320000, 0x51, 0x7F, 40000), +}; + +static const struct spacemit_pmic_regulator_range pm853_buck_ranges2[] = +{ + SPACEMIT_PMIC_REGULATOR_RANGE(600000, 0x0, 0x50, 12500), + SPACEMIT_PMIC_REGULATOR_RANGE(1650000, 0x51, 0x7F, 50000), +}; + +static const struct spacemit_pmic_regulator_range pm853_ldo_ranges1[] = +{ + SPACEMIT_PMIC_REGULATOR_RANGE(1200000, 0x0, 0x6, 100000), + SPACEMIT_PMIC_REGULATOR_RANGE(1850000, 0x7, 0x8, 50000), + SPACEMIT_PMIC_REGULATOR_RANGE(2750000, 0x9, 0xc, 50000), + SPACEMIT_PMIC_REGULATOR_RANGE(3000000, 13, 14, 100000), + SPACEMIT_PMIC_REGULATOR_RANGE(3300000, 15, 15, 0), +}; + +static const struct spacemit_pmic_regulator_range pm853_ldo_ranges2[] = +{ + SPACEMIT_PMIC_REGULATOR_RANGE(1600000, 0x0, 0x3, 100000), +}; + +static const struct spacemit_pmic_regulator_range pm853_ldo_ranges3[] = +{ + SPACEMIT_PMIC_REGULATOR_RANGE(1200000, 0x0, 0xf, 50000), +}; + +static const struct spacemit_pmic_regulator_range pm853_ldo_ranges4[] = +{ + SPACEMIT_PMIC_REGULATOR_RANGE(1000000, 0x0, 0x7, 50000), +}; + +static const struct spacemit_pmic_regulator_desc pm853_reg[] = +{ + /* BUCK */ + PM853_DESC(PM853_ID_DCDC1, "DCDC_REG1", "vcc_sys", + 128, PM853_BUCK1_VSEL_REG, PM853_BUCK1_VSEL_MSK, + PM853_LDO_BUCK_EN_REG0, PM853_BUCK1_EN_MSK, + pm853_buck_ranges1), + + PM853_DESC(PM853_ID_DCDC2, "DCDC_REG2", "vcc_sys", + 128, PM853_BUCK2_VSEL_REG, PM853_BUCK2_VSEL_MSK, + PM853_LDO_BUCK_EN_REG0, PM853_BUCK2_EN_MSK, + pm853_buck_ranges2), + + PM853_DESC(PM853_ID_DCDC3, "DCDC_REG3", "vcc_sys", + 128, PM853_BUCK3_VSEL_REG, PM853_BUCK3_VSEL_MSK, + PM853_LDO_BUCK_EN_REG0, PM853_BUCK3_EN_MSK, + pm853_buck_ranges2), + + PM853_DESC(PM853_ID_DCDC4, "DCDC_REG4", "vcc_sys", + 128, PM853_BUCK4_VSEL_REG, PM853_BUCK4_VSEL_MSK, + PM853_LDO_BUCK_EN_REG0, PM853_BUCK4_EN_MSK, + pm853_buck_ranges1), + + PM853_DESC(PM853_ID_DCDC5, "DCDC_REG5", "vcc_sys", + 128, PM853_BUCK5_VSEL_REG, PM853_BUCK5_VSEL_MSK, + PM853_LDO_BUCK_EN_REG0, PM853_BUCK5_EN_MSK, + pm853_buck_ranges2), + + /* ALDO */ + PM853_DESC(PM853_ID_LDO1, "LDO_REG1", "vcc_sys", + 16, PM853_LDO1_VSEL_REG, PM853_LDO_VSEL_MSK, + PM853_LDO_BUCK_EN_REG0, PM853_LDO1_EN_MSK, + pm853_ldo_ranges1), + + PM853_DESC(PM853_ID_LDO2, "LDO_REG2", "vcc_sys", + 16, PM853_LDO2_VSEL_REG, PM853_LDO_VSEL_MSK, + PM853_LDO_BUCK_EN_REG0, PM853_LDO2_EN_MSK, + pm853_ldo_ranges1), + + PM853_DESC(PM853_ID_LDO3, "LDO_REG3", "vcc_sys", + 16, PM853_LDO3_VSEL_REG, PM853_LDO_VSEL_MSK, + PM853_LDO_BUCK_EN_REG0, PM853_LDO3_EN_MSK, + pm853_ldo_ranges1), + + PM853_DESC(PM853_ID_LDO4, "LDO_REG4", "vcc_sys", + 16, PM853_LDO4_VSEL_REG, PM853_LDO_VSEL_MSK, + PM853_LDO_BUCK_EN_REG1, PM853_LDO4_EN_MSK, + pm853_ldo_ranges1), + + PM853_DESC(PM853_ID_LDO5, "LDO_REG5", "vcc_sys", + 4, PM853_LDO5_VSEL_REG, PM853_LDO_VSEL_MSK, + PM853_LDO_BUCK_EN_REG1, PM853_LDO5_EN_MSK, + pm853_ldo_ranges2), + + PM853_DESC(PM853_ID_LDO6, "LDO_REG6", "vcc_sys", + 16, PM853_LDO6_VSEL_REG, PM853_LDO_VSEL_MSK, + PM853_LDO_BUCK_EN_REG1, PM853_LDO6_EN_MSK, + pm853_ldo_ranges1), + + PM853_DESC(PM853_ID_LDO7, "LDO_REG7", "dcdc2", + 16, PM853_LDO7_VSEL_REG, PM853_LDO_VSEL_MSK, + PM853_LDO_BUCK_EN_REG1, PM853_LDO7_EN_MSK, + pm853_ldo_ranges3), + + PM853_DESC(PM853_ID_LDO8, "LDO_REG8", "vcc_sys", + 16, PM853_LDO8_VSEL_REG, PM853_LDO_VSEL_MSK, + PM853_LDO_BUCK_EN_REG1, PM853_LDO8_EN_MSK, + pm853_ldo_ranges1), + + PM853_DESC(PM853_ID_LDO9, "LDO_REG9", "vcc_sys", + 16, PM853_LDO9_VSEL_REG, PM853_LDO_VSEL_MSK, + PM853_LDO_BUCK_EN_REG1, PM853_LDO9_EN_MSK, + pm853_ldo_ranges1), + + PM853_DESC(PM853_ID_LDO10, "LDO_REG10", "vcc_sys", + 16, PM853_LDO10_VSEL_REG, PM853_LDO_VSEL_MSK, + PM853_LDO_BUCK_EN_REG1, PM853_LDO10_EN_MSK, + pm853_ldo_ranges1), + + PM853_DESC(PM853_ID_LDO11, "LDO_REG11", "dcdc2", + 16, PM853_LDO11_VSEL_REG, PM853_LDO_VSEL_MSK, + PM853_LDO_BUCK_EN_REG1, PM853_LDO11_EN_MSK, + pm853_ldo_ranges3), + + PM853_DESC(PM853_ID_LDO12, "LDO_REG12", "vcc_sys", + 16, PM853_LDO12_VSEL_REG, PM853_LDO_VSEL_MSK, + PM853_LDO_BUCK_EN_REG2, PM853_LDO12_EN_MSK, + pm853_ldo_ranges1), + + PM853_DESC(PM853_ID_LDO13, "LDO_REG13", "vcc_sys", + 16, PM853_LDO13_VSEL_REG, PM853_LDO_VSEL_MSK, + PM853_LDO_BUCK_EN_REG2, PM853_LDO13_EN_MSK, + pm853_ldo_ranges1), + + PM853_DESC(PM853_ID_LDO14, "LDO_REG14", "vcc_sys", + 16, PM853_LDO14_VSEL_REG, PM853_LDO_VSEL_MSK, + PM853_LDO_BUCK_EN_REG2, PM853_LDO14_EN_MSK, + pm853_ldo_ranges1), + + PM853_DESC(PM853_ID_LDO15, "LDO_REG15", "dcdc2", + 16, PM853_LDO15_VSEL_REG, PM853_LDO_VSEL_MSK, + PM853_LDO_BUCK_EN_REG2, PM853_LDO15_EN_MSK, + pm853_ldo_ranges3), + + PM853_DESC(PM853_ID_LDO16, "LDO_REG16", "vcc_sys", + 16, PM853_LDO16_VSEL_REG, PM853_LDO_VSEL_MSK, + PM853_LDO_BUCK_EN_REG2, PM853_LDO16_EN_MSK, + pm853_ldo_ranges1), + + PM853_DESC(PM853_ID_LDO17, "LDO_REG17", "dcdc5", + 8, PM853_LDO17_VSEL_REG, PM853_LDO_VSEL_MSK, + PM853_LDO_BUCK_EN_REG2, PM853_LDO17_EN_MSK, + pm853_ldo_ranges4), + + PM853_DESC(PM853_ID_LDO18, "LDO_REG18", "dcdc2", + 16, PM853_LDO18_VSEL_REG, PM853_LDO_VSEL_MSK, + PM853_LDO_BUCK_EN_REG2, PM853_LDO18_EN_MSK, + pm853_ldo_ranges3), + + PM853_DESC(PM853_ID_LDO19, "LDO_REG19", "dcdc5", + 8, PM853_LDO19_VSEL_REG, PM853_LDO_VSEL_MSK, + PM853_LDO_BUCK_EN_REG2, PM853_LDO19_EN_MSK, + pm853_ldo_ranges4), + + PM853_DESC(PM853_ID_LDO20, "LDO_REG20", "dcdc5", + 8, PM853_LDO20_VSEL_REG, PM853_LDO_VSEL_MSK, + PM853_LDO_BUCK_EN_REG3, PM853_LDO20_EN_MSK, + pm853_ldo_ranges4), + + PM853_DESC(PM853_ID_LDO21, "LDO_REG21", "dcdc2", + 16, PM853_LDO21_VSEL_REG, PM853_LDO_VSEL_MSK, + PM853_LDO_BUCK_EN_REG3, PM853_LDO21_EN_MSK, + pm853_ldo_ranges3), + + PM853_DESC(PM853_ID_LDO22, "LDO_REG22", "dcdc5", + 8, PM853_LDO22_VSEL_REG, PM853_LDO_VSEL_MSK, + PM853_LDO_BUCK_EN_REG3, PM853_LDO22_EN_MSK, + pm853_ldo_ranges4), + + /* PWR SWITCH */ + PM853_DESC_SWITCH(PM853_ID_LDO5_SW, "SWITCH_REG1", "vcc_sys", + PM853_LDO_BUCK_EN_REG3, PM853_SW_EN_MSK), +}; + +static struct spacemit_pmic_regulator_data pm853_regulator_data = +{ + .desc = pm853_reg, + .desc_nr = RT_ARRAY_SIZE(pm853_reg), +}; +#endif /* __SPACEMIT_REGULATOR_INTERNAL */ + +#ifdef __SPACEMIT_PMIC_INTERNAL +static struct spacemit_pmic_mfd_endpoint pm853_mfd_endpoint[] = +{ + { + .ofw_name = "spacemit-regulator@pm853", + .ofw_compatible = "pmic,regulator,pm853", + }, +}; + +static struct spacemit_pmic_mfd_data pm853_mfd_data = +{ + .regmap_cfg = + { + .reg_bits = 8, + .val_bits = 8, + .max_register = SPACEMIT_PM853_MAX_REG, + }, + .endpoint = pm853_mfd_endpoint, + .endpoint_num = RT_ARRAY_SIZE(pm853_mfd_endpoint), +}; +#endif /* __SPACEMIT_PMIC_INTERNAL */ + +#endif /* __PM853_H__ */ diff --git a/bsp/spacemit/dm/include/mfd/spacemit-pmic.h b/bsp/spacemit/dm/include/mfd/spacemit-pmic.h new file mode 100644 index 000000000000..a843d66e7fa6 --- /dev/null +++ b/bsp/spacemit/dm/include/mfd/spacemit-pmic.h @@ -0,0 +1,483 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#ifndef __SPACEMIT_PMIC_H__ +#define __SPACEMIT_PMIC_H__ + +#include +#include + +struct spacemit_pmic_mfd_data; + +struct spacemit_pmic +{ + int irq; + int addr_offset; + struct rt_device *dev; + rt_mutex_t io_lock; + const struct spacemit_pmic_mfd_data *mfd_data; + + unsigned (*read)(struct spacemit_pmic *pmic, unsigned reg); + rt_err_t (*write)(struct spacemit_pmic *pmic, unsigned reg, unsigned data); + rt_err_t (*write_bit)(struct spacemit_pmic *pmic, unsigned reg, unsigned mask, unsigned data); + rt_err_t (*update_bits)(struct spacemit_pmic *pmic, unsigned reg, unsigned mask, unsigned data); +}; + +struct spacemit_pmic_irq_map +{ + rt_uint32_t reg_offset; + rt_uint32_t mask; +}; + +struct spacemit_pmic_irqchip +{ + struct rt_pic parent; + + struct spacemit_pmic *pmic; + + rt_uint32_t *irq_status; + + int num_regs; + int reg_stride; + int mask_base; + int status_base; + int ack_base; + + rt_bool_t init_ack_masked; + rt_bool_t mask_unmask_non_inverted; + + int irqs_nr; + const struct spacemit_pmic_irq_map *irqs_map; + + struct rt_thread *irq_thread; + struct rt_semaphore irq_sem; + + volatile rt_uint32_t hard_irq_count; + volatile rt_uint32_t worker_count; + volatile rt_uint32_t rearm_count; +}; + +#define raw_to_spacemit_pmic_irqchip(raw) rt_container_of(raw, struct spacemit_pmic_irqchip, parent) + +struct spacemit_pmic_regmap_config +{ + rt_uint8_t reg_bits; + rt_uint8_t val_bits; + rt_uint16_t max_register; +}; + +struct spacemit_pmic_mfd_endpoint +{ + const char *ofw_name; + const char *ofw_compatible; + + int irqs_nr; + const int *irqs_list; +}; + +struct spacemit_pmic_mfd_data +{ + struct spacemit_pmic_regmap_config regmap_cfg; + + struct spacemit_pmic_mfd_endpoint *endpoint; + rt_uint32_t endpoint_num; + + struct spacemit_pmic_irqchip *irqchip; + + /* Shutdown - reboot support */ + struct + { + rt_uint8_t reg; + rt_uint8_t bit; + } shutdown; + + struct + { + rt_uint32_t reg; + rt_uint8_t bit; + } reboot; + + /* Value will be kept in register while reset pmic */ + struct + { + rt_uint32_t reg; + rt_uint8_t bit; + } non_reset; +}; + +/* Regulator */ +struct spacemit_pmic_regulator_range +{ + int min; + int min_sel; + int max_sel; + int step; +}; + +#define SPACEMIT_PMIC_REGULATOR_RANGE(UVOLT_MIN, MIN_SEL, MAX_SEL, UVOLT_STEP) \ +{ \ + .min = UVOLT_MIN, \ + .min_sel = MIN_SEL, \ + .max_sel = MAX_SEL, \ + .step = UVOLT_STEP, \ +} + +struct spacemit_pmic_regulator_desc +{ + const char *name; + const char *match; + const char *supply_name; + + const struct rt_regulator_ops *ops; + + rt_uint32_t id; + + int voltages_nr; + int uvolt_min; + int uvolt_step; + + int ranges_nr; + const struct spacemit_pmic_regulator_range *ranges; + + rt_uint32_t vsel_reg; + rt_uint32_t vsel_mask; + rt_uint32_t enable_reg; + rt_uint32_t enable_mask; + rt_uint32_t enable_val; + rt_uint32_t disable_val; +}; + +#define SPACEMIT_PMIC_REGULATOR_DESC(ID, NAME, \ + SUPPLY_NAME, OPS, \ + VOLTAGES_NR, UVOLT_MIN, UVOLT_STEP, \ + RANGES_NR, RANGES, \ + VSEL_REG, VSEL_MASK, ENABLE_REG, \ + ENABLE_MASK, ENABLE_VAL, DISABLE_VAL) \ +{ \ + .name = NAME, \ + .supply_name = SUPPLY_NAME, \ + .ops = &OPS, \ + .id = ID, \ + .voltages_nr = VOLTAGES_NR, \ + .uvolt_min = UVOLT_MIN, \ + .uvolt_step = UVOLT_STEP, \ + .ranges_nr = RANGES_NR, \ + .ranges = RANGES, \ + .vsel_reg = VSEL_REG, \ + .vsel_mask = VSEL_MASK, \ + .enable_reg = ENABLE_REG, \ + .enable_mask = ENABLE_MASK, \ + .enable_val = ENABLE_VAL, \ + .disable_val = DISABLE_VAL, \ +} + +#define SPACEMIT_PMIC_REGULATOR_DESC_COMMON(ID, \ + NAME, SUPPLY_NAME, VOLTAGES_NR, VSEL_REG, \ + VSEL_MASK, ENABLE_REG, ENABLE_MASK, RANGES, \ + OPS) \ + SPACEMIT_PMIC_REGULATOR_DESC(ID, NAME, \ + SUPPLY_NAME, OPS, \ + VOLTAGES_NR, 0, 0, \ + RT_ARRAY_SIZE(RANGES), RANGES, \ + VSEL_REG, VSEL_MASK, ENABLE_REG, \ + ENABLE_MASK, 0, 0) + +#define SPACEMIT_PMIC_REGULATOR_DESC_SWITCH_COM(\ + ID, NAME, SUPPLY_NAME, \ + ENABLE_REG, ENABLE_MASK, \ + ENABLE_VAL, DISABLE_VAL, OPS) \ + SPACEMIT_PMIC_REGULATOR_DESC(ID, NAME, \ + SUPPLY_NAME, OPS, \ + 0, 0, 0, \ + 0, RT_NULL, \ + 0, 0, ENABLE_REG, \ + ENABLE_MASK, ENABLE_VAL, DISABLE_VAL) + +struct spacemit_pmic_regulator_data +{ + const struct spacemit_pmic_regulator_desc *desc; + rt_uint32_t desc_nr; + int sleep_reg_offset; +}; + +/* Pinctrl */ +struct spacemit_pmic_pin_func_desc +{ + const char *name; + rt_uint8_t pin_id; + rt_uint8_t func_reg; + rt_uint8_t func_mask; + rt_uint8_t en_val; + rt_uint8_t ha_sub; + rt_uint8_t sub_reg; + rt_uint8_t sub_mask; + rt_uint8_t sube_val; +}; + +#define SPM8XX_DESC_PIN_FUNC_COM(_pin_id, _match, \ + _ereg, _emask, _enval, \ + _hsub, _subreg, _submask, _subenval) \ +{ \ + .name = (_match), \ + .pin_id = (_pin_id), \ + .func_reg = (_ereg), \ + .func_mask = (_emask), \ + .en_val = (_enval), \ + .ha_sub = (_hsub), \ + .sub_reg = (_subreg), \ + .sub_mask = (_submask), \ + .sube_val = (_subenval), \ +} + +struct spacemit_pmic_pin_config_desc +{ + rt_uint32_t pin_id; + /* Input config desc */ + struct + { + rt_uint8_t reg; + rt_uint8_t msk; + } input; + + /* Output config desc */ + struct + { + rt_uint8_t reg; + rt_uint8_t msk; + } output; + + /* Pull-down desc */ + struct + { + rt_uint8_t reg; + rt_uint8_t msk; + } pup; + + /* Deb */ + struct + { + rt_uint8_t reg; + rt_uint8_t timemsk; + + struct + { + rt_uint8_t msk; + } en; + } deb; + + /* OD */ + struct + { + rt_uint8_t reg; + rt_uint8_t msk; + } od; + + struct + { + rt_uint8_t reg; + rt_uint8_t msk; + } itype; +}; + +#define SPM8XX_DESC_PIN_CONFIG_COM(_pin_id, \ + _ireg, _imsk, _oreg, _omsk, \ + _pureg, _pumsk, \ + _debreg, _debtmsk, _debemsk, \ + _odreg, _odmsk, \ + _itypereg, _itypemsk) \ +{ \ + .pin_id = (_pin_id), \ + .input = \ + { \ + .reg = (_ireg), \ + .msk = (_imsk), \ + }, \ + .output = \ + { \ + .reg = (_oreg), \ + .msk = (_omsk), \ + }, \ + .pup = \ + { \ + .reg = (_pureg), \ + .msk = (_pumsk), \ + }, \ + .deb = \ + { \ + .reg = (_debreg), \ + .timemsk = (_debtmsk), \ + .en.msk = (_debemsk) \ + }, \ + .od = \ + { \ + .reg = (_odreg), \ + .msk = (_odmsk), \ + }, \ + .itype = \ + { \ + .reg = (_itypereg), \ + .msk = (_itypemsk), \ + }, \ +} + +struct spacemit_pmic_pin_data +{ + int pin_mux_nr; + const char **pinmux_funcs; + + int pin_fuc_desc_nr; + const struct spacemit_pmic_pin_func_desc *pinfunc_desc; + + int pin_conf_desc_nr; + const struct spacemit_pmic_pin_config_desc *pinconf_desc; +}; + +/* RTC */ +union spacemit_pmic_rtc_ctl_desc +{ + rt_uint32_t val; + struct + { + rt_uint32_t crystal_en:1; + rt_uint32_t out_32k_en:1; + rt_uint32_t rtc_en:1; + rt_uint32_t rtc_clk_sel:1; + rt_uint32_t tick_type:1; + rt_uint32_t alarm_en:1; + rt_uint32_t tick_en:1; + rt_uint32_t reserved:25; + } bits; +}; + +struct spacemit_pmic_rtc_regdesc +{ + /* Seconds */ + struct + { + rt_uint8_t reg; + rt_uint8_t msk; + } cnt_s; + + /* Mini */ + struct + { + rt_uint8_t reg; + rt_uint8_t msk; + } cnt_mi; + + /* Hour */ + struct + { + rt_uint8_t reg; + rt_uint8_t msk; + } cnt_h; + + /* Day */ + struct + { + rt_uint8_t reg; + rt_uint8_t msk; + } cnt_d; + + /* Mounth */ + struct + { + rt_uint8_t reg; + rt_uint8_t msk; + } cnt_mo; + + /* Year */ + struct + { + rt_uint8_t reg; + rt_uint8_t msk; + } cnt_y; + + struct + { + rt_uint8_t reg; + rt_uint8_t msk; + } alarm_s; + + struct + { + rt_uint8_t reg; + rt_uint8_t msk; + } alarm_mi; + + struct + { + rt_uint8_t reg; + rt_uint8_t msk; + } alarm_h; + + struct + { + rt_uint8_t reg; + rt_uint8_t msk; + } alarm_d; + + struct + { + rt_uint8_t reg; + rt_uint8_t msk; + } alarm_mo; + + struct + { + rt_uint8_t reg; + rt_uint8_t msk; + } alarm_y; + + struct + { + rt_uint8_t reg; + } rtc_ctl; +}; + +/* IIO */ +struct spacemit_pmic_iio_chan_spec +{ + int channel; +}; + +struct spacemit_pmic_adc_data +{ + int iio_desc_nr; + struct spacemit_pmic_iio_chan_spec *iio_desc; +}; + +#include "spm8821.h" +#include "pm853.h" +#include "sy8810l.h" + +rt_inline unsigned spacemit_pmic_read(struct spacemit_pmic *pmic, unsigned reg) +{ + return pmic->read(pmic, reg); +} + +rt_inline rt_err_t spacemit_pmic_write(struct spacemit_pmic *pmic, unsigned reg, unsigned data) +{ + return pmic->write(pmic, reg, data); +} + +rt_inline rt_err_t spacemit_pmic_write_bit(struct spacemit_pmic *pmic, unsigned reg, + unsigned mask, unsigned data) +{ + return pmic->write_bit(pmic, reg, mask, data); +} + +rt_inline rt_err_t spacemit_pmic_update_bits(struct spacemit_pmic *pmic, unsigned reg, + unsigned mask, unsigned data) +{ + return pmic->update_bits(pmic, reg, mask, data); +} + +#endif /* __SPACEMIT_PMIC_H__ */ diff --git a/bsp/spacemit/dm/include/mfd/spm8821.h b/bsp/spacemit/dm/include/mfd/spm8821.h new file mode 100644 index 000000000000..c93ffcb600f0 --- /dev/null +++ b/bsp/spacemit/dm/include/mfd/spm8821.h @@ -0,0 +1,885 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#ifndef __SMP8821_H__ +#define __SMP8821_H__ + +enum +{ + SPM8821_ID_DCDC1, + SPM8821_ID_DCDC2, + SPM8821_ID_DCDC3, + SPM8821_ID_DCDC4, + SPM8821_ID_DCDC5, + SPM8821_ID_DCDC6, + SPM8821_ID_LDO1, + SPM8821_ID_LDO2, + SPM8821_ID_LDO3, + SPM8821_ID_LDO4, + SPM8821_ID_LDO5, + SPM8821_ID_LDO6, + SPM8821_ID_LDO7, + SPM8821_ID_LDO8, + SPM8821_ID_LDO9, + SPM8821_ID_LDO10, + SPM8821_ID_LDO11, + SPM8821_ID_SWITCH1, +}; + +#define SPACEMIT_SPM8821_MAX_REG 0xb0 + +#define SPM8821_VERSION_ID_REG 0xa1 + +#define SPM8821_BUCK_VSEL_MASK 0xff +#define SMP8821_BUCK_EN_MASK 0x1 + +#define SPM8821_BUCK1_CTRL_REG 0x47 +#define SPM8821_BUCK2_CTRL_REG 0x4a +#define SPM8821_BUCK3_CTRL_REG 0x4d +#define SPM8821_BUCK4_CTRL_REG 0x50 +#define SPM8821_BUCK5_CTRL_REG 0x53 +#define SPM8821_BUCK6_CTRL_REG 0x56 + +#define SPM8821_BUCK1_VSEL_REG 0x48 +#define SPM8821_BUCK2_VSEL_REG 0x4b +#define SPM8821_BUCK3_VSEL_REG 0x4e +#define SPM8821_BUCK4_VSEL_REG 0x51 +#define SPM8821_BUCK5_VSEL_REG 0x54 +#define SPM8821_BUCK6_VSEL_REG 0x57 + +#define SPM8821_ALDO1_CTRL_REG 0x5b +#define SPM8821_ALDO2_CTRL_REG 0x5e +#define SPM8821_ALDO3_CTRL_REG 0x61 +#define SPM8821_ALDO4_CTRL_REG 0x64 + +#define SPM8821_ALDO1_VOLT_REG 0x5c +#define SPM8821_ALDO2_VOLT_REG 0x5f +#define SPM8821_ALDO3_VOLT_REG 0x62 +#define SPM8821_ALDO4_VOLT_REG 0x65 + +#define SPM8821_ALDO_EN_MASK 0x1 +#define SPM8821_ALDO_VSEL_MASK 0x7f + +#define SPM8821_DLDO1_CTRL_REG 0x67 +#define SPM8821_DLDO2_CTRL_REG 0x6a +#define SPM8821_DLDO3_CTRL_REG 0x6d +#define SPM8821_DLDO4_CTRL_REG 0x70 +#define SPM8821_DLDO5_CTRL_REG 0x73 +#define SPM8821_DLDO6_CTRL_REG 0x76 +#define SPM8821_DLDO7_CTRL_REG 0x79 + +#define SPM8821_DLDO1_VOLT_REG 0x68 +#define SPM8821_DLDO2_VOLT_REG 0x6b +#define SPM8821_DLDO3_VOLT_REG 0x6e +#define SPM8821_DLDO4_VOLT_REG 0x71 +#define SPM8821_DLDO5_VOLT_REG 0x74 +#define SPM8821_DLDO6_VOLT_REG 0x77 +#define SPM8821_DLDO7_VOLT_REG 0x7a + +#define SPM8821_DLDO_EN_MASK 0x1 +#define SPM8821_DLDO_VSEL_MASK 0x7f + +#define SPM8821_SWITCH_CTRL_REG 0x59 +#define SPM8821_SWTICH_EN_MASK 0x1 + +#define SPM8821_PWR_CTRL2 0x7e +#define SPM8821_SW_SHUTDOWN_BIT_MSK 0x4 +#define SPM8821_SW_RESET_BIT_MSK 0x2 + +#define SPM8821_NON_RESET_REG 0xab +#define SPM8821_RESTART_CFG_BIT_MSK 0x7 + +#define SPM8821_SLEEP_REG_OFFSET 0x1 + +#define SPM8821_ADC_AUTO_REG 0x22 +#define SPM8821_ADC_AUTO_BIT_MSK 0x7f + +#define SPM8821_ADC_CTRL_REG 0x1e +#define SPM8821_ADC_CTRL_BIT_MSK 0x3 +#define SPM8821_ADC_CTRL_EN_BIT_OFFSET 0x0 +#define SPM8821_ADC_CTRL_GO_BIT_OFFSET 0x1 + +#define SPM8821_ADC_CFG1_REG 0x20 + +#define SPM8821_ADC_CFG1_ADC_CHOP_EN_BIT_OFFSET 0x6 +#define SPM8821_ADC_CFG1_ADC_CHOP_EN_BIT_MSK 0x40 + +#define SPM8821_ADC_CFG1_ADC_CHNNL_SEL_BIT_OFFSET 0x3 +#define SPM8821_ADC_CFG1_ADC_CHNNL_SEL_BIT_MSK 0x38 + +#define SPM8821_ADC_CFG2_REG 0x21 +#define SPM8821_ADC_CFG2_REF_SEL_BIT_OFFSET 0x0 +#define SPM8821_ADC_CFG2_REF_SEL_BIT_MSK 0x3 +#define SPM8821_ADC_CFG2_3V3_REF 0x2 + +#define SPM8821_ADC_CFG2_7_DEB_NUM 0x7 +#define SPM8821_ADC_CFG2_DEB_NUM_BIT_MSK 0x70 +#define SPM8821_ADC_CFG2_DEB_NUM_BIT_OFFSET 0x4 + +#define SPM8821_ADC_EXTERNAL_CHANNEL_OFFSET 2 + +#define SPM8821_ADCIN0_RES_H_REG 0x2a +#define SPM8821_ADCIN0_RES_L_REG 0x2b +#define SPM8821_ADCIN0_REG_L_BIT_MSK 0xf0 + +#define SPM8821_E_STATUS_REG_BASE 0x91 +#define SPM8821_E_EN_REG_BASE 0x98 + +#define SPM8821_DESC(_id, _match, _supply, _nv, _vr, _vm, _er, _em, _lr) \ + SPACEMIT_PMIC_REGULATOR_DESC_COMMON(_id, _match, _supply, _nv, _vr, _vm, _er, _em, _lr, pmic_dcdc_ldo_ops) + +#define SPM8821_DESC_SWITCH(_id, _match, _supply, _ereg, _emask) \ + SPACEMIT_PMIC_REGULATOR_DESC_SWITCH_COM(_id, _match, _supply, _ereg, _emask, 0, 0, pmic_switch_ops) + +#ifdef __SPACEMIT_REGULATOR_INTERNAL +static const struct spacemit_pmic_regulator_range spm8821_buck_ranges[] = +{ + SPACEMIT_PMIC_REGULATOR_RANGE(500000, 0x0, 0xaa, 5000), + SPACEMIT_PMIC_REGULATOR_RANGE(1375000, 0xab, 0xff, 25000), +}; + +static const struct spacemit_pmic_regulator_range spm8821_ldo_ranges[] = +{ + SPACEMIT_PMIC_REGULATOR_RANGE(500000, 0xb, 0x7f, 25000), +}; + +static const struct spacemit_pmic_regulator_desc spm8821_reg[] = +{ + /* BUCK */ + SPM8821_DESC(SPM8821_ID_DCDC1, "DCDC_REG1", "vcc_sys", + 255, SPM8821_BUCK1_VSEL_REG, SPM8821_BUCK_VSEL_MASK, + SPM8821_BUCK1_CTRL_REG, SMP8821_BUCK_EN_MASK, + spm8821_buck_ranges), + + SPM8821_DESC(SPM8821_ID_DCDC2, "DCDC_REG2", "vcc_sys", + 255, SPM8821_BUCK2_VSEL_REG, SPM8821_BUCK_VSEL_MASK, + SPM8821_BUCK2_CTRL_REG, SMP8821_BUCK_EN_MASK, + spm8821_buck_ranges), + + SPM8821_DESC(SPM8821_ID_DCDC3, "DCDC_REG3", "vcc_sys", + 255, SPM8821_BUCK3_VSEL_REG, SPM8821_BUCK_VSEL_MASK, + SPM8821_BUCK3_CTRL_REG, SMP8821_BUCK_EN_MASK, + spm8821_buck_ranges), + + SPM8821_DESC(SPM8821_ID_DCDC4, "DCDC_REG4", "vcc_sys", + 255, SPM8821_BUCK4_VSEL_REG, SPM8821_BUCK_VSEL_MASK, + SPM8821_BUCK4_CTRL_REG, SMP8821_BUCK_EN_MASK, + spm8821_buck_ranges), + + SPM8821_DESC(SPM8821_ID_DCDC5, "DCDC_REG5", "vcc_sys", + 255, SPM8821_BUCK5_VSEL_REG, SPM8821_BUCK_VSEL_MASK, + SPM8821_BUCK5_CTRL_REG, SMP8821_BUCK_EN_MASK, + spm8821_buck_ranges), + + SPM8821_DESC(SPM8821_ID_DCDC6, "DCDC_REG6", "vcc_sys", + 255, SPM8821_BUCK6_VSEL_REG, SPM8821_BUCK_VSEL_MASK, + SPM8821_BUCK6_CTRL_REG, SMP8821_BUCK_EN_MASK, + spm8821_buck_ranges), + /* ALDO */ + SPM8821_DESC(SPM8821_ID_LDO1, "LDO_REG1", "vcc_sys", + 128, SPM8821_ALDO1_VOLT_REG, SPM8821_ALDO_VSEL_MASK, + SPM8821_ALDO1_CTRL_REG, SPM8821_ALDO_EN_MASK, spm8821_ldo_ranges), + + SPM8821_DESC(SPM8821_ID_LDO2, "LDO_REG2", "vcc_sys", + 128, SPM8821_ALDO2_VOLT_REG, SPM8821_ALDO_VSEL_MASK, + SPM8821_ALDO2_CTRL_REG, SPM8821_ALDO_EN_MASK, spm8821_ldo_ranges), + + SPM8821_DESC(SPM8821_ID_LDO3, "LDO_REG3", "vcc_sys", + 128, SPM8821_ALDO3_VOLT_REG, SPM8821_ALDO_VSEL_MASK, + SPM8821_ALDO3_CTRL_REG, SPM8821_ALDO_EN_MASK, spm8821_ldo_ranges), + + SPM8821_DESC(SPM8821_ID_LDO4, "LDO_REG4", "vcc_sys", + 128, SPM8821_ALDO4_VOLT_REG, SPM8821_ALDO_VSEL_MASK, + SPM8821_ALDO4_CTRL_REG, SPM8821_ALDO_EN_MASK, spm8821_ldo_ranges), + + /* DLDO */ + SPM8821_DESC(SPM8821_ID_LDO5, "LDO_REG5", "dcdc5", + 128, SPM8821_DLDO1_VOLT_REG, SPM8821_DLDO_VSEL_MASK, + SPM8821_DLDO1_CTRL_REG, SPM8821_DLDO_EN_MASK, spm8821_ldo_ranges), + + SPM8821_DESC(SPM8821_ID_LDO6, "LDO_REG6", "dcdc5", + 128, SPM8821_DLDO2_VOLT_REG, SPM8821_DLDO_VSEL_MASK, + SPM8821_DLDO2_CTRL_REG, SPM8821_DLDO_EN_MASK, spm8821_ldo_ranges), + + SPM8821_DESC(SPM8821_ID_LDO7, "LDO_REG7", "dcdc5", + 128, SPM8821_DLDO3_VOLT_REG, SPM8821_DLDO_VSEL_MASK, + SPM8821_DLDO3_CTRL_REG, SPM8821_DLDO_EN_MASK, spm8821_ldo_ranges), + + SPM8821_DESC(SPM8821_ID_LDO8, "LDO_REG8", "dcdc5", + 128, SPM8821_DLDO4_VOLT_REG, SPM8821_DLDO_VSEL_MASK, + SPM8821_DLDO4_CTRL_REG, SPM8821_DLDO_EN_MASK, spm8821_ldo_ranges), + + SPM8821_DESC(SPM8821_ID_LDO9, "LDO_REG9", "dcdc5", + 128, SPM8821_DLDO5_VOLT_REG, SPM8821_DLDO_VSEL_MASK, + SPM8821_DLDO5_CTRL_REG, SPM8821_DLDO_EN_MASK, spm8821_ldo_ranges), + + SPM8821_DESC(SPM8821_ID_LDO10, "LDO_REG10", "dcdc5", + 128, SPM8821_DLDO6_VOLT_REG, SPM8821_DLDO_VSEL_MASK, + SPM8821_DLDO6_CTRL_REG, SPM8821_DLDO_EN_MASK, spm8821_ldo_ranges), + + SPM8821_DESC(SPM8821_ID_LDO11, "LDO_REG11", "dcdc5", + 128, SPM8821_DLDO7_VOLT_REG, SPM8821_DLDO_VSEL_MASK, + SPM8821_DLDO7_CTRL_REG, SPM8821_DLDO_EN_MASK, spm8821_ldo_ranges), + + /* PWR SWITCH */ + SPM8821_DESC_SWITCH(SPM8821_ID_SWITCH1, "SWITCH_REG1", "vcc_sys", + SPM8821_SWITCH_CTRL_REG, SPM8821_SWTICH_EN_MASK), +}; + +static struct spacemit_pmic_regulator_data spm8821_regulator_data = +{ + .desc = spm8821_reg, + .desc_nr = RT_ARRAY_SIZE(spm8821_reg), + .sleep_reg_offset = SPM8821_SLEEP_REG_OFFSET, +}; +#endif /* __SPACEMIT_REGULATOR_INTERNAL */ + +#ifdef __SPACEMIT_PINCTRL_INTERNAL +const char *spm8821_pinmux_functions[] = +{ + "gpioin", "gpioout", "exten", "pwrctrl", "sleep", "nreset", "adcin" +}; + +static const struct spacemit_pmic_pin_func_desc spm8821_pinfunc_desc[] = +{ + /* PIN0 gpioin */ + SPM8XX_DESC_PIN_FUNC_COM(0, "gpioin", 0x8, 0x3, 0, 0, 0, 0, 0), + /* PIN0 gpioout*/ + SPM8XX_DESC_PIN_FUNC_COM(0, "gpioout", 0x8, 0x3, 1, 0, 0, 0, 0), + /* PIN0 exten */ + SPM8XX_DESC_PIN_FUNC_COM(0, "exten", 0x8, 0x3, 0x3, 1, 0xa, 0x7, 0x0), + /* PIN0 pwrctrl */ + SPM8XX_DESC_PIN_FUNC_COM(0, "pwrctrl", 0x8, 0x3, 0x3, 1, 0xa, 0x7, 0x1), + /* PIN0 sleep */ + SPM8XX_DESC_PIN_FUNC_COM(0, "sleep", 0x8, 0x3, 0x3, 1, 0xa, 0x7, 0x2), + /* PIN0 nreset */ + SPM8XX_DESC_PIN_FUNC_COM(0, "nreset", 0x8, 0x3, 0x3, 1, 0xa, 0x7, 0x3), + /* PIN0 adcin */ + SPM8XX_DESC_PIN_FUNC_COM(0, "adcin", 0x8, 0x3, 0x3, 1, 0xa, 0x7, 0x4), + /* PIN1 gpioin */ + SPM8XX_DESC_PIN_FUNC_COM(1, "gpioin", 0x8, 0xc, 0, 0, 0, 0, 0), + /* PIN1 gpioout*/ + SPM8XX_DESC_PIN_FUNC_COM(1, "gpioout", 0x8, 0xc, 1, 0, 0, 0, 0), + /* PIN1 exten */ + SPM8XX_DESC_PIN_FUNC_COM(1, "exten", 0x8, 0xc, 0x3, 1, 0xa, 0x38, 0x0), + /* PIN1 pwrctrl */ + SPM8XX_DESC_PIN_FUNC_COM(1, "pwrctrl", 0x8, 0xc, 0x3, 1, 0xa, 0x38, 0x1), + /* PIN1 sleep */ + SPM8XX_DESC_PIN_FUNC_COM(1, "sleep", 0x8, 0xc, 0x3, 1, 0xa, 0x38, 0x2), + /* PIN1 nreset */ + SPM8XX_DESC_PIN_FUNC_COM(1, "nreset", 0x8, 0xc, 0x3, 1, 0xa, 0x38, 0x3), + /* PIN1 adcin */ + SPM8XX_DESC_PIN_FUNC_COM(1, "adcin", 0x8, 0xc, 0x3, 1, 0xa, 0x38, 0x4), + /* PIN2 gpioin */ + SPM8XX_DESC_PIN_FUNC_COM(2, "gpioin", 0x8, 0x30, 0, 0, 0, 0, 0), + /* PIN2 gpioout*/ + SPM8XX_DESC_PIN_FUNC_COM(2, "gpioout", 0x8, 0x30, 1, 0, 0, 0, 0), + /* PIN2 exten */ + SPM8XX_DESC_PIN_FUNC_COM(2, "exten", 0x8, 0x30, 0x3, 1, 0xb, 0x7, 0x0), + /* PIN2 pwrctrl */ + SPM8XX_DESC_PIN_FUNC_COM(2, "pwrctrl", 0x8, 0x30, 0x3, 1, 0xb, 0x7, 0x1), + /* PIN2 sleep */ + SPM8XX_DESC_PIN_FUNC_COM(2, "sleep", 0x8, 0x30, 0x3, 1, 0xb, 0x7, 0x2), + /* PIN2 nreset */ + SPM8XX_DESC_PIN_FUNC_COM(2, "nreset", 0x8, 0x30, 0x3, 1, 0xb, 0x7, 0x3), + /* PIN2 adcin */ + SPM8XX_DESC_PIN_FUNC_COM(2, "adcin", 0x8, 0x30, 0x3, 1, 0xb, 0x7, 0x4), + /* PIN3 gpioin */ + SPM8XX_DESC_PIN_FUNC_COM(3, "gpioin", 0x9, 0x3, 0, 0, 0, 0, 0), + /* PIN3 gpioout*/ + SPM8XX_DESC_PIN_FUNC_COM(3, "gpioout", 0x9, 0x3, 1, 0, 0, 0, 0), + /* PIN3 exten */ + SPM8XX_DESC_PIN_FUNC_COM(3, "exten", 0x9, 0x3, 0x3, 1, 0xb, 0x38, 0x0), + /* PIN3 pwrctrl */ + SPM8XX_DESC_PIN_FUNC_COM(3, "pwrctrl", 0x9, 0x3, 0x3, 1, 0xb, 0x38, 0x1), + /* PIN3 sleep */ + SPM8XX_DESC_PIN_FUNC_COM(3, "sleep", 0x9, 0x3, 0x3, 1, 0xb, 0x38, 0x2), + /* PIN3 nreset */ + SPM8XX_DESC_PIN_FUNC_COM(3, "nreset", 0x9, 0x3, 0x3, 1, 0xb, 0x38, 0x3), + /* PIN3 adcin */ + SPM8XX_DESC_PIN_FUNC_COM(3, "adcin", 0x9, 0x3, 0x3, 1, 0xb, 0x38, 0x4), + /* PIN4 gpioin */ + SPM8XX_DESC_PIN_FUNC_COM(4, "gpioin", 0x9, 0xc, 0, 0, 0, 0, 0), + /* PIN4 gpioout*/ + SPM8XX_DESC_PIN_FUNC_COM(4, "gpioout", 0x9, 0xc, 1, 0, 0, 0, 0), + /* PIN4 exten */ + SPM8XX_DESC_PIN_FUNC_COM(4, "exten", 0x9, 0xc, 0x3, 1, 0xc, 0x7, 0x0), + /* PIN4 pwrctrl */ + SPM8XX_DESC_PIN_FUNC_COM(4, "pwrctrl", 0x9, 0xc, 0x3, 1, 0xc, 0x7, 0x1), + /* PIN4 sleep */ + SPM8XX_DESC_PIN_FUNC_COM(4, "sleep", 0x9, 0xc, 0x3, 1, 0xc, 0x7, 0x2), + /* PIN4 nreset */ + SPM8XX_DESC_PIN_FUNC_COM(4, "nreset", 0x9, 0xc, 0x3, 1, 0xc, 0x7, 0x3), + /* PIN4 adcin */ + SPM8XX_DESC_PIN_FUNC_COM(4, "adcin", 0x9, 0xc, 0x3, 1, 0xc, 0x7, 0x4), + /* PIN5 gpioin */ + SPM8XX_DESC_PIN_FUNC_COM(5, "gpioin", 0x9, 0x30, 0, 0, 0, 0, 0), + /* PIN5 gpioout*/ + SPM8XX_DESC_PIN_FUNC_COM(5, "gpioout", 0x9, 0x30, 1, 0, 0, 0, 0), + /* PIN5 exten */ + SPM8XX_DESC_PIN_FUNC_COM(5, "exten", 0x9, 0x30, 0x3, 1, 0xc, 0x38, 0x0), + /* PIN5 pwrctrl */ + SPM8XX_DESC_PIN_FUNC_COM(5, "pwrctrl", 0x9, 0x30, 0x3, 1, 0xc, 0x38, 0x1), + /* PIN5 sleep */ + SPM8XX_DESC_PIN_FUNC_COM(5, "sleep", 0x9, 0x30, 0x3, 1, 0xc, 0x38, 0x2), + /* PIN5 nreset */ + SPM8XX_DESC_PIN_FUNC_COM(5, "nreset", 0x9, 0x30, 0x3, 1, 0xc, 0x38, 0x3), + /* PIN5 adcin */ + SPM8XX_DESC_PIN_FUNC_COM(5, "adcin", 0x9, 0x30, 0x3, 1, 0xc, 0x38, 0x4), +}; + +static const struct spacemit_pmic_pin_config_desc spm8821_pinconfig_desc[] = +{ + SPM8XX_DESC_PIN_CONFIG_COM(0, 0x0, 0x1, 0x1, 0x1, 0x2, 0x3, 0x4, 0xc0, 0x1, 0x5, 0x1, 0x6, 0x3), + SPM8XX_DESC_PIN_CONFIG_COM(1, 0x0, 0x2, 0x1, 0x2, 0x2, 0xc, 0x4, 0xc0, 0x2, 0x5, 0x2, 0x6, 0xc), + SPM8XX_DESC_PIN_CONFIG_COM(2, 0x0, 0x4, 0x1, 0x4, 0x2, 0x30, 0x4, 0xc0, 0x4, 0x5, 0x4, 0x6, 0x30), + SPM8XX_DESC_PIN_CONFIG_COM(3, 0x0, 0x8, 0x1, 0x8, 0x3, 0x3, 0x4, 0xc0, 0x8, 0x5, 0x8, 0x7, 0x3), + SPM8XX_DESC_PIN_CONFIG_COM(4, 0x0, 0x10, 0x1, 0x10, 0x3, 0xc, 0x4, 0xc0, 0x10, 0x5, 0x10, 0x7, 0xc), + SPM8XX_DESC_PIN_CONFIG_COM(5, 0x0, 0x20, 0x1, 0x20, 0x3, 0x30, 0x4, 0xc0, 0x20, 0x5, 0x20, 0x7, 0x30), +}; + +static const struct spacemit_pmic_pin_data spm8821_pinctrl_data = +{ + .pin_mux_nr = RT_ARRAY_SIZE(spm8821_pinmux_functions), + .pinmux_funcs = spm8821_pinmux_functions, + .pin_fuc_desc_nr = RT_ARRAY_SIZE(spm8821_pinfunc_desc), + .pinfunc_desc = spm8821_pinfunc_desc, + .pin_conf_desc_nr = RT_ARRAY_SIZE(spm8821_pinconfig_desc), + .pinconf_desc = spm8821_pinconfig_desc, +}; +#endif /* __SPACEMIT_PINCTRL_INTERNAL */ + +#ifdef __SPACEMIT_ADC_INTERNAL +static struct spacemit_pmic_iio_chan_spec spm8821_iio_desc[] = +{ + { + .channel = 0, + }, + { + .channel = 1, + }, + { + .channel = 2, + }, + { + .channel = 3, + }, + { + .channel = 4, + }, + { + .channel = 5, + }, +}; + +static const struct spacemit_pmic_adc_data spm8821_adc_data = +{ + .iio_desc = spm8821_iio_desc, + .iio_desc_nr = RT_ARRAY_SIZE(spm8821_iio_desc), +}; +#endif /* __SPACEMIT_ADC_INTERNAL */ + +#ifdef __SPACEMIT_RTC_INTERNAL +static const struct spacemit_pmic_rtc_regdesc spm8821_regdesc = +{ + .cnt_s = + { + .reg = 0xd, + .msk = 0x3f, + }, + .cnt_mi = + { + .reg = 0xe, + .msk = 0x3f, + }, + .cnt_h = + { + .reg = 0xf, + .msk = 0x1f, + }, + .cnt_d = + { + .reg = 0x10, + .msk = 0x1f, + }, + .cnt_mo = + { + .reg = 0x11, + .msk = 0xf, + }, + .cnt_y = + { + .reg = 0x12, + .msk = 0x3f, + }, + .alarm_s = + { + .reg = 0x13, + .msk = 0x3f, + }, + .alarm_mi = + { + .reg = 0x14, + .msk = 0x3f, + }, + .alarm_h = + { + .reg = 0x15, + .msk = 0x1f, + }, + .alarm_d = + { + .reg = 0x16, + .msk = 0x1f, + }, + .alarm_mo = + { + .reg = 0x17, + .msk = 0xf, + }, + .alarm_y = + { + .reg = 0x18, + .msk = 0x3f, + }, + .rtc_ctl = + { + .reg = 0x1d, + }, +}; +#endif /* __SPACEMIT_RTC_INTERNAL */ + +#ifdef __SPACEMIT_PMIC_INTERNAL +enum +{ + /* reg: 0x91 */ + SPM8821_E_GPI0, + SPM8821_E_GPI1, + SPM8821_E_GPI2, + SPM8821_E_GPI3, + SPM8821_E_GPI4, + SPM8821_E_GPI5, + + /* reg: 0x92 */ + SPM8821_E_ADC_TEMP, + SPM8821_E_ADC_EOC, + SPM8821_E_ADC_EOS, + SPM8821_E_WDT_TO, + SPM8821_E_ALARM, + SPM8821_E_TICK, + + /* reg: 0x93 */ + SPM8821_E_LDO_OV, + SPM8821_E_LDO_UV, + SPM8821_E_LDO_SC, + SPM8821_E_SW_SC, + SPM8821_E_TEMP_WARN, + SPM8821_E_TEMP_SEVERE, + SPM8821_E_TEMP_CRIT, + + /* reg: 0x94 */ + SPM8821_E_BUCK1_OV, + SPM8821_E_BUCK2_OV, + SPM8821_E_BUCK3_OV, + SPM8821_E_BUCK4_OV, + SPM8821_E_BUCK5_OV, + SPM8821_E_BUCK6_OV, + + /* reg: 0x95 */ + SPM8821_E_BUCK1_UV, + SPM8821_E_BUCK2_UV, + SPM8821_E_BUCK3_UV, + SPM8821_E_BUCK4_UV, + SPM8821_E_BUCK5_UV, + SPM8821_E_BUCK6_UV, + + /* reg: 0x96 */ + SPM8821_E_BUCK1_SC, + SPM8821_E_BUCK2_SC, + SPM8821_E_BUCK3_SC, + SPM8821_E_BUCK4_SC, + SPM8821_E_BUCK5_SC, + SPM8821_E_BUCK6_SC, + + /* reg: 0x97 */ + SPM8821_E_PWRON_RINTR, + SPM8821_E_PWRON_FINTR, + SPM8821_E_PWRON_SINTR, + SPM8821_E_PWRON_LINTR, + SPM8821_E_PWRON_SDINTR, + SPM8821_E_VSYS_OV, +}; + +#define SPM8821_E_GPI0_MSK RT_BIT(0) +#define SPM8821_E_GPI1_MSK RT_BIT(1) +#define SPM8821_E_GPI2_MSK RT_BIT(2) +#define SPM8821_E_GPI3_MSK RT_BIT(3) +#define SPM8821_E_GPI4_MSK RT_BIT(4) +#define SPM8821_E_GPI5_MSK RT_BIT(5) + +#define SPM8821_E_ADC_TEMP_MSK RT_BIT(0) +#define SPM8821_E_ADC_EOC_MSK RT_BIT(1) +#define SPM8821_E_ADC_EOS_MSK RT_BIT(2) +#define SPM8821_E_WDT_TO_MSK RT_BIT(3) +#define SPM8821_E_ALARM_MSK RT_BIT(4) +#define SPM8821_E_TICK_MSK RT_BIT(5) + +#define SPM8821_E_LDO_OV_MSK RT_BIT(0) +#define SPM8821_E_LDO_UV_MSK RT_BIT(1) +#define SPM8821_E_LDO_SC_MSK RT_BIT(2) +#define SPM8821_E_SW_SC_MSK RT_BIT(3) +#define SPM8821_E_TEMP_WARN_MSK RT_BIT(4) +#define SPM8821_E_TEMP_SEVERE_MSK RT_BIT(5) +#define SPM8821_E_TEMP_CRIT_MSK RT_BIT(6) + +#define SPM8821_E_BUCK1_OV_MSK RT_BIT(0) +#define SPM8821_E_BUCK2_OV_MSK RT_BIT(1) +#define SPM8821_E_BUCK3_OV_MSK RT_BIT(2) +#define SPM8821_E_BUCK4_OV_MSK RT_BIT(3) +#define SPM8821_E_BUCK5_OV_MSK RT_BIT(4) +#define SPM8821_E_BUCK6_OV_MSK RT_BIT(5) + +#define SPM8821_E_BUCK1_UV_MSK RT_BIT(0) +#define SPM8821_E_BUCK2_UV_MSK RT_BIT(1) +#define SPM8821_E_BUCK3_UV_MSK RT_BIT(2) +#define SPM8821_E_BUCK4_UV_MSK RT_BIT(3) +#define SPM8821_E_BUCK5_UV_MSK RT_BIT(4) +#define SPM8821_E_BUCK6_UV_MSK RT_BIT(5) + +#define SPM8821_E_BUCK1_SC_MSK RT_BIT(0) +#define SPM8821_E_BUCK2_SC_MSK RT_BIT(1) +#define SPM8821_E_BUCK3_SC_MSK RT_BIT(2) +#define SPM8821_E_BUCK4_SC_MSK RT_BIT(3) +#define SPM8821_E_BUCK5_SC_MSK RT_BIT(4) +#define SPM8821_E_BUCK6_SC_MSK RT_BIT(5) + +#define SPM8821_E_PWRON_RINTR_MSK RT_BIT(0) +#define SPM8821_E_PWRON_FINTR_MSK RT_BIT(1) +#define SPM8821_E_PWRON_SINTR_MSK RT_BIT(2) +#define SPM8821_E_PWRON_LINTR_MSK RT_BIT(3) +#define SPM8821_E_PWRON_SDINTR_MSK RT_BIT(4) +#define SPM8821_E_VSYS_OV_MSK RT_BIT(5) + +static const struct spacemit_pmic_irq_map spm8821_irqs[] = +{ + [SPM8821_E_GPI0] = + { + .mask = SPM8821_E_GPI0_MSK, + .reg_offset = 0, + }, + [SPM8821_E_GPI1] = + { + .mask = SPM8821_E_GPI1_MSK, + .reg_offset = 0, + }, + [SPM8821_E_GPI2] = + { + .mask = SPM8821_E_GPI2_MSK, + .reg_offset = 0, + }, + [SPM8821_E_GPI3] = + { + .mask = SPM8821_E_GPI3_MSK, + .reg_offset = 0, + }, + [SPM8821_E_GPI4] = + { + .mask = SPM8821_E_GPI4_MSK, + .reg_offset = 0, + }, + [SPM8821_E_GPI5] = + { + .mask = SPM8821_E_GPI5_MSK, + .reg_offset = 0, + }, + [SPM8821_E_ADC_TEMP] = + { + .mask = SPM8821_E_ADC_TEMP_MSK, + .reg_offset = 1, + }, + [SPM8821_E_ADC_EOC] = + { + .mask = SPM8821_E_ADC_EOC_MSK, + .reg_offset = 1, + }, + [SPM8821_E_ADC_EOS] = + { + .mask = SPM8821_E_ADC_EOS_MSK, + .reg_offset = 1, + }, + [SPM8821_E_WDT_TO] = + { + .mask = SPM8821_E_WDT_TO_MSK, + .reg_offset = 1, + }, + [SPM8821_E_ALARM] = + { + .mask = SPM8821_E_ALARM_MSK, + .reg_offset = 1, + }, + [SPM8821_E_TICK] = + { + .mask = SPM8821_E_TICK_MSK, + .reg_offset = 1, + }, + [SPM8821_E_LDO_OV] = + { + .mask = SPM8821_E_LDO_OV_MSK, + .reg_offset = 2, + }, + [SPM8821_E_LDO_UV] = + { + .mask = SPM8821_E_LDO_UV_MSK, + .reg_offset = 2, + }, + [SPM8821_E_LDO_SC] = + { + .mask = SPM8821_E_LDO_SC_MSK, + .reg_offset = 2, + }, + [SPM8821_E_SW_SC] = + { + .mask = SPM8821_E_SW_SC_MSK, + .reg_offset = 2, + }, + [SPM8821_E_TEMP_WARN] = + { + .mask = SPM8821_E_TEMP_WARN_MSK, + .reg_offset = 2, + }, + [SPM8821_E_TEMP_SEVERE] = + { + .mask = SPM8821_E_TEMP_SEVERE_MSK, + .reg_offset = 2, + }, + [SPM8821_E_TEMP_CRIT] = + { + .mask = SPM8821_E_TEMP_CRIT_MSK, + .reg_offset = 2, + }, + [SPM8821_E_BUCK1_OV] = + { + .mask = SPM8821_E_BUCK1_OV_MSK, + .reg_offset = 3, + }, + [SPM8821_E_BUCK2_OV] = + { + .mask = SPM8821_E_BUCK2_OV_MSK, + .reg_offset = 3, + }, + [SPM8821_E_BUCK3_OV] = + { + .mask = SPM8821_E_BUCK3_OV_MSK, + .reg_offset = 3, + }, + [SPM8821_E_BUCK4_OV] = + { + .mask = SPM8821_E_BUCK4_OV_MSK, + .reg_offset = 3, + }, + [SPM8821_E_BUCK5_OV] = + { + .mask = SPM8821_E_BUCK5_OV_MSK, + .reg_offset = 3, + }, + [SPM8821_E_BUCK6_OV] = + { + .mask = SPM8821_E_BUCK6_OV_MSK, + .reg_offset = 3, + }, + [SPM8821_E_BUCK1_UV] = + { + .mask = SPM8821_E_BUCK1_UV_MSK, + .reg_offset = 4, + }, + [SPM8821_E_BUCK2_UV] = + { + .mask = SPM8821_E_BUCK2_UV_MSK, + .reg_offset = 4, + }, + [SPM8821_E_BUCK3_UV] = + { + .mask = SPM8821_E_BUCK3_UV_MSK, + .reg_offset = 4, + }, + [SPM8821_E_BUCK4_UV] = + { + .mask = SPM8821_E_BUCK4_UV_MSK, + .reg_offset = 4, + }, + [SPM8821_E_BUCK5_UV] = + { + .mask = SPM8821_E_BUCK5_UV_MSK, + .reg_offset = 4, + }, + [SPM8821_E_BUCK6_UV] = + { + .mask = SPM8821_E_BUCK6_UV_MSK, + .reg_offset = 4, + }, + [SPM8821_E_BUCK1_SC] = + { + .mask = SPM8821_E_BUCK1_SC_MSK, + .reg_offset = 5, + }, + [SPM8821_E_BUCK2_SC] = + { + .mask = SPM8821_E_BUCK2_SC_MSK, + .reg_offset = 5, + }, + [SPM8821_E_BUCK3_SC] = + { + .mask = SPM8821_E_BUCK3_SC_MSK, + .reg_offset = 5, + }, + [SPM8821_E_BUCK4_SC] = + { + .mask = SPM8821_E_BUCK4_SC_MSK, + .reg_offset = 5, + }, + [SPM8821_E_BUCK5_SC] = + { + .mask = SPM8821_E_BUCK5_SC_MSK, + .reg_offset = 5, + }, + [SPM8821_E_BUCK6_SC] = + { + .mask = SPM8821_E_BUCK6_SC_MSK, + .reg_offset = 5, + }, + [SPM8821_E_PWRON_RINTR] = + { + .mask = SPM8821_E_PWRON_RINTR_MSK, + .reg_offset = 6, + }, + [SPM8821_E_PWRON_FINTR] = + { + .mask = SPM8821_E_PWRON_FINTR_MSK, + .reg_offset = 6, + }, + [SPM8821_E_PWRON_SINTR] = + { + .mask = SPM8821_E_PWRON_SINTR_MSK, + .reg_offset = 6, + }, + [SPM8821_E_PWRON_LINTR] = + { + .mask = SPM8821_E_PWRON_LINTR_MSK, + .reg_offset = 6, + }, + [SPM8821_E_PWRON_SDINTR] = + { + .mask = SPM8821_E_PWRON_SDINTR_MSK, + .reg_offset = 6, + }, + [SPM8821_E_VSYS_OV] = + { + .mask = SPM8821_E_VSYS_OV_MSK, + .reg_offset = 6, + }, +}; + +static rt_uint32_t spm8821_irq_status[7]; + +static struct spacemit_pmic_irqchip spm8821_irq_chip = +{ + .num_regs = RT_ARRAY_SIZE(spm8821_irq_status), + .irq_status = spm8821_irq_status, + .reg_stride = 1, + .status_base = SPM8821_E_STATUS_REG_BASE, + .mask_base = SPM8821_E_EN_REG_BASE, + .ack_base = SPM8821_E_STATUS_REG_BASE, + .init_ack_masked = RT_TRUE, + .mask_unmask_non_inverted = RT_TRUE, + .irqs_map = spm8821_irqs, + .irqs_nr = RT_ARRAY_SIZE(spm8821_irqs), +}; + +static const int spm8821_pwrkey_irqs[] = +{ + SPM8821_E_PWRON_RINTR, + SPM8821_E_PWRON_FINTR, + SPM8821_E_PWRON_SINTR, + SPM8821_E_PWRON_LINTR, +}; + +static const int spm8821_rtc_irqs[] = +{ + SPM8821_E_ALARM, +}; + +static const int spm8821_adc_irqs[] = +{ + SPM8821_E_ADC_EOC, +}; + +static struct spacemit_pmic_mfd_endpoint spm8821_mfd_endpoint[] = +{ + { + .ofw_name = "spacemit-regulator@spm8821", + .ofw_compatible = "pmic,regulator,spm8821", + }, + { + .ofw_name = "spacemit-pinctrl@spm8821", + .ofw_compatible = "pmic,pinctrl,spm8821", + }, + { + .ofw_name = "spacemit-pwrkey@spm8821", + .ofw_compatible = "pmic,pwrkey,spm8821", + .irqs_nr = RT_ARRAY_SIZE(spm8821_pwrkey_irqs), + .irqs_list = spm8821_pwrkey_irqs, + }, + { + .ofw_name = "spacemit-rtc@spm8821", + .ofw_compatible = "pmic,rtc,spm8821", + .irqs_nr = RT_ARRAY_SIZE(spm8821_rtc_irqs), + .irqs_list = spm8821_rtc_irqs, + }, + { + .ofw_name = "spacemit-adc@spm8821", + .ofw_compatible = "pmic,adc,spm8821", + .irqs_nr = RT_ARRAY_SIZE(spm8821_adc_irqs), + .irqs_list = spm8821_adc_irqs, + }, +}; + +static struct spacemit_pmic_mfd_data spm8821_mfd_data = +{ + .regmap_cfg = + { + .reg_bits = 8, + .val_bits = 8, + .max_register = SPACEMIT_SPM8821_MAX_REG, + }, + + .endpoint = spm8821_mfd_endpoint, + .endpoint_num = RT_ARRAY_SIZE(spm8821_mfd_endpoint), + + .irqchip = &spm8821_irq_chip, + + .shutdown = + { + .reg = SPM8821_PWR_CTRL2, + .bit = SPM8821_SW_SHUTDOWN_BIT_MSK, + }, + .reboot = + { + .reg = SPM8821_PWR_CTRL2, + .bit = SPM8821_SW_RESET_BIT_MSK, + }, + .non_reset = + { + .reg = SPM8821_NON_RESET_REG, + .bit = SPM8821_RESTART_CFG_BIT_MSK, + }, +}; +#endif /* __SPACEMIT_PMIC_INTERNAL */ + +#endif /* __SPM8821_H__ */ diff --git a/bsp/spacemit/dm/include/mfd/sy8810l.h b/bsp/spacemit/dm/include/mfd/sy8810l.h new file mode 100644 index 000000000000..e80a9c5ba2cb --- /dev/null +++ b/bsp/spacemit/dm/include/mfd/sy8810l.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#ifndef __SY8810L_H__ +#define __SY8810L_H__ + +enum +{ + SY8810L_ID_DCDC1, +}; + +#define SPACEMIT_SY8810L_MAX_REG 0x2 + +#define SY8810L_BUCK_VSEL_MASK 0x3f +#define SY8810L_BUCK_EN_MASK 0x80 + +#define SY8810L_BUCK_CTRL_REG 0x1 +#define SY8810L_BUCK_VSEL_REG 0x0 + +#define SY8810L_DESC(_id, _match, _supply, _nv, _vr, _vm, _er, _em, _lr) \ + SPACEMIT_PMIC_REGULATOR_DESC_COMMON(_id, _match, _supply, _nv, _vr, _vm, _er, _em, _lr, pmic_dcdc_ldo_ops) + +#ifdef __SPACEMIT_REGULATOR_INTERNAL +static const struct spacemit_pmic_regulator_range sy8810l_buck_ranges[] = +{ + SPACEMIT_PMIC_REGULATOR_RANGE(600000, 0x0, 0x5a, 10000), +}; + +static const struct spacemit_pmic_regulator_desc sy8810l_reg[] = +{ + /* BUCK */ + SY8810L_DESC(SY8810L_ID_DCDC1, "EDCDC_REG1", "dcdc1", + 91, SY8810L_BUCK_VSEL_REG, SY8810L_BUCK_VSEL_MASK, + SY8810L_BUCK_CTRL_REG, SY8810L_BUCK_EN_MASK, sy8810l_buck_ranges), +}; + +static struct spacemit_pmic_regulator_data sy8810l_regulator_data = +{ + .desc = sy8810l_reg, + .desc_nr = RT_ARRAY_SIZE(sy8810l_reg), +}; +#endif /* __SPACEMIT_REGULATOR_INTERNAL */ + +#ifdef __SPACEMIT_PMIC_INTERNAL +static struct spacemit_pmic_mfd_endpoint sy8810l_mfd_endpoint[] = +{ + { + .ofw_name = "spacemit-regulator@sy8810l", + .ofw_compatible = "pmic,regulator,sy8810l", + }, +}; + +static struct spacemit_pmic_mfd_data sy8810l_mfd_data = +{ + .regmap_cfg = + { + .reg_bits = 8, + .val_bits = 8, + .max_register = SPACEMIT_SY8810L_MAX_REG, + }, + .endpoint = sy8810l_mfd_endpoint, + .endpoint_num = RT_ARRAY_SIZE(sy8810l_mfd_endpoint), +}; +#endif /* __SPACEMIT_PMIC_INTERNAL */ + +#endif /* __SY8810L_H__ */ diff --git a/bsp/spacemit/dm/include/spacemit.h b/bsp/spacemit/dm/include/spacemit.h new file mode 100644 index 000000000000..587d5a3cd602 --- /dev/null +++ b/bsp/spacemit/dm/include/spacemit.h @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#ifndef __SPACEMIT_H__ +#define __SPACEMIT_H__ + +#include + +#define is_aligned(x, a) (((x) & ((typeof(x))(a) - 1)) == 0) + +#define readx_poll_timeout(OP, ADDR, VAL, COND, DELAY_US, TIMEOUT_US) \ +({ \ + rt_uint64_t timeout_us = (TIMEOUT_US); \ + rt_int64_t left_ns = timeout_us * 1000L; \ + rt_ubase_t delay_us = (DELAY_US); \ + rt_uint64_t delay_ns = delay_us * 1000L; \ + for (;;) \ + { \ + (VAL) = OP(ADDR); \ + if (COND) \ + { \ + break; \ + } \ + if (timeout_us && left_ns < 0) \ + { \ + (VAL) = OP(ADDR); \ + break; \ + } \ + if (delay_us) \ + { \ + rt_hw_us_delay(delay_us); \ + if (timeout_us) \ + { \ + left_ns -= delay_ns; \ + } \ + } \ + rt_hw_cpu_relax(); \ + if (timeout_us) \ + { \ + --left_ns; \ + } \ + } \ + (COND) ? RT_EOK : -RT_ETIMEOUT; \ +}) + +#define readl_poll_timeout(ADDR, VAL, COND, DELAY_US, TIMEOUT_US) \ + readx_poll_timeout(HWREG32, ADDR, VAL, COND, DELAY_US, TIMEOUT_US) + +rt_inline rt_uint32_t fls(rt_uint32_t val) +{ + rt_uint32_t bit = 32; + + if (!val) + return 0; + if (!(val & 0xffff0000u)) + { + val <<= 16; + bit -= 16; + } + if (!(val & 0xff000000u)) + { + val <<= 8; + bit -= 8; + } + if (!(val & 0xf0000000u)) + { + val <<= 4; + bit -= 4; + } + if (!(val & 0xc0000000u)) + { + val <<= 2; + bit -= 2; + } + if (!(val & 0x80000000u)) + { + bit -= 1; + } + + return bit; +} + +#ifdef ARCH_RISCV +#include + +/* TCM enable register */ +#define CSR_TCMCFG 0x5db +#define TCM_EN _UL(0x00000001) /* TCM Access Enable */ + +rt_inline rt_uint32_t tcm_override_readl(const volatile void *addr) +{ + rt_uint32_t val; + rt_ubase_t level, tcm_csr; + + level = rt_hw_local_irq_disable(); + tcm_csr = csr_read_clear(CSR_TCMCFG, TCM_EN); + val = HWREG32(addr); + csr_set(CSR_TCMCFG, tcm_csr); + rt_hw_local_irq_enable(level); + + return val; +} + +/* i/o write on the tcm override area */ +rt_inline void tcm_override_writel(volatile void *addr, rt_uint32_t val) +{ + rt_ubase_t level, tcm_csr; + + level = rt_hw_local_irq_disable(); + tcm_csr = csr_read_clear(CSR_TCMCFG, TCM_EN); + HWREG32(addr) = val; + csr_set(CSR_TCMCFG, tcm_csr); + rt_hw_local_irq_enable(level); +} +#endif /* ARCH_RISCV */ + +#endif /* __SPACEMIT_H__ */ diff --git a/bsp/spacemit/dm/include/v2d.h b/bsp/spacemit/dm/include/v2d.h new file mode 100644 index 000000000000..65327ba81d37 --- /dev/null +++ b/bsp/spacemit/dm/include/v2d.h @@ -0,0 +1,358 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#ifndef __SPACEMIT_V2D_H__ +#define __SPACEMIT_V2D_H__ + +#include +#include +#include + +#define V2D_BUFFER_MAX_SIZE (64U * 1024U * 1024U) + +typedef enum SPACEMIT_V2D_SCALER_MODE_E +{ + V2D_NO_SCALE =0, + V2D_SCALE_DOWN =1, + V2D_SCALE_UP =2, +} V2D_SCALER_MODE_E; + +typedef enum SPACEMIT_V2D_INPUT_LAYER_E +{ + V2D_INPUT_LAYER0 =0, + V2D_INPUT_LAYER1 =1, + V2D_INPUT_LAYER_NUM =2, +} V2D_INPUT_LAYER_E; + +typedef enum SPACEMIT_V2D_FUNCTION_MODE_E +{ + V2D_FUNC_DISABLE=0, + V2D_FUNC_ENABLE =1, +} V2D_FUNCTION_MODE_E; + +typedef enum SPACEMIT_V2D_DITHER_E +{ + V2D_NO_DITHER =0, + V2D_DITHER_4X4 =1, + V2D_DITHER_8X8 =2, +} V2D_DITHER_E; + +typedef enum SPACEMIT_V2D_ROTATE_ANGLE +{ + V2D_ROT_0 =0, + V2D_ROT_90 =1, + V2D_ROT_180 =2, + V2D_ROT_270 =3, + V2D_ROT_MIRROR =4, + V2D_ROT_FLIP =5, +} V2D_ROTATE_ANGLE_E; + +typedef enum SPACEMIT_V2D_BLENDCMD_E +{ + V2D_BLENDCMD_ALPHA = 0, + V2D_BLENDCMD_ROP2 = 1, + V2D_BLENDCMD_BUTT +} V2D_BLENDCMD_E; + +typedef enum SPACEMIT_V2D_MASKCMD_E +{ + V2D_MASKCMD_DISABLE = 0, + V2D_MASKCMD_NORMAL = 1, + V2D_MASKCMD_AS_VALUE = 2, + V2D_MASKCMD_BUTT +} V2D_MASKCMD_E; + +typedef enum SPACEMIT_V2D_BLENDALPHA_SOURCE_E +{ + V2D_BLENDALPHA_SOURCE_PIXEL = 0, + V2D_BLENDALPHA_SOURCE_GOLBAL = 1, + V2D_BLENDALPHA_SOURCE_MASK = 2, + V2D_BLENDALPHA_SOURCE_BUTT +} V2D_BLENDALPHA_SOURCE_E; + +typedef enum SPACEMIT_V2D_BLEND_PRE_ALPHA_FUNC_E +{ + V2D_BLEND_PRE_ALPHA_FUNC_DISABLE = 0, + V2D_BLEND_PRE_ALPHA_FUNC_GLOBAL_MULTI_SOURCE = 1, + V2D_BLEND_PRE_ALPHA_FUNC_MASK_MULTI_SOURCE = 2, + V2D_BLEND_PRE_ALPHA_FUNC_BUTT +} V2D_BLEND_PRE_ALPHA_FUNC_E; + +typedef enum SPACEMIT_V2D_BLEND_MODE_E +{ + V2D_BLEND_ZERO = 0x0, + V2D_BLEND_ONE, + V2D_BLEND_SRC_ALPHA, + V2D_BLEND_ONE_MINUS_SRC_ALPHA, + V2D_BLEND_DST_ALPHA, + V2D_BLEND_ONE_MINUS_DST_ALPHA, + V2D_BLEND_BUTT +}V2D_BLEND_MODE_E; + +typedef enum SPACEMIT_V2D_ROP2_MODE_E +{ + V2D_ROP2_BLACK =0, + V2D_ROP2_NOTMERGEPEN=1, + V2D_ROP2_MASKNOTPEN =2, + V2D_ROP2_NOTCOPYPEN =3, + V2D_ROP2_MASKPENNOT =4, + V2D_ROP2_NOT =5, + V2D_ROP2_XORPEN =6, + V2D_ROP2_NOTMASKPEN =7, + V2D_ROP2_MASKPEN =8, + V2D_ROP2_NOTXORPEN =9, + V2D_ROP2_NOP =10, + V2D_ROP2_MERGENOTPEN=11, + V2D_ROP2_COPYPEN =12, + V2D_ROP2_MERGEPENNOT=13, + V2D_ROP2_MERGEPEN =14, + V2D_ROP2_WHITE =15, + V2D_ROP2_BUTT =16 +}V2D_ROP2_MODE_E; + +typedef enum SPACEMIT_V2D_COLOR_FORMAT_E +{ + V2D_COLOR_FORMAT_RGB888 =0, + V2D_COLOR_FORMAT_RGBX8888 =1, + V2D_COLOR_FORMAT_RGBA8888 =2, + V2D_COLOR_FORMAT_ARGB8888 =3, + V2D_COLOR_FORMAT_RGB565 =4, + V2D_COLOR_FORMAT_NV12 =5, + V2D_COLOR_FORMAT_RGBA5658 =6, + V2D_COLOR_FORMAT_ARGB8565 =7, + V2D_COLOR_FORMAT_A8 =8, + V2D_COLOR_FORMAT_Y8 =9, + V2D_COLOR_FORMAT_L8_RGBA8888=10, + V2D_COLOR_FORMAT_L8_RGB888 =11, + V2D_COLOR_FORMAT_L8_RGB565 =12, + V2D_COLOR_FORMAT_BGR888 =13, + V2D_COLOR_FORMAT_BGRX8888 =14, + V2D_COLOR_FORMAT_BGRA8888 =15, + V2D_COLOR_FORMAT_ABGR8888 =16, + V2D_COLOR_FORMAT_BGR565 =17, + V2D_COLOR_FORMAT_NV21 =18, + V2D_COLOR_FORMAT_BGRA5658 =19, + V2D_COLOR_FORMAT_ABGR8565 =20, + V2D_COLOR_FORMAT_L8_BGRA8888=21, + V2D_COLOR_FORMAT_L8_BGR888 =22, + V2D_COLOR_FORMAT_L8_BGR565 =23, + V2D_COLOR_FORMAT_BUTT, +}V2D_COLOR_FORMAT_E; + +typedef enum SPACEMIT_V2D_CSC_MODE_E +{ + V2D_CSC_MODE_RGB_2_BT601WIDE =0, + V2D_CSC_MODE_BT601WIDE_2_RGB =1, + V2D_CSC_MODE_RGB_2_BT601NARROW =2, + V2D_CSC_MODE_BT601NARROW_2_RGB =3, + V2D_CSC_MODE_RGB_2_BT709WIDE =4, + V2D_CSC_MODE_BT709WIDE_2_RGB =5, + V2D_CSC_MODE_RGB_2_BT709NARROW =6, + V2D_CSC_MODE_BT709NARROW_2_RGB =7, + V2D_CSC_MODE_BT601WIDE_2_BT709WIDE =8, + V2D_CSC_MODE_BT601WIDE_2_BT709NARROW =9, + V2D_CSC_MODE_BT601WIDE_2_BT601NARROW =10, + V2D_CSC_MODE_BT601NARROW_2_BT709WIDE =11, + V2D_CSC_MODE_BT601NARROW_2_BT709NARROW =12, + V2D_CSC_MODE_BT601NARROW_2_BT601WIDE =13, + V2D_CSC_MODE_BT709WIDE_2_BT601WIDE =14, + V2D_CSC_MODE_BT709WIDE_2_BT601NARROW =15, + V2D_CSC_MODE_BT709WIDE_2_BT709NARROW =16, + V2D_CSC_MODE_BT709NARROW_2_BT601WIDE =17, + V2D_CSC_MODE_BT709NARROW_2_BT601NARROW =18, + V2D_CSC_MODE_BT709NARROW_2_BT709WIDE =19, + V2D_CSC_MODE_RGB_2_GREY =20, + V2D_CSC_MODE_RGB_2_RGB =21, + V2D_CSC_MODE_BUTT =22, +} V2D_CSC_MODE_E; + +typedef enum SPACEMIT_FBC_DECODER_MODE_E +{ + FBC_DECODER_MODE_SCAN_LINE =0, + FBC_DECODER_MODE_LDC_Y =1, + FBC_DECODER_MODE_LDC_UV =2, + FBC_DECODER_MODE_H264_32x16 =3, + FBC_DECODER_MODE_H265_32x32 =4, + FBC_DECODER_MODE_BUTT =5, +} FBC_DECODER_MODE_E; + +typedef enum SPACEMIT_FBC_DECODER_FORMAT_E +{ + FBC_DECODER_FORMAT_NV12 =0, + FBC_DECODER_FORMAT_RGB888 =1, + FBC_DECODER_FORMAT_ARGB8888 =2, + FBC_DECODER_FORMAT_RGB565 =3, + FBC_DECODER_FORMAT_BUTT =4, +} FBC_DECODER_FORMAT_E; + +typedef struct +{ + uint16_t x; /* left */ + uint16_t y; /* top */ + uint16_t w; /* crop width */ + uint16_t h; /* crop height */ +} V2D_AREA_S; + +typedef struct SPACEMIT_V2D_FILLCOLOR_S +{ + uint32_t colorvalue; + V2D_COLOR_FORMAT_E format; +} V2D_FILLCOLOR_S; + +typedef struct SPACEMIT_V2D_BACKGROUND_S +{ + V2D_FILLCOLOR_S fillcolor; + bool enable; +} V2D_BACKGROUND_S; + +typedef struct SPACEMIT_V2D_SOLIDCOLOR_S +{ + V2D_FILLCOLOR_S fillcolor; + bool enable; +} V2D_SOLIDCOLOR_S; + +typedef struct SPACEMIT_V2D_PALETTE_S +{ + uint8_t palVal[1024]; + int len; +} V2D_PALETTE_S; + +typedef struct SPACEMIT_FBC_DECODER_S +{ + int fd; + uint32_t headerAddr_h; + uint32_t headerAddr_l; + uint16_t bboxLeft; + uint16_t bboxRight; + uint16_t bboxTop; + uint16_t bboxBottom; + bool rgb_pack_en; + bool is_split; + FBC_DECODER_MODE_E enFbcdecMode; + FBC_DECODER_FORMAT_E enFbcdecFmt; +} FBC_DECODER_S; + +typedef FBC_DECODER_FORMAT_E FBC_ENCODER_FORMAT_E; +typedef struct SPACEMIT_FBC_ENCODER_S +{ + int fd; + int offset; + uint32_t headerAddr_h; + uint32_t headerAddr_l; + uint32_t payloadAddr_h; + uint32_t payloadAddr_l; + uint16_t bboxLeft; + uint16_t bboxRight; + uint16_t bboxTop; + uint16_t bboxBottom; + bool is_split; + FBC_ENCODER_FORMAT_E enFbcencFmt; +} FBC_ENCODER_S; + +typedef struct SPACEMIT_V2D_SURFACE_S +{ + struct + { + bool fbc_enable; + int fd; + int offset; + uint32_t phyaddr_y_l; + uint32_t phyaddr_y_h; + uint32_t phyaddr_uv_l; + uint32_t phyaddr_uv_h; + uint16_t w; + uint16_t h; + uint16_t stride; + V2D_COLOR_FORMAT_E format; + }; + union + { + FBC_DECODER_S fbcDecInfo; + FBC_ENCODER_S fbcEncInfo; + }; + V2D_SOLIDCOLOR_S solidcolor; +} V2D_SURFACE_S; + +typedef struct +{ + V2D_BLEND_MODE_E srcColorFactor; + V2D_BLEND_MODE_E dstColorFactor; + V2D_BLEND_MODE_E srcAlphaFactor; + V2D_BLEND_MODE_E dstAlphaFactor; +} V2D_BLEND_FACTOR_S; + +typedef struct +{ + V2D_ROP2_MODE_E colorRop2Code; + V2D_ROP2_MODE_E alphaRop2Code; +} V2D_ROP2_CODE_S; + +typedef struct +{ + V2D_BLENDALPHA_SOURCE_E blend_alpha_source; + V2D_BLEND_PRE_ALPHA_FUNC_E blend_pre_alpha_func; + uint8_t global_alpha; + union + { + V2D_BLEND_FACTOR_S stBlendFactor; + V2D_ROP2_CODE_S stRop2Code; + }; + V2D_AREA_S blend_area; +} V2D_BLEND_LAYER_CONF_S; + +typedef struct +{ + V2D_BLENDCMD_E blend_cmd; + V2D_BACKGROUND_S bgcolor; + V2D_MASKCMD_E mask_cmd; + V2D_AREA_S blend_mask_area; + V2D_BLEND_LAYER_CONF_S blendlayer[V2D_INPUT_LAYER_NUM]; +} V2D_BLEND_CONF_S; + +typedef struct +{ + V2D_SURFACE_S layer0; + V2D_SURFACE_S layer1; + V2D_SURFACE_S mask; + V2D_SURFACE_S dst; + V2D_AREA_S l0_rect; + V2D_AREA_S l1_rect; + V2D_AREA_S mask_rect; + V2D_AREA_S dst_rect; + V2D_BLEND_CONF_S blendconf; + V2D_ROTATE_ANGLE_E l0_rt; + V2D_ROTATE_ANGLE_E l1_rt; + V2D_CSC_MODE_E l0_csc; + V2D_CSC_MODE_E l1_csc; + V2D_DITHER_E dither; + V2D_PALETTE_S palette; +} V2D_PARAM_S; + +typedef struct +{ + V2D_PARAM_S param; + int32_t acquireFencefd; + int32_t completeFencefd; +} V2D_SUBMIT_TASK_S; + +typedef struct +{ + uint32_t size; + uint64_t phys_addr; + void *virt_addr; +} V2D_BUFFER_S; + +#define V2D_IOC_MAGIC 'V' +#define V2D_SUBMIT _IOWR(V2D_IOC_MAGIC, 0, V2D_SUBMIT_TASK_S) +#define V2D_ALLOC_BUFFER _IOWR(V2D_IOC_MAGIC, 1, V2D_BUFFER_S) +#define V2D_FREE_BUFFER _IOW(V2D_IOC_MAGIC, 2, V2D_BUFFER_S) +#define V2D_RESET _IO(V2D_IOC_MAGIC, 3) + +#endif /* __SPACEMIT_V2D_H__ */ diff --git a/bsp/spacemit/dm/input/SConscript b/bsp/spacemit/dm/input/SConscript new file mode 100644 index 000000000000..3d15055d62d2 --- /dev/null +++ b/bsp/spacemit/dm/input/SConscript @@ -0,0 +1,13 @@ +import os +from building import * + +cwd = GetCurrentDir() +objs = [] +list = os.listdir(cwd) + +for d in list: + path = os.path.join(cwd, d) + if os.path.isfile(os.path.join(path, 'SConscript')): + objs = objs + SConscript(os.path.join(d, 'SConscript')) + +Return('objs') diff --git a/bsp/spacemit/dm/input/misc/Kconfig b/bsp/spacemit/dm/input/misc/Kconfig new file mode 100644 index 000000000000..64e5bd720f68 --- /dev/null +++ b/bsp/spacemit/dm/input/misc/Kconfig @@ -0,0 +1,5 @@ +config RT_INPUT_MISC_PWRKEY_SPACEMIT_PMIC + bool "Spacemit PMIC power key support" + depends on RT_INPUT_MISC + depends on RT_MFD_SPACEMIT_PMIC + default n diff --git a/bsp/spacemit/dm/input/misc/SConscript b/bsp/spacemit/dm/input/misc/SConscript new file mode 100644 index 000000000000..c1f5f17ab6e9 --- /dev/null +++ b/bsp/spacemit/dm/input/misc/SConscript @@ -0,0 +1,13 @@ +from building import * + +group = [] +src = [] +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../../include'] + +if GetDepend(['RT_INPUT_MISC_PWRKEY_SPACEMIT_PMIC']): + src += ['pwrkey-spacemit-pmic.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/spacemit/dm/input/misc/pwrkey-spacemit-pmic.c b/bsp/spacemit/dm/input/misc/pwrkey-spacemit-pmic.c new file mode 100644 index 000000000000..28ac2d63bae1 --- /dev/null +++ b/bsp/spacemit/dm/input/misc/pwrkey-spacemit-pmic.c @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#define __SPACEMIT_PWRKEY_INTERNAL +#include + +struct spacemit_pmic_pwrkey +{ + struct rt_input_device parent; + + int fall_irq, rise_irq; + int s_key_irq, l_key_irq; +}; + +static void spacemit_pmic_pwrkey_fall_irq(int irqno, void *param) +{ + struct spacemit_pmic_pwrkey *pwr = param; + + rt_interrupt_enter(); + + rt_input_report_key(&pwr->parent, KEY_POWER, 1); + rt_input_sync(&pwr->parent); + + rt_interrupt_leave(); +} + +static void spacemit_pmic_pwrkey_rise_irq(int irqno, void *param) +{ + struct spacemit_pmic_pwrkey *pwr = param; + + rt_interrupt_enter(); + + rt_input_report_key(&pwr->parent, KEY_POWER, 0); + rt_input_sync(&pwr->parent); + + rt_interrupt_leave(); +} + +static void spacemit_pmic_pwrkey_skey_irq(int irqno, void *param) +{ + /* Do nothing by now */ +} + +static void spacemit_pmic_pwrkey_lkey_irq(int irqno, void *param) +{ + /* Do nothing by now */ +} + +static rt_err_t spacemit_pmic_pwrkey_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + struct rt_device *dev = &pdev->parent; + struct spacemit_pmic_pwrkey *pwr = rt_calloc(1, sizeof(*pwr)); + + if (!pwr) + { + return -RT_ENOMEM; + } + + if ((pwr->rise_irq = rt_dm_dev_get_irq(dev, 0)) < 0) + { + err = pwr->rise_irq; + goto _fail; + } + + if ((pwr->fall_irq = rt_dm_dev_get_irq(dev, 1)) < 0) + { + err = pwr->fall_irq; + goto _fail; + } + + if ((pwr->s_key_irq = rt_dm_dev_get_irq(dev, 2)) < 0) + { + err = pwr->s_key_irq; + goto _fail; + } + + if ((pwr->l_key_irq = rt_dm_dev_get_irq(dev, 3)) < 0) + { + err = pwr->l_key_irq; + goto _fail; + } + + rt_input_set_capability(&pwr->parent, EV_KEY, KEY_POWER); + + if ((err = rt_input_device_register(&pwr->parent))) + { + goto _fail; + } + + dev->user_data = pwr; + + rt_hw_interrupt_install(pwr->fall_irq, spacemit_pmic_pwrkey_fall_irq, pwr, "pwrkey-pmic-fall"); + rt_hw_interrupt_umask(pwr->fall_irq); + + rt_hw_interrupt_install(pwr->rise_irq, spacemit_pmic_pwrkey_rise_irq, pwr, "pwrkey-pmic-rise"); + rt_hw_interrupt_umask(pwr->rise_irq); + + rt_hw_interrupt_install(pwr->s_key_irq, spacemit_pmic_pwrkey_skey_irq, pwr, "pwrkey-pmic-skey"); + rt_hw_interrupt_umask(pwr->s_key_irq); + + rt_hw_interrupt_install(pwr->l_key_irq, spacemit_pmic_pwrkey_lkey_irq, pwr, "pwrkey-pmic-lkey"); + rt_hw_interrupt_umask(pwr->l_key_irq); + + return RT_EOK; + +_fail: + rt_free(pwr); + + return err; +} + +static rt_err_t spacemit_pmic_pwrkey_remove(struct rt_platform_device *pdev) +{ + struct spacemit_pmic_pwrkey *pwr = pdev->parent.user_data; + + rt_hw_interrupt_mask(pwr->fall_irq); + rt_pic_detach_irq(pwr->fall_irq, pwr); + + rt_hw_interrupt_mask(pwr->rise_irq); + rt_pic_detach_irq(pwr->rise_irq, pwr); + + rt_hw_interrupt_mask(pwr->s_key_irq); + rt_pic_detach_irq(pwr->s_key_irq, pwr); + + rt_hw_interrupt_mask(pwr->l_key_irq); + rt_pic_detach_irq(pwr->l_key_irq, pwr); + + rt_input_device_unregister(&pwr->parent); + + rt_free(pwr); + + return RT_EOK; +} + +static const struct rt_ofw_node_id spacemit_pmic_pwrkey_ofw_ids[] = +{ + { .compatible = "pmic,pwrkey,spm8821" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver spacemit_pmic_pwrkey_driver = +{ + .name = "spacemit-pmic-pwrkey", + .ids = spacemit_pmic_pwrkey_ofw_ids, + + .probe = spacemit_pmic_pwrkey_probe, + .remove = spacemit_pmic_pwrkey_remove, +}; +RT_PLATFORM_DRIVER_EXPORT(spacemit_pmic_pwrkey_driver); diff --git a/bsp/spacemit/dm/mailbox/Kconfig b/bsp/spacemit/dm/mailbox/Kconfig new file mode 100644 index 000000000000..b4f54b2dee3e --- /dev/null +++ b/bsp/spacemit/dm/mailbox/Kconfig @@ -0,0 +1,3 @@ +config RT_MBOX_K1X + bool "Spacemit K1pro Mailbox Support" + default n diff --git a/bsp/spacemit/dm/mailbox/SConscript b/bsp/spacemit/dm/mailbox/SConscript new file mode 100644 index 000000000000..176d261ed8ac --- /dev/null +++ b/bsp/spacemit/dm/mailbox/SConscript @@ -0,0 +1,12 @@ +from building import * + +cwd = GetCurrentDir() +src = [] +CPPPATH = [cwd + '/../include'] + +if GetDepend(['RT_MBOX_K1X']): + src += ['mailbox-k1x.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/spacemit/dm/mailbox/mailbox-k1x.c b/bsp/spacemit/dm/mailbox/mailbox-k1x.c new file mode 100644 index 000000000000..133908e9f064 --- /dev/null +++ b/bsp/spacemit/dm/mailbox/mailbox-k1x.c @@ -0,0 +1,270 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#include +#include + +#include + +#define DBG_TAG "mailbox.spacemit" +#define DBG_LVL DBG_INFO +#include + +#define SPACEMIT_NUM_CHANNELS 4 +#define SPACEMIT_TX_ACK_OFFSET 4 + +#define MBOX_REG_IPC_DW 0x00 +#define MBOX_REG_IPC_WDR 0x04 +#define MBOX_REG_ISRW 0x08 +#define MBOX_REG_ICR 0x0C +#define MBOX_REG_IIR 0x10 +#define MBOX_REG_RDR 0x14 + +struct spacemit_mailbox +{ + struct rt_mbox_controller parent; + + int irq; + void *regs; + rt_bool_t clk_enabled; + struct rt_clk *clk; + struct rt_reset_control *rstc; +}; + +#define raw_to_spacemit_mailbox(raw) rt_container_of(raw, struct spacemit_mailbox, parent) + +static rt_err_t spacemit_mailbox_request(struct rt_mbox_chan *chan) +{ + return RT_EOK; +} + +static void spacemit_mailbox_release(struct rt_mbox_chan *chan) +{ + struct spacemit_mailbox *sp_mbox = raw_to_spacemit_mailbox(chan->ctrl); + + HWREG32(sp_mbox->regs + MBOX_REG_ICR) = + RT_BIT(chan - sp_mbox->parent.chans); +} + +static rt_err_t spacemit_mailbox_send(struct rt_mbox_chan *chan, const void *data) +{ + struct spacemit_mailbox *sp_mbox = raw_to_spacemit_mailbox(chan->ctrl); + + HWREG32(sp_mbox->regs + MBOX_REG_ISRW) = + RT_BIT(chan - sp_mbox->parent.chans); + + return RT_EOK; +} + +static rt_bool_t spacemit_mailbox_peek(struct rt_mbox_chan *chan) +{ + struct spacemit_mailbox *sp_mbox = raw_to_spacemit_mailbox(chan->ctrl); + + return !!(HWREG32(sp_mbox->regs + MBOX_REG_RDR) & + RT_BIT(chan - sp_mbox->parent.chans)); +} + +static const struct rt_mbox_controller_ops spacemit_mailbox_ops = +{ + .request = spacemit_mailbox_request, + .release = spacemit_mailbox_release, + .send = spacemit_mailbox_send, + .peek = spacemit_mailbox_peek, +}; + +static void spacemit_mailbox_isr(int irqno, void *param) +{ + rt_uint32_t status, msg = 0; + struct rt_mbox_chan *chan; + struct spacemit_mailbox *sp_mbox = param; + + HWREG32(sp_mbox->regs + MBOX_REG_IIR) = 0; + + status = HWREG32(sp_mbox->regs + MBOX_REG_IIR); + + if (!(status & 0xff)) + { + return; + } + + for (int i = SPACEMIT_TX_ACK_OFFSET; i < SPACEMIT_NUM_CHANNELS + SPACEMIT_TX_ACK_OFFSET; ++i) + { + chan = &sp_mbox->parent.chans[i - SPACEMIT_TX_ACK_OFFSET]; + + if (!(status & RT_BIT(i))) + { + continue; + } + + /* Clear the irq pending */ + HWREG32(sp_mbox->regs + MBOX_REG_ICR) = 1 << i; + + rt_mbox_send_done(chan, 0); + } + + for (int i = 0; i < SPACEMIT_NUM_CHANNELS; ++i) + { + chan = &sp_mbox->parent.chans[i]; + + if (!(status & RT_BIT(i))) + { + continue; + } + + rt_mbox_recv(chan, &msg); + + /* Clear the irq pending */ + HWREG32(sp_mbox->regs + MBOX_REG_ICR) = RT_BIT(i); + + /* Then send an ack */ + HWREG32(sp_mbox->regs + MBOX_REG_ISRW) = RT_BIT(i + SPACEMIT_TX_ACK_OFFSET); + } +} + +static void spacemit_mailbox_free_resource(struct spacemit_mailbox *sp_mbox) +{ + if (sp_mbox->regs) + { + rt_iounmap(sp_mbox->regs); + } + + if (!rt_is_err_or_null(sp_mbox->clk)) + { + if (sp_mbox->clk_enabled) + { + rt_clk_disable_unprepare(sp_mbox->clk); + } + rt_clk_put(sp_mbox->clk); + } + + if (!rt_is_err_or_null(sp_mbox->rstc)) + { + rt_reset_control_put(sp_mbox->rstc); + } + + rt_free(sp_mbox); +} + +static rt_err_t spacemit_mailbox_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + struct rt_device *dev = &pdev->parent; + struct spacemit_mailbox *sp_mbox = rt_calloc(1, sizeof(*sp_mbox)); + + if (!sp_mbox) + { + return -RT_ENOMEM; + } + + sp_mbox->regs = rt_dm_dev_iomap(dev, 0); + + if (!sp_mbox->regs) + { + err = -RT_EIO; + goto _fail; + } + + sp_mbox->clk = rt_clk_get_by_name(dev, "core"); + + if (rt_is_err(sp_mbox->clk)) + { + err = rt_ptr_err(sp_mbox->clk); + goto _fail; + } + + if ((err = rt_clk_prepare_enable(sp_mbox->clk))) + { + goto _fail; + } + sp_mbox->clk_enabled = RT_TRUE; + + sp_mbox->rstc = rt_reset_control_get_by_name(dev, "core_reset"); + + if (rt_is_err(sp_mbox->rstc)) + { + err = rt_ptr_err(sp_mbox->rstc); + goto _fail; + } + + if ((err = rt_reset_control_deassert(sp_mbox->rstc))) + { + goto _fail; + } + + sp_mbox->irq = rt_dm_dev_get_irq(dev, 0); + + if (sp_mbox->irq < 0) + { + err = sp_mbox->irq; + goto _fail; + } + + rt_hw_interrupt_install(sp_mbox->irq, spacemit_mailbox_isr, sp_mbox, "sp_mbox"); + rt_hw_interrupt_umask(sp_mbox->irq); + + dev->user_data = sp_mbox; + + sp_mbox->parent.dev = dev; + sp_mbox->parent.num_chans = SPACEMIT_NUM_CHANNELS; + sp_mbox->parent.ops = &spacemit_mailbox_ops; + + if ((err = rt_mbox_controller_register(&sp_mbox->parent))) + { + goto _free_irq; + } + + return RT_EOK; + +_free_irq: + rt_hw_interrupt_mask(sp_mbox->irq); + rt_pic_detach_irq(sp_mbox->irq, sp_mbox); + +_fail: + spacemit_mailbox_free_resource(sp_mbox); + + return err; +} + +static rt_err_t spacemit_mailbox_remove(struct rt_platform_device *pdev) +{ + struct spacemit_mailbox *sp_mbox = pdev->parent.user_data; + + rt_hw_interrupt_mask(sp_mbox->irq); + rt_pic_detach_irq(sp_mbox->irq, sp_mbox); + + rt_mbox_controller_unregister(&sp_mbox->parent); + + spacemit_mailbox_free_resource(sp_mbox); + + return RT_EOK; +} + +static const struct rt_ofw_node_id spacemit_mailbox_ofw_ids[] = +{ + { .compatible = "spacemit,k1-x-mailbox", }, + { /* sentinel */ } +}; + +static struct rt_platform_driver spacemit_mailbox_driver = +{ + .name = "mailbox-spacemit", + .ids = spacemit_mailbox_ofw_ids, + + .probe = spacemit_mailbox_probe, + .remove = spacemit_mailbox_remove, +}; + +static int spacemit_mailbox_drv_register(void) +{ + rt_platform_driver_register(&spacemit_mailbox_driver); + + return 0; +} +INIT_SUBSYS_EXPORT(spacemit_mailbox_drv_register); diff --git a/bsp/spacemit/dm/mfd/Kconfig b/bsp/spacemit/dm/mfd/Kconfig new file mode 100644 index 000000000000..017cd0cad80b --- /dev/null +++ b/bsp/spacemit/dm/mfd/Kconfig @@ -0,0 +1,7 @@ +config RT_MFD_SPACEMIT_PMIC + bool "Spacemit Power Management Chip" + depends on RT_USING_PIC + depends on RT_USING_I2C + depends on RT_USING_OFW + select RT_MFD_SYSCON + default y diff --git a/bsp/spacemit/dm/mfd/SConscript b/bsp/spacemit/dm/mfd/SConscript new file mode 100644 index 000000000000..e188ee121125 --- /dev/null +++ b/bsp/spacemit/dm/mfd/SConscript @@ -0,0 +1,12 @@ +from building import * + +cwd = GetCurrentDir() +src = [] +CPPPATH = [cwd + '/../include'] + +if GetDepend(['RT_MFD_SPACEMIT_PMIC']): + src += ['spacemit-pmic.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/spacemit/dm/mfd/spacemit-pmic.c b/bsp/spacemit/dm/mfd/spacemit-pmic.c new file mode 100644 index 000000000000..3f042e39a856 --- /dev/null +++ b/bsp/spacemit/dm/mfd/spacemit-pmic.c @@ -0,0 +1,763 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#include +#include + +#define DBG_TAG "mfd.spacemit-pmic" +#define DBG_LVL DBG_INFO +#include + +#include +#define __SPACEMIT_PMIC_INTERNAL +#include + +#ifdef RT_USING_FINSH +#include +#endif + +struct restart_config_info +{ + const char *cmd; + uint32_t value; +}; + +static const struct restart_config_info config_info[] = +{ + /* Enter uboot fastboot mode after restart */ + { "fastboot", 1 }, + /* Enter uboot shell after restart */ + { "uboot", 2 }, +}; + +static rt_err_t spacemit_pmic_reboot(struct rt_device *dev, char *cmd) +{ + struct spacemit_pmic *pmic = dev->user_data; + const struct spacemit_pmic_mfd_data *mfd_data = pmic->mfd_data; + + if (cmd) + { + for (int i = 0; i < RT_ARRAY_SIZE(config_info); ++i) + { + if (!rt_strcmp(cmd, config_info[i].cmd)) + { + spacemit_pmic_update_bits(pmic, + mfd_data->non_reset.reg, + mfd_data->non_reset.bit, + config_info[i].value); + break; + } + } + } + + if (spacemit_pmic_update_bits(pmic, + mfd_data->reboot.reg, + mfd_data->reboot.bit, + mfd_data->reboot.bit)) + { + LOG_E("Failed to %s device", "reboot"); + } + + return RT_EOK; +} + +static rt_err_t spacemit_pmic_shutdown(struct rt_device *dev) +{ + struct spacemit_pmic *pmic = dev->user_data; + const struct spacemit_pmic_mfd_data *mfd_data = pmic->mfd_data; + + if (spacemit_pmic_update_bits(pmic, + mfd_data->shutdown.reg, + mfd_data->shutdown.bit, + mfd_data->shutdown.bit)) + { + LOG_E("Failed to %s device", "shutdown"); + } + + return RT_EOK; +} + +static void spacemit_pmic_irq_mask(struct rt_pic_irq *pirq) +{ + rt_err_t err; + unsigned value; + struct spacemit_pmic_irqchip *irqchip = raw_to_spacemit_pmic_irqchip(pirq->pic); + const struct spacemit_pmic_irq_map *irq_map = &irqchip->irqs_map[pirq->hwirq]; + + value = irqchip->mask_base + (irq_map->reg_offset / irqchip->reg_stride); + + err = spacemit_pmic_update_bits(irqchip->pmic, value, irq_map->mask, + irqchip->mask_unmask_non_inverted ? 0 : irq_map->mask); + + if (err) + { + LOG_E("Mask PMIC IRQ %d failed: %s", pirq->hwirq, rt_strerror(err)); + } +} + +static void spacemit_pmic_irq_unmask(struct rt_pic_irq *pirq) +{ + rt_err_t err; + unsigned value; + struct spacemit_pmic_irqchip *irqchip = raw_to_spacemit_pmic_irqchip(pirq->pic); + const struct spacemit_pmic_irq_map *irq_map = &irqchip->irqs_map[pirq->hwirq]; + + value = irqchip->mask_base + (irq_map->reg_offset / irqchip->reg_stride); + + err = spacemit_pmic_update_bits(irqchip->pmic, value, irq_map->mask, + irqchip->mask_unmask_non_inverted ? irq_map->mask : 0); + + if (err) + { + LOG_E("Unmask PMIC IRQ %d failed: %s", pirq->hwirq, rt_strerror(err)); + } +} + +static int spacemit_pmic_irq_map(struct rt_pic *pic, int hwirq, rt_uint32_t mode) +{ + int irq = -1; + struct rt_pic_irq *pirq = rt_pic_find_irq(pic, hwirq); + + if (pirq) + { + struct spacemit_pmic_irqchip *irqchip = raw_to_spacemit_pmic_irqchip(pic); + + irq = rt_pic_config_irq(pic, hwirq, hwirq); + pirq->mode = mode; + rt_pic_cascade(pirq, irqchip->pmic->irq); + } + + return irq; +} + +static rt_err_t spacemit_pmic_irq_parse(struct rt_pic *pic, struct rt_ofw_cell_args *args, struct rt_pic_irq *out_pirq) +{ + struct spacemit_pmic_irqchip *irqchip = raw_to_spacemit_pmic_irqchip(pic); + + if (args->args_count != 1) + { + return -RT_EINVAL; + } + + out_pirq->mode = rt_pic_irq_get_triger_mode(irqchip->pmic->irq); + out_pirq->hwirq = args->args[0]; + + return RT_EOK; +} + +const static struct rt_pic_ops spacemit_pmic_irq_ops = +{ + .name = "Spacemit-PMIC", + .irq_mask = spacemit_pmic_irq_mask, + .irq_unmask = spacemit_pmic_irq_unmask, + .irq_map = spacemit_pmic_irq_map, + .irq_parse = spacemit_pmic_irq_parse, +}; + +static rt_uint32_t spacemit_pmic_irq_valid_mask(struct spacemit_pmic_irqchip *irqchip, + int reg_index) +{ + rt_uint32_t mask = 0; + + for (int i = 0; i < irqchip->irqs_nr; ++i) + { + if (irqchip->irqs_map[i].reg_offset / irqchip->reg_stride == reg_index) + { + mask |= irqchip->irqs_map[i].mask; + } + } + + return mask; +} + +static void spacemit_pmic_thread_isr(void *param) +{ + rt_bool_t parent_rearmed; + rt_uint32_t enabled, *status; + rt_uint16_t base, reg; + struct rt_pic_irq *pirq; + struct spacemit_pmic *pmic; + struct spacemit_pmic_irqchip *irqchip = param; + + pmic = irqchip->pmic; + status = irqchip->irq_status; + + while (RT_TRUE) + { + if (rt_sem_take(&irqchip->irq_sem, RT_WAITING_FOREVER)) + { + continue; + } + + parent_rearmed = RT_FALSE; + ++irqchip->worker_count; + + base = irqchip->status_base; + rt_memset(status, 0, sizeof(*status) * irqchip->num_regs); + + for (int i = 0; i < irqchip->num_regs; ++i) + { + reg = base + i * irqchip->reg_stride; + status[i] = spacemit_pmic_read(pmic, reg); + + if ((rt_err_t)status[i] < 0) + { + LOG_E("Read IRQ status failed error = %s", rt_strerror(status[i])); + + goto _end; + } + + enabled = spacemit_pmic_read(pmic, + irqchip->mask_base + i * irqchip->reg_stride); + + if ((rt_err_t)enabled < 0) + { + LOG_E("Read IRQ mask failed error = %s", rt_strerror(enabled)); + + goto _end; + } + + if (irqchip->mask_unmask_non_inverted) + { + status[i] &= enabled; + } + else + { + status[i] &= ~enabled; + } + } + + base = irqchip->ack_base; + + for (int i = 0; i < irqchip->num_regs; ++i) + { + rt_err_t err; + + reg = base + i * irqchip->reg_stride; + err = spacemit_pmic_write(pmic, reg, status[i]); + + if (err) + { + LOG_E("ACK IRQ failed error = %s", rt_strerror(err)); + + goto _end; + } + } + + /* The PMIC line is clear after ACK; rearm before child handlers can schedule. */ + rt_hw_interrupt_umask(pmic->irq); + ++irqchip->rearm_count; + parent_rearmed = RT_TRUE; + + for (int i = 0; i < irqchip->irqs_nr; ++i) + { + base = irqchip->irqs_map[i].reg_offset / irqchip->reg_stride; + + if (status[base] & irqchip->irqs_map[i].mask) + { + pirq = rt_pic_find_irq(&irqchip->parent, i); + + if (pirq && pirq->pic) + { + rt_pic_handle_isr(pirq); + } + } + } + _end: + if (!parent_rearmed) + { + rt_hw_interrupt_umask(pmic->irq); + ++irqchip->rearm_count; + } + } +} + +static void spacemit_pmic_isr(int irqno, void *param) +{ + struct spacemit_pmic_irqchip *irqchip = param; + + ++irqchip->hard_irq_count; + rt_hw_interrupt_mask(irqchip->pmic->irq); + + rt_sem_release(&irqchip->irq_sem); +} + +#define spacemit_pmic_to_i2c_client(pmic) rt_container_of((pmic)->dev, struct rt_i2c_client, parent) + +static unsigned spacemit_pmic_i2c_read_unlocked(struct spacemit_pmic *pmic, unsigned reg) +{ + rt_uint8_t data = 0; + rt_uint8_t send_buf[2]; + struct rt_i2c_msg msg[2]; + struct rt_i2c_client *client = spacemit_pmic_to_i2c_client(pmic); + + send_buf[0] = (reg & 0xff); + + msg[0].addr = client->client_addr + pmic->addr_offset; + msg[0].flags = RT_I2C_WR; + msg[0].len = 1; + msg[0].buf = send_buf; + + msg[1].addr = client->client_addr + pmic->addr_offset; + msg[1].flags = RT_I2C_RD; + msg[1].len = 1; + msg[1].buf = &data; + + if (rt_i2c_transfer(client->bus, msg, 2) == 2) + { + return data; + } + else + { + return (unsigned)-RT_ERROR; + } +} + +static rt_err_t spacemit_pmic_i2c_write_unlocked(struct spacemit_pmic *pmic, + unsigned reg, unsigned data) +{ + rt_uint8_t send_buf[2]; + struct rt_i2c_msg msg; + struct rt_i2c_client *client = spacemit_pmic_to_i2c_client(pmic); + + send_buf[0] = reg & 0xff; + send_buf[1] = data; + + msg.addr = client->client_addr + pmic->addr_offset; + msg.flags = RT_I2C_WR; + msg.len = 2; + msg.buf = send_buf; + + if (rt_i2c_transfer(client->bus, &msg, 1) == 1) + { + return RT_EOK; + } + else + { + return -RT_ERROR; + } +} + +static unsigned spacemit_pmic_i2c_read(struct spacemit_pmic *pmic, unsigned reg) +{ + unsigned value; + rt_err_t err = rt_mutex_take(pmic->io_lock, RT_WAITING_FOREVER); + + if (err) + { + return (unsigned)err; + } + + value = spacemit_pmic_i2c_read_unlocked(pmic, reg); + rt_mutex_release(pmic->io_lock); + + return value; +} + +static rt_err_t spacemit_pmic_i2c_write(struct spacemit_pmic *pmic, + unsigned reg, unsigned data) +{ + rt_err_t err = rt_mutex_take(pmic->io_lock, RT_WAITING_FOREVER); + + if (err) + { + return err; + } + + err = spacemit_pmic_i2c_write_unlocked(pmic, reg, data); + rt_mutex_release(pmic->io_lock); + + return err; +} + +static rt_err_t spacemit_pmic_i2c_write_bit(struct spacemit_pmic *pmic, + unsigned reg, unsigned mask, unsigned data) +{ + rt_err_t err; + rt_int32_t val; + + if ((err = rt_mutex_take(pmic->io_lock, RT_WAITING_FOREVER))) + { + return err; + } + + val = (rt_int32_t)spacemit_pmic_i2c_read_unlocked(pmic, reg); + + if (val < 0) + { + err = val; + goto _out; + } + + if (data) + { + val |= mask; + } + else + { + val &= ~mask; + } + + err = spacemit_pmic_i2c_write_unlocked(pmic, reg, val); + +_out: + rt_mutex_release(pmic->io_lock); + + return err; +} + +static rt_err_t spacemit_pmic_i2c_update_bits(struct spacemit_pmic *pmic, unsigned reg, + unsigned mask, unsigned data) +{ + rt_err_t err; + rt_int32_t old; + rt_uint32_t tmp; + + if ((err = rt_mutex_take(pmic->io_lock, RT_WAITING_FOREVER))) + { + return err; + } + + old = (rt_int32_t)spacemit_pmic_i2c_read_unlocked(pmic, reg); + + if (old < 0) + { + err = old; + goto _out; + } + + tmp = old & ~mask; + tmp |= (data & mask); + + err = spacemit_pmic_i2c_write_unlocked(pmic, reg, tmp); + +_out: + rt_mutex_release(pmic->io_lock); + + return err; +} + +static rt_err_t create_spacemit_pmic_platform_device(rt_bus_t platform_bus, + struct spacemit_pmic *pmic, const char *name, void *ofw_node) +{ + rt_err_t err; + struct rt_platform_device *pdev = rt_platform_device_alloc(name); + + if (!pdev) + { + return -RT_ENOMEM; + } + + pdev->parent.ofw_node = ofw_node; + pdev->priv = pmic; + + err = rt_bus_add_device(platform_bus, &pdev->parent); + + if (err && err != -RT_ENOSYS) + { + LOG_E("Add %s - %s error = %s", "SPACEMIT-PMIC", name, rt_strerror(err)); + } + + return err; +} + +static rt_err_t spacemit_pmic_ofw_bind_irq(struct spacemit_pmic_irqchip *irqchip, + struct rt_ofw_node *dev_np, struct rt_ofw_node *np, + const struct spacemit_pmic_mfd_endpoint *ep) +{ + /* + * ic: spacemit-pmic-interrupt-controller { + * #interrupt-cells = <1>; + * + * spacemit-pmic-endpoint0 { + * interrupts-extended = <&ic 0>; + * } + * + * spacemit-pmic-endpoint1 { + * interrupts-extended = <&ic 1>, <&ic 2>; + * } + * } + */ + rt_err_t err; + fdt32_t *values; + rt_size_t irq_list_size; + static fdt32_t irq_cell; + static struct rt_ofw_node *ic_np = RT_NULL; + + if (!ic_np) + { + ic_np = rt_ofw_append_child(dev_np, "spacemit-pmic-interrupt-controller"); + + if (!ic_np) + { + return -RT_ENOSYS; + } + + irq_cell = cpu_to_fdt32(1); + err = rt_ofw_append_prop(ic_np, "#interrupt-cells", sizeof(fdt32_t), &irq_cell); + + if (err) + { + return err; + } + + rt_ofw_data(ic_np) = &irqchip->parent; + } + + irq_list_size = sizeof(fdt32_t) * 2 * ep->irqs_nr; + values = rt_malloc(irq_list_size); + + if (!values) + { + return -RT_ENOMEM; + } + + for (int i = 0; i < ep->irqs_nr; ++i) + { + values[i * 2] = cpu_to_fdt32(ic_np->phandle); + values[i * 2 + 1] = cpu_to_fdt32(ep->irqs_list[i]); + } + + if ((err = rt_ofw_append_prop(np, "interrupts-extended", irq_list_size, values))) + { + rt_free(values); + } + + return err; +} + +static rt_err_t spacemit_pmic_i2c_probe(struct rt_i2c_client *client) +{ + rt_err_t err; + rt_bus_t platform_bus; + struct rt_ofw_node *np, *dev_np; + struct rt_device *dev = &client->parent; + struct spacemit_pmic *pmic; + struct spacemit_pmic_mfd_endpoint *pmic_ep; + const struct spacemit_pmic_mfd_data *mfd_data = rt_i2c_client_id_data(client); + + platform_bus = rt_bus_find_by_name("platform"); + + if (!platform_bus) + { + return -RT_EIO; + } + + if (!(pmic = rt_calloc(1, sizeof(*pmic)))) + { + return -RT_ENOMEM; + } + + if (!(pmic->io_lock = rt_mutex_create("pmic-io", RT_IPC_FLAG_PRIO))) + { + rt_free(pmic); + return -RT_ENOMEM; + } + + pmic->dev = dev; + pmic->mfd_data = mfd_data; + pmic->read = spacemit_pmic_i2c_read; + pmic->write = spacemit_pmic_i2c_write; + pmic->write_bit = spacemit_pmic_i2c_write_bit; + pmic->update_bits = spacemit_pmic_i2c_update_bits; + + if (mfd_data->irqchip) + { + struct spacemit_pmic_irqchip *irqchip = mfd_data->irqchip; + + if ((pmic->irq = rt_dm_dev_get_irq(dev, 0)) < 0) + { + err = pmic->irq; + goto _fail; + } + + irqchip->pmic = pmic; + irqchip->parent.priv_data = irqchip; + irqchip->parent.ops = &spacemit_pmic_irq_ops; + + if ((err = rt_pic_linear_irq(&irqchip->parent, irqchip->irqs_nr))) + { + LOG_E("Init %s IRQ chip failed error = %s", "SPACEMIT-PMIC", rt_strerror(err)); + goto _fail; + } + + /* Match regmap-irq: mask and acknowledge all defined interrupts. */ + for (int i = 0; i < irqchip->num_regs; ++i) + { + rt_uint32_t status, valid_mask; + + valid_mask = spacemit_pmic_irq_valid_mask(irqchip, i); + err = spacemit_pmic_update_bits(pmic, + irqchip->mask_base + i * irqchip->reg_stride, + valid_mask, + irqchip->mask_unmask_non_inverted ? 0 : valid_mask); + + if (err) + { + LOG_E("Mask IRQs failed error = %s", rt_strerror(err)); + rt_pic_cancel_irq(&irqchip->parent); + goto _fail; + } + + status = spacemit_pmic_read(pmic, + irqchip->status_base + i * irqchip->reg_stride); + + if ((rt_err_t)status < 0) + { + err = (rt_err_t)status; + LOG_E("Read IRQ status failed error = %s", rt_strerror(err)); + rt_pic_cancel_irq(&irqchip->parent); + goto _fail; + } + + if (irqchip->init_ack_masked && (status & valid_mask)) + { + err = spacemit_pmic_write(pmic, + irqchip->ack_base + i * irqchip->reg_stride, + status & valid_mask); + + if (err) + { + LOG_E("ACK masked IRQs failed error = %s", rt_strerror(err)); + rt_pic_cancel_irq(&irqchip->parent); + goto _fail; + } + } + } + + rt_pic_user_extends(&irqchip->parent); + + if ((err = rt_sem_init(&irqchip->irq_sem, "pmic-irq", 0, RT_IPC_FLAG_FIFO))) + { + rt_pic_cancel_irq(&irqchip->parent); + goto _fail; + } + + irqchip->irq_thread = rt_thread_create("spacemit-pmic", &spacemit_pmic_thread_isr, + irqchip, DM_THREAD_STACK_SIZE, RT_THREAD_PRIORITY_MAX / 2, 10); + + if (!irqchip->irq_thread) + { + rt_sem_detach(&irqchip->irq_sem); + rt_pic_cancel_irq(&irqchip->parent); + err = -RT_ENOMEM; + goto _fail; + } + + rt_thread_startup(irqchip->irq_thread); + + rt_hw_interrupt_install(pmic->irq, spacemit_pmic_isr, irqchip, "spacemit-pmic"); + rt_hw_interrupt_umask(pmic->irq); + } + + dev->user_data = pmic; + + if (mfd_data->shutdown.reg) + { + if (rt_dm_power_off_handler(dev, RT_DM_POWER_OFF_MODE_SHUTDOWN, + RT_DM_POWER_OFF_PRIO_PLATFORM, spacemit_pmic_shutdown)) + { + LOG_W("Add %s failed", "shutdown"); + } + } + + if (mfd_data->reboot.reg) + { + if (rt_dm_reboot_mode_register(dev, spacemit_pmic_reboot)) + { + LOG_W("Add %s failed", "reboot"); + } + } + + dev_np = dev->ofw_node; + pmic_ep = mfd_data->endpoint; + + for (int i = 0; i < mfd_data->endpoint_num; ++i, ++pmic_ep) + { + np = RT_NULL; + + if (!(np = rt_ofw_get_child_by_tag(dev_np, pmic_ep->ofw_name))) + { + if (pmic_ep->ofw_compatible) + { + np = rt_ofw_get_child_by_compatible(dev_np, pmic_ep->ofw_compatible); + } + + if (!np) + { + LOG_D("%s not found", pmic_ep->ofw_name); + + continue; + } + } + + if (!rt_ofw_node_is_available(np)) + { + continue; + } + + if (pmic_ep->irqs_nr) + { + if (!np && !(np = rt_ofw_append_child(dev_np, pmic_ep->ofw_name))) + { + continue; + } + + err = spacemit_pmic_ofw_bind_irq(mfd_data->irqchip, dev_np, np, pmic_ep); + + if (err == -RT_ENOMEM) + { + goto _out_put; + } + } + + err = create_spacemit_pmic_platform_device(platform_bus, pmic, pmic_ep->ofw_name, np); + + _out_put: + rt_ofw_node_put(np); + + if (err == -RT_ENOMEM) + { + LOG_E("No memory to create %s", pmic_ep->ofw_name); + break; + } + } + + return RT_EOK; + +_fail: + rt_mutex_delete(pmic->io_lock); + rt_free(pmic); + + return err; +} + +static const struct rt_ofw_node_id spacemit_pmic_i2c_ofw_ids[] = +{ + { .compatible = "spacemit,spm8821", .data = &spm8821_mfd_data }, + { .compatible = "spacemit,pm853", .data = &pm853_mfd_data }, + { .compatible = "spacemit,sy8810l", .data = &sy8810l_mfd_data }, + { /* sentinel */ }, +}; + +static struct rt_i2c_driver spacemit_pmic_i2c_driver = +{ + .ofw_ids = spacemit_pmic_i2c_ofw_ids, + + .probe = spacemit_pmic_i2c_probe, +}; + +static int spacemit_pmic_i2c_drv_register(void) +{ + rt_i2c_driver_register(&spacemit_pmic_i2c_driver); + + return 0; +} +INIT_SUBSYS_EXPORT(spacemit_pmic_i2c_drv_register); diff --git a/bsp/spacemit/dm/nvmem/Kconfig b/bsp/spacemit/dm/nvmem/Kconfig new file mode 100644 index 000000000000..c8d868e37b1b --- /dev/null +++ b/bsp/spacemit/dm/nvmem/Kconfig @@ -0,0 +1,6 @@ +config RT_NVMEM_SPACEMIT_EFUSE + bool "Spacemit SoCs efuse support" + depends on RT_USING_NVMEM + depends on RT_USING_CLK + depends on RT_USING_RESET + default n diff --git a/bsp/spacemit/dm/nvmem/SConscript b/bsp/spacemit/dm/nvmem/SConscript new file mode 100644 index 000000000000..ca95989a8642 --- /dev/null +++ b/bsp/spacemit/dm/nvmem/SConscript @@ -0,0 +1,13 @@ +from building import * + +group = [] +src = [] +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../include'] + +if GetDepend(['RT_NVMEM_SPACEMIT_EFUSE']): + src += ['spacemit-efuse.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/spacemit/dm/nvmem/spacemit-efuse.c b/bsp/spacemit/dm/nvmem/spacemit-efuse.c new file mode 100644 index 000000000000..2a4d363d4e92 --- /dev/null +++ b/bsp/spacemit/dm/nvmem/spacemit-efuse.c @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#include +#include + +#define DBG_TAG "nvmem.spacemit" +#define DBG_LVL DBG_INFO +#include + +struct spacemit_efuse +{ + struct rt_nvmem_device parent; + + void *base; + struct rt_clk *clk; + struct rt_reset_control *rstc; + + rt_uint8_t *efuse_data; + rt_uint32_t size; +}; + +#define raw_to_spacemit_efuse(raw) rt_container_of(raw, struct spacemit_efuse, parent) + +static rt_err_t spacemit_k1_efuse_read(struct spacemit_efuse *efuse) +{ + rt_err_t err; + + if ((err = rt_clk_prepare_enable(efuse->clk))) + { + LOG_E("Failed to prepare/enable efuse clk"); + return err; + } + + if ((err = rt_reset_control_deassert(efuse->rstc))) + { + LOG_E("Failed to deassert efuse"); + rt_clk_disable_unprepare(efuse->clk); + return err; + } + + /* + * efuse data has been load into register by uboot already, + * just get efuse data from register + */ + for (int i = 0; i < efuse->size; i += 4) + { + *(rt_uint32_t *)(efuse->efuse_data + i) = *(rt_uint32_t *)(efuse->base + i); + } + + /* RESET_AES is shared with the crypto and RNG blocks. */ + rt_clk_disable_unprepare(efuse->clk); + + return err; +} + +static rt_ssize_t spacemit_efuse_read(struct rt_nvmem_device *ndev, int offset, + void *val, rt_size_t bytes) +{ + struct spacemit_efuse *efuse = raw_to_spacemit_efuse(ndev); + + rt_memcpy(val, &efuse->efuse_data[offset], bytes); + + return bytes; +} + +static rt_err_t spacemit_efuse_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + rt_uint64_t address, size; + struct spacemit_efuse *efuse; + struct rt_nvmem_device *nvmem; + struct rt_device *dev = &pdev->parent; + rt_err_t (*efuse_read)(struct spacemit_efuse *efuse); + + if (!(efuse_read = pdev->id->data)) + { + return -RT_EINVAL; + } + + if (!(efuse = rt_calloc(1, sizeof(*efuse)))) + { + return -RT_ENOMEM; + } + + if ((err = rt_dm_dev_get_address(dev, 0, &address, &size))) + { + goto _fail; + } + + efuse->base = rt_ioremap((void *)address, size); + if (!efuse->base) + { + err = -RT_EIO; + goto _fail; + } + + efuse->clk = rt_clk_get_by_index(dev, 0); + if (rt_is_err(efuse->clk)) + { + err = rt_ptr_err(efuse->clk); + goto _fail; + } + + efuse->rstc = rt_reset_control_get_by_index(dev, 0); + if (rt_is_err(efuse->rstc)) + { + err = rt_ptr_err(efuse->rstc); + goto _fail; + } + + efuse->size = rt_roundup(size, sizeof(rt_uint32_t)); + efuse->efuse_data = rt_calloc(1, efuse->size); + if (!efuse->efuse_data) + { + err = -RT_ENOMEM; + goto _fail; + } + + if ((err = efuse_read(efuse))) + { + goto _fail; + } + + nvmem = &efuse->parent; + nvmem->parent.ofw_node = dev->ofw_node; + nvmem->reg_read = spacemit_efuse_read, + nvmem->size = size; + nvmem->read_only = RT_TRUE; + nvmem->stride = 1; + nvmem->word_size = 1; + + if ((err = rt_nvmem_device_register(nvmem))) + { + goto _fail; + } + + return RT_EOK; + +_fail: + if (efuse->base) + { + rt_iounmap(efuse->base); + } + + if (!rt_is_err_or_null(efuse->clk)) + { + rt_clk_put(efuse->clk); + } + + if (!rt_is_err_or_null(efuse->rstc)) + { + rt_reset_control_put(efuse->rstc); + } + + if (efuse->efuse_data) + { + rt_free(efuse->efuse_data); + } + + rt_free(efuse); + + return err; +} + +static const struct rt_ofw_node_id spacemit_efuse_ofw_ids[] = +{ + { .compatible = "spacemit,k1-efuse", .data = &spacemit_k1_efuse_read }, + { /* sentinel */ } +}; + +static struct rt_platform_driver spacemit_efuse_driver = +{ + .name = "nvmem-spacemit-efuse", + .ids = spacemit_efuse_ofw_ids, + + .probe = spacemit_efuse_probe, +}; + +RT_PLATFORM_DRIVER_EXPORT(spacemit_efuse_driver); diff --git a/bsp/spacemit/dm/pci/Kconfig b/bsp/spacemit/dm/pci/Kconfig new file mode 100644 index 000000000000..286a3e0edbe2 --- /dev/null +++ b/bsp/spacemit/dm/pci/Kconfig @@ -0,0 +1,10 @@ +config RT_PCI_DW_SPACEMIT_K1X + bool "Spacemit k1x DesignWare PCIe" + depends on RT_PCI_DW + depends on RT_USING_PIN + depends on RT_USING_PINCTRL + depends on RT_USING_RESET + depends on RT_USING_REGULATOR + select RT_PCI_DW_HOST + select RT_PCI_DW_EP + default n diff --git a/bsp/spacemit/dm/pci/SConscript b/bsp/spacemit/dm/pci/SConscript new file mode 100644 index 000000000000..5c28842a96b4 --- /dev/null +++ b/bsp/spacemit/dm/pci/SConscript @@ -0,0 +1,15 @@ +from building import * + +group = [] + +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../include', cwd + '/../../../../components/drivers/pci', cwd + '/../../../../components/drivers/pci/host/dw'] + +src = [] + +if GetDepend(['RT_PCI_DW_SPACEMIT_K1X']): + src += ['pcie-k1x.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/spacemit/dm/pci/pcie-k1x.c b/bsp/spacemit/dm/pci/pcie-k1x.c new file mode 100644 index 000000000000..bf3e399441c5 --- /dev/null +++ b/bsp/spacemit/dm/pci/pcie-k1x.c @@ -0,0 +1,1366 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#define DBG_TAG "pci.dw.k1x" +#define DBG_LVL DBG_INFO +#include + +#include "pcie-dw.h" + +#define PCIE_VENDORID_MASK 0xffff +#define PCIE_DEVICEID_SHIFT 16 +#define K1X_PCIE_VENDOR_ID 0x201f +#define k1X_PCIE_DEVICE_ID 0x0001 + +/* PCIe controller wrapper k1x configuration registers */ + +#define K1X_PHY_AHB_IRQ_EN 0x0000 +#define IRQ_EN RT_BIT(0) +#define PME_TURN_OFF RT_BIT(5) + +#define K1X_PHY_AHB_IRQSTATUS_INTX 0x0008 +#define INTA RT_BIT(6) +#define INTB RT_BIT(7) +#define INTC RT_BIT(8) +#define INTD RT_BIT(9) +#define LEG_EP_INTERRUPTS (INTA | INTB | INTC | INTD) +#define INTX_MASK RT_GENMASK(9, 6) +#define INTX_SHIFT 6 + +#define K1X_PHY_AHB_IRQENABLE_SET_INTX 0x000c + +#define K1X_PHY_AHB_IRQSTATUS_MSI 0x0010 +#define MSI RT_BIT(11) +#define PCIE_REMOTE_INTERRUPT RT_BIT(31) +/* DMA write channel 0~7 irq*/ +#define EDMA_INT0 RT_BIT(0) +#define EDMA_INT1 RT_BIT(1) +#define EDMA_INT2 RT_BIT(2) +#define EDMA_INT3 RT_BIT(3) +#define EDMA_INT4 RT_BIT(4) +#define EDMA_INT5 RT_BIT(5) +#define EDMA_INT6 RT_BIT(6) +#define EDMA_INT7 RT_BIT(7) +/* DMA read channel 0~7 irq*/ +#define EDMA_INT8 RT_BIT(8) +#define EDMA_INT9 RT_BIT(9) +#define EDMA_INT10 RT_BIT(10) +#define EDMA_INT11 RT_BIT(11) +#define EDMA_INT12 RT_BIT(12) +#define EDMA_INT13 RT_BIT(13) +#define EDMA_INT14 RT_BIT(14) +#define EDMA_INT15 RT_BIT(15) +#define DMA_READ_INT RT_GENMASK(11, 8) + +#define K1X_PHY_AHB_IRQENABLE_SET_MSI 0x0014 + +#define PCIECTRL_K1X_CONF_DEVICE_CMD 0x0000 +#define LTSSM_EN RT_BIT(6) +/* Perst input value in ep mode */ +#define PCIE_PERST_IN RT_BIT(7) +#define PCIE_AUX_PWR_DET RT_BIT(9) +/* Perst GPIO en in RC mode 1: perst# low, 0: perst# high */ +#define PCIE_RC_PERST RT_BIT(12) +/* Wake# GPIO in EP mode 1: Wake# low, 0: Wake# high */ +#define PCIE_EP_WAKE RT_BIT(13) +#define APP_HOLD_PHY_RST RT_BIT(30) +/* BIT31 0: EP, 1: RC*/ +#define DEVICE_TYPE_RC RT_BIT(31) + +#define PCIE_CTRL_LOGIC 0x0004 +#define PCIE_IGNORE_PERSTN RT_BIT(2) + +#define K1X_PHY_AHB_LINK_STS 0x0004 +#define SMLH_LINK_UP RT_BIT(1) +#define RDLH_LINK_UP RT_BIT(12) +#define PCIE_CLIENT_DEBUG_LTSSM_MASK RT_GENMASK(11, 6) +#define PCIE_CLIENT_DEBUG_LTSSM_L1 (RT_BIT(10) | RT_BIT(8)) +#define PCIE_CLIENT_DEBUG_LTSSM_L2 (RT_BIT(10) | RT_BIT(8) | RT_BIT(6)) + +#define ADDR_INTR_STATUS1 0x0018 +#define ADDR_INTR_ENABLE1 0x001c +#define MSI_INT RT_BIT(0) +#define MSIX_INT RT_GENMASK(8, 1) + +#define ADDR_MSI_RECV_CTRL 0x0080 +#define MSI_MON_EN RT_BIT(0) +#define MSIX_MON_EN RT_GENMASK(8, 1) +#define MSIX_AFIFO_FULL RT_BIT(30) +#define MSIX_AFIFO_EMPTY RT_BIT(29) +#define ADDR_MSI_RECV_ADDR0 0x0084 +#define ADDR_MSIX_MON_MASK 0x0088 +#define ADDR_MSIX_MON_BASE0 0x008c + +#define ADDR_MON_FIFO_DATA0 0x00b0 +#define ADDR_MON_FIFO_DATA1 0x00b4 +#define FIFO_EMPTY 0xffffffff +#define FIFO_LEN 32 +#define INT_VEC_MASK RT_GENMASK(7, 0) + +#define EXP_CAP_ID_OFFSET 0x70 + +#define PCIECTRL_K1X_CONF_INTX_ASSERT 0x0124 +#define PCIECTRL_K1X_CONF_INTX_DEASSERT 0x0128 + +/*RC write config 0xD28 offset register which equal with ELBI offset 0x028 addr*/ +#define PCIE_ELBI_EP_DMA_IRQ_STATUS 0x028 +#define PC_TO_EP_INT 0x3fffffff + +#define PCIE_ELBI_EP_DMA_IRQ_MASK 0x02c +#define PC_TO_EP_INT_MASK 0x3fffffff + +#define PCIE_ELBI_EP_MSI_REASON 0x018 + +#define PCIE_LINK_IS_L2(x) (((x) & PCIE_CLIENT_DEBUG_LTSSM_MASK) == PCIE_CLIENT_DEBUG_LTSSM_L2) + +struct k1x_pcie_soc_data +{ + enum dw_pcie_device_mode mode; +}; + +struct k1x_pcie +{ + struct dw_pcie pci; + + int irq; + void *base; + void *elbi_base; + void *dma_base; + void *phy_ahb; + void *phy_addr; + void *conf0_addr; + void *phy0_addr; + + enum dw_pcie_device_mode mode; + + struct rt_clk *clk_master; + struct rt_reset_control *rstc; + + rt_base_t pwr_on_pin; + rt_uint8_t pwr_on_active_val; + + rt_uint32_t pcie_rcal; + rt_uint32_t port_id; + rt_uint32_t num_lanes; + rt_uint32_t link_gen; + + fdt32_t msi_phandle_cell; + + void *msix_data; + rt_ubase_t msix_data_phy; + + struct rt_ofw_node *pic_np; + struct rt_pic pic; +}; + +#define to_k1x_pcie(dw_pcie) rt_container_of(dw_pcie, struct k1x_pcie, pci) + +static rt_bool_t porta_init_done = RT_FALSE; + +rt_inline rt_uint32_t k1x_pcie_readl_dma(struct k1x_pcie *k1x, int offset) +{ + return HWREG32(k1x->dma_base + offset); +} + +rt_inline void k1x_pcie_writel_dma(struct k1x_pcie *k1x, int offset, rt_uint32_t val) +{ + HWREG32(k1x->dma_base + offset) = val; +} + +rt_inline rt_uint32_t k1x_pcie_readw_dma(struct k1x_pcie *k1x, int offset) +{ + return (rt_uint32_t)HWREG16(k1x->dma_base + offset); +} + +rt_inline void k1x_pcie_writew_dma(struct k1x_pcie *k1x, int offset, rt_uint32_t val) +{ + HWREG16(k1x->dma_base + offset) = (rt_uint16_t)val; +} + +rt_inline rt_uint32_t k1x_pcie_readl(struct k1x_pcie *k1x, int offset) +{ + return HWREG32(k1x->base + offset); +} + +rt_inline void k1x_pcie_writel(struct k1x_pcie *k1x, int offset, rt_uint32_t val) +{ + HWREG32(k1x->base + offset) = val; +} + +rt_inline rt_uint32_t k1x_pcie_readl_elbi(struct k1x_pcie *k1x, int offset) +{ + return HWREG32(k1x->elbi_base + offset); +} + +rt_inline void k1x_pcie_writel_elbi(struct k1x_pcie *k1x, int offset, rt_uint32_t val) +{ + HWREG32(k1x->elbi_base + offset) = val; +} + +rt_inline rt_uint32_t k1x_pcie_phy_ahb_readl(struct k1x_pcie *k1x, int offset) +{ + return HWREG32(k1x->phy_ahb + offset); +} + +rt_inline void k1x_pcie_phy_ahb_writel(struct k1x_pcie *k1x, int offset, rt_uint32_t val) +{ + HWREG32(k1x->phy_ahb + offset) = val; +} + +rt_inline rt_uint32_t k1x_pcie_phy_reg_readl(struct k1x_pcie *k1x, int offset) +{ + return HWREG32(k1x->phy_addr + offset); +} + +rt_inline void k1x_pcie_phy_reg_writel(struct k1x_pcie *k1x, int offset, rt_uint32_t val) +{ + HWREG32(k1x->phy_addr + offset) = val; +} + +rt_inline rt_uint32_t k1x_pcie_conf0_reg_readl(struct k1x_pcie *k1x, int offset) +{ + return HWREG32(k1x->conf0_addr + offset); +} + +rt_inline void k1x_pcie_conf0_reg_writel(struct k1x_pcie *k1x, int offset, rt_uint32_t val) +{ + HWREG32(k1x->conf0_addr + offset) = val; +} + +rt_inline rt_uint32_t k1x_pcie_phy0_reg_readl(struct k1x_pcie *k1x, int offset) +{ + return HWREG32(k1x->phy0_addr + offset); +} + +rt_inline void k1x_pcie_phy0_reg_writel(struct k1x_pcie *k1x, int offset, rt_uint32_t val) +{ + HWREG32(k1x->phy0_addr + offset) = val; +} + +static rt_err_t k1x_pcie_ep_init(struct dw_pcie_ep *ep) +{ + rt_uint32_t reg; + struct dw_pcie *pci = to_dw_pcie_from_endpoint(ep); + struct k1x_pcie *k1x = to_k1x_pcie(pci); + + /* Enable wrapper interrupts */ + reg = k1x_pcie_phy_ahb_readl(k1x, K1X_PHY_AHB_IRQENABLE_SET_MSI); + reg |= PCIE_REMOTE_INTERRUPT | DMA_READ_INT; + k1x_pcie_phy_ahb_writel(k1x, K1X_PHY_AHB_IRQENABLE_SET_MSI, reg); + + reg = k1x_pcie_phy_ahb_readl(k1x, K1X_PHY_AHB_IRQ_EN); + reg |= IRQ_EN; + k1x_pcie_phy_ahb_writel(k1x, K1X_PHY_AHB_IRQ_EN, reg); + + reg = k1x_pcie_readl_elbi(k1x, PCIE_ELBI_EP_DMA_IRQ_MASK); + reg |= PC_TO_EP_INT_MASK; + k1x_pcie_writel_elbi(k1x, PCIE_ELBI_EP_DMA_IRQ_MASK, reg); + + return RT_EOK; +} + +static rt_err_t k1x_pcie_raise_irq(struct dw_pcie_ep *ep, rt_uint8_t func_no, + enum rt_pci_ep_irq type, unsigned irq) +{ + switch (type) + { + case RT_PCI_EP_IRQ_LEGACY: + LOG_E("Unsupported INTx"); + return -RT_EINVAL; + + case RT_PCI_EP_IRQ_MSI: + dw_pcie_ep_raise_msi_irq(ep, func_no, irq); + break; + + case RT_PCI_EP_IRQ_MSIX: + dw_pcie_ep_raise_msix_irq(ep, func_no, irq); + break; + + default: + LOG_E("Unknown IRQ type = %d", type); + } + + return RT_EOK; +} + +static struct dw_pcie_ep_ops pcie_ep_ops = +{ + .ep_init = k1x_pcie_ep_init, + .raise_irq = k1x_pcie_raise_irq, +}; + +static rt_err_t k1x_add_pcie_ep(struct k1x_pcie *k1x, struct rt_device *dev) +{ + rt_err_t err; + struct dw_pcie *pci = &k1x->pci; + struct dw_pcie_ep *ep = &pci->endpoint; + + ep->ops = &pcie_ep_ops; + + if (!(k1x->elbi_base = rt_dm_dev_iomap_by_name(dev, "elbi"))) + { + return -RT_EIO; + } + + if (!(k1x->dma_base = rt_dm_dev_iomap_by_name(dev, "dma"))) + { + return -RT_EIO; + } + + if ((err = dw_pcie_ep_init(ep))) + { + LOG_E("Failed to initialize endpoint"); + return err; + } + + return RT_EOK; +} + +static rt_err_t k1x_pcie_host_init(struct dw_pcie_port *port) +{ + rt_err_t err; + rt_uint32_t reg; + struct dw_pcie *pci = to_dw_pcie_from_port(port); + struct k1x_pcie *k1x = to_k1x_pcie(pci); + + rt_thread_mdelay(100); + + /* Set Perst# gpio high state */ + reg = k1x_pcie_readl(k1x, PCIECTRL_K1X_CONF_DEVICE_CMD); + reg &= ~PCIE_RC_PERST; + k1x_pcie_writel(k1x, PCIECTRL_K1X_CONF_DEVICE_CMD, reg); + + /* Enable MSI interrupts */ + reg = k1x_pcie_phy_ahb_readl(k1x, K1X_PHY_AHB_IRQENABLE_SET_MSI); + reg |= MSI; + k1x_pcie_phy_ahb_writel(k1x, K1X_PHY_AHB_IRQENABLE_SET_MSI, reg); + + reg = k1x_pcie_phy_ahb_readl(k1x, K1X_PHY_AHB_IRQENABLE_SET_INTX); + reg |= LEG_EP_INTERRUPTS; + k1x_pcie_phy_ahb_writel(k1x, K1X_PHY_AHB_IRQENABLE_SET_INTX, reg); + + reg = k1x_pcie_phy_ahb_readl(k1x, K1X_PHY_AHB_IRQ_EN); + reg |= IRQ_EN; + k1x_pcie_phy_ahb_writel(k1x, K1X_PHY_AHB_IRQ_EN, reg); + + reg = k1x_pcie_phy_ahb_readl(k1x, ADDR_INTR_ENABLE1); + reg |= (MSI_INT | MSIX_INT); + k1x_pcie_phy_ahb_writel(k1x, ADDR_INTR_ENABLE1, reg); + + /* Configure the root complex before starting link training. */ + dw_pcie_setup_rc(port); + + if (!dw_pcie_link_up(pci) && pci->ops->start_link) + { + if ((err = pci->ops->start_link(pci))) + { + LOG_E("Failed to start PCIe%d link: %s", k1x->port_id, + rt_strerror(err)); + return err; + } + } + + /* Keep the host registered even when an endpoint trains later. */ + if ((err = dw_pcie_wait_for_link(pci))) + { + reg = k1x_pcie_phy_ahb_readl(k1x, K1X_PHY_AHB_LINK_STS); + LOG_W("PCIe%d link down, status=0x%08x", k1x->port_id, reg); + } + else + { + reg = dw_pcie_readw_dbi(pci, EXP_CAP_ID_OFFSET + PCIER_LINK_STA); + LOG_I("PCIe%d Link up, Gen%i", k1x->port_id, + reg & PCIEM_LINK_STA_SPEED); + } + + return RT_EOK; +} + +static rt_err_t k1x_pcie_msi_host_init(struct dw_pcie_port *port) +{ + rt_uint32_t reg; + rt_uint64_t msi_target; + struct dw_pcie *pci = to_dw_pcie_from_port(port); + struct k1x_pcie *k1x = to_k1x_pcie(pci); + + /* MSI Start */ + port->msi_data = rt_dma_alloc_coherent(pci->dev, sizeof(rt_uint64_t), + &port->msi_data_phy); + if (!port->msi_data) + { + goto _msix_init; + } + msi_target = (rt_uint64_t)port->msi_data_phy; + + /* Program the msi_data */ + dw_pcie_writel_dbi(pci, PCIE_MSI_ADDR_LO, rt_lower_32_bits(msi_target)); + dw_pcie_writel_dbi(pci, PCIE_MSI_ADDR_HI, rt_upper_32_bits(msi_target)); + + reg = k1x_pcie_phy_ahb_readl(k1x, ADDR_MSI_RECV_CTRL); + reg |= MSI_MON_EN; + k1x_pcie_phy_ahb_writel(k1x, ADDR_MSI_RECV_CTRL, reg); + k1x_pcie_phy_ahb_writel(k1x, ADDR_MSI_RECV_ADDR0, (rt_lower_32_bits(msi_target) >> 2)); + /* MSI End */ + +_msix_init: + /* MSI-X Start */ + k1x->msix_data = rt_dma_alloc_coherent(pci->dev, sizeof(rt_uint64_t), + &k1x->msix_data_phy); + if (!k1x->msix_data) + { + goto _end; + } + msi_target = (rt_uint64_t)k1x->msix_data_phy; + + reg = k1x_pcie_phy_ahb_readl(k1x, ADDR_MSI_RECV_CTRL); + reg |= MSIX_MON_EN; + k1x_pcie_phy_ahb_writel(k1x, ADDR_MSI_RECV_CTRL, reg); + k1x_pcie_phy_ahb_writel(k1x, ADDR_MSIX_MON_BASE0, (rt_lower_32_bits(msi_target) >> 2)); + /* MSI-X End */ + +_end: + return RT_EOK; +} + +static const struct dw_pcie_host_ops k1x_pcie_host_ops = +{ + .host_init = k1x_pcie_host_init, + .msi_host_init = k1x_pcie_msi_host_init, +}; + +static rt_bool_t k1x_pcie_link_up(struct dw_pcie *pci) +{ + struct k1x_pcie *k1x = to_k1x_pcie(pci); + rt_uint32_t reg = k1x_pcie_phy_ahb_readl(k1x, K1X_PHY_AHB_LINK_STS); + + return (reg & RDLH_LINK_UP) && (reg & SMLH_LINK_UP); +} + +static rt_err_t k1x_pcie_establish_link(struct dw_pcie *pci) +{ + rt_uint32_t reg; + struct k1x_pcie *k1x = to_k1x_pcie(pci); + + if (k1x->mode == DW_PCIE_EP_TYPE) + { + rt_uint32_t cnt = 0; + do { + reg = k1x_pcie_readl(k1x, PCIECTRL_K1X_CONF_DEVICE_CMD); + + if ((reg & RT_BIT(7)) == RT_BIT(7)) + { + break; + } + + rt_hw_us_delay(10); + cnt += 1; + } while (cnt < 300000); + } + + if (dw_pcie_link_up(pci)) + { + LOG_E("Link is already up"); + return RT_EOK; + } + + reg = k1x_pcie_readl(k1x, PCIECTRL_K1X_CONF_DEVICE_CMD); + reg |= LTSSM_EN; + reg &= ~APP_HOLD_PHY_RST; + k1x_pcie_writel(k1x, PCIECTRL_K1X_CONF_DEVICE_CMD, reg); + + LOG_D("LTSSM Enable"); + + return RT_EOK; +} + +static void k1x_pcie_stop_link(struct dw_pcie *pci) +{ + rt_uint32_t reg; + struct k1x_pcie *k1x = to_k1x_pcie(pci); + + reg = k1x_pcie_readl(k1x, PCIECTRL_K1X_CONF_DEVICE_CMD); + reg &= ~LTSSM_EN; + k1x_pcie_writel(k1x, PCIECTRL_K1X_CONF_DEVICE_CMD, reg); +} + +static const struct dw_pcie_ops dw_pcie_ops = +{ + .link_up = k1x_pcie_link_up, + .start_link = k1x_pcie_establish_link, + .stop_link = k1x_pcie_stop_link, +}; + +static void k1x_pci_irq_mask(struct rt_pic_irq *pirq) +{ + if (pirq->msi_desc) + { + rt_pci_msi_mask_irq(pirq); + } +} + +static void k1x_pci_irq_unmask(struct rt_pic_irq *pirq) +{ + if (pirq->msi_desc) + { + rt_pci_msi_unmask_irq(pirq); + } +} + +static void k1x_pcie_irq_compose_msi_msg(struct rt_pic_irq *pirq, struct rt_pci_msi_msg *msg) +{ + rt_uint64_t msi_target; + struct k1x_pcie *k1x = pirq->pic->priv_data; + struct dw_pcie_port *port = &k1x->pci.port; + + msi_target = (rt_uint64_t)port->msi_data_phy; + + msg->address_lo = rt_lower_32_bits(msi_target); + msg->address_hi = rt_upper_32_bits(msi_target); + msg->data = pirq->hwirq; +} + +static int k1x_pcie_irq_alloc_msi(struct rt_pic *pic, struct rt_pci_msi_desc *msi_desc) +{ + rt_ubase_t level; + int irq, virq, hwirq; + struct rt_pic_irq *pirq; + struct k1x_pcie *k1x = pic->priv_data; + struct dw_pcie_port *port = &k1x->pci.port; + + level = rt_spin_lock_irqsave(&port->lock); + hwirq = rt_bitmap_next_clear_bit(port->msi_map, 0, MAX_MSI_IRQS); + virq = hwirq + RT_PCI_INTX_PIN_MAX; + + if (hwirq >= MAX_MSI_IRQS || virq >= pic->irq_nr) + { + irq = -RT_EEMPTY; + goto _out_lock; + } + + pirq = rt_pic_find_irq(pic, virq); + + irq = rt_pic_config_irq(pic, virq, hwirq); + pirq->mode = RT_IRQ_MODE_EDGE_RISING; + + rt_bitmap_set_bit(port->msi_map, hwirq); + +_out_lock: + rt_spin_unlock_irqrestore(&port->lock, level); + + return irq; +} + +static void k1x_pcie_irq_free_msi(struct rt_pic *pic, int irq) +{ + rt_ubase_t level; + struct rt_pic_irq *pirq; + struct k1x_pcie *k1x = pic->priv_data; + struct dw_pcie_port *port = &k1x->pci.port; + + pirq = rt_pic_find_pirq(pic, irq); + + if (!pirq) + { + return; + } + + level = rt_spin_lock_irqsave(&port->lock); + rt_bitmap_clear_bit(port->msi_map, pirq->hwirq); + rt_spin_unlock_irqrestore(&port->lock, level); +} + +static int k1x_pcie_irq_map(struct rt_pic *pic, int hwirq, rt_uint32_t mode) +{ + int irq; + struct rt_pic_irq *pirq = rt_pic_find_irq(pic, hwirq); + + if (pirq) + { + if (pirq->irq >= 0) + { + irq = pirq->irq; + } + else + { + irq = rt_pic_config_irq(pic, hwirq, hwirq); + rt_pic_irq_set_triger_mode(irq, RT_IRQ_MODE_LEVEL_HIGH); + } + } + else + { + irq = -1; + } + + return irq; +} + +static rt_err_t k1x_pcie_irq_parse(struct rt_pic *pic, + struct rt_ofw_cell_args *args, struct rt_pic_irq *out_pirq) +{ + rt_err_t err = RT_EOK; + + if (args->args_count == 1) + { + out_pirq->hwirq = args->args[0]; + out_pirq->mode = RT_IRQ_MODE_LEVEL_HIGH; + } + else + { + err = -RT_EINVAL; + } + + return err; +} + +const static struct rt_pic_ops k1x_pcie_pic_ops = +{ + .name = "K1X-PCIe", + .irq_mask = k1x_pci_irq_mask, + .irq_unmask = k1x_pci_irq_unmask, + .irq_compose_msi_msg = k1x_pcie_irq_compose_msi_msg, + .irq_alloc_msi = k1x_pcie_irq_alloc_msi, + .irq_free_msi = k1x_pcie_irq_free_msi, + .irq_map = k1x_pcie_irq_map, + .irq_parse = k1x_pcie_irq_parse, +}; + +static void k1x_pcie_pic_isr(int irqno, void *param) +{ + rt_uint32_t reg, hwirq; + struct rt_pic_irq *pirq; + struct k1x_pcie *k1x = param; + + reg = k1x_pcie_phy_ahb_readl(k1x, ADDR_INTR_STATUS1); + k1x_pcie_phy_ahb_writel(k1x, ADDR_INTR_STATUS1, reg); + + /* MSI int handler */ + if ((reg & MSI_INT) | (reg & MSIX_INT)) + { + rt_uint32_t val; + + if (k1x_pcie_phy_ahb_readl(k1x, ADDR_MSI_RECV_CTRL) & MSIX_AFIFO_FULL) + { + LOG_W("AXI monitor FIFO FULL"); + } + + for (int i = 0; i < FIFO_LEN; ++i) + { + if (k1x_pcie_phy_ahb_readl(k1x, ADDR_MON_FIFO_DATA0) == FIFO_EMPTY) + { + break; + } + val = k1x_pcie_phy_ahb_readl(k1x, ADDR_MON_FIFO_DATA1); + /* In fact, val is the hwirq which equals with msi_data + msi vector */ + val &= INT_VEC_MASK; + + if ((pirq = rt_pic_find_irq(&k1x->pic, val + RT_PCI_INTX_PIN_MAX))) + { + rt_pic_handle_isr(pirq); + } + } + } + + /* Legacy INTx */ + reg = k1x_pcie_phy_ahb_readl(k1x, K1X_PHY_AHB_IRQSTATUS_INTX); + k1x_pcie_phy_ahb_writel(k1x, K1X_PHY_AHB_IRQSTATUS_INTX, reg); + reg = (reg & INTX_MASK) >> INTX_SHIFT; + + if (reg) + { + LOG_D("Legacy INTx interrupt received"); + } + + while (reg) + { + hwirq = __rt_ffs(reg) - 1; + reg &= ~RT_BIT(hwirq); + + pirq = rt_pic_find_irq(&k1x->pic, hwirq); + + if (pirq) + { + rt_pic_handle_isr(pirq); + } + else + { + LOG_E("Unexpected IRQ INTx #%c", 'A' + hwirq); + } + } +} + +static rt_err_t k1x_add_pcie_port(struct k1x_pcie *k1x, struct rt_device *dev) +{ + rt_err_t err; + rt_uint32_t reg; + struct dw_pcie *pci = &k1x->pci; + struct dw_pcie_port *port = &pci->port; + struct rt_ofw_node *np = dev->ofw_node, *msi_np; + + /* Set Perst# (fundamental rstc) gpio low state */ + reg = k1x_pcie_readl(k1x, PCIECTRL_K1X_CONF_DEVICE_CMD); + reg |= PCIE_RC_PERST; + k1x_pcie_writel(k1x, PCIECTRL_K1X_CONF_DEVICE_CMD, reg); + + port->sys_irq = rt_dm_dev_get_irq(dev, 0); + if (port->sys_irq < 0) + { + LOG_E("Missing IRQ resource"); + return port->sys_irq; + } + + if (!(pci->dbi_base = rt_dm_dev_iomap_by_name(dev, "dbi"))) + { + return -RT_EIO; + } + + if (!(pci->atu_base = rt_dm_dev_iomap_by_name(dev, "atu"))) + { + return -RT_EIO; + } + + if (!(msi_np = rt_ofw_append_child(np, "msi-controller"))) + { + return -RT_ENOMEM; + } + + k1x->msi_phandle_cell = cpu_to_fdt32(msi_np->phandle); + + if ((err = rt_ofw_append_prop(np, "msi-parent", sizeof(fdt32_t), &k1x->msi_phandle_cell))) + { + return err; + } + + if (!(k1x->pic_np = rt_ofw_get_child_by_tag(np, "interrupt-controller"))) + { + LOG_E("INTx ofw node not found"); + return -RT_EIO; + } + + port->ops = &k1x_pcie_host_ops; + port->irq_count = RT_PCI_INTX_PIN_MAX + MAX_MSI_IRQS; + + k1x->pic.priv_data = k1x; + k1x->pic.ops = &k1x_pcie_pic_ops; + rt_pic_linear_irq(&k1x->pic, port->irq_count); + rt_pic_user_extends(&k1x->pic); + rt_ofw_data(k1x->pic_np) = &k1x->pic; + rt_ofw_node_put(k1x->pic_np); + + /* For MSI */ + rt_ofw_data(msi_np) = &k1x->pic; + + rt_hw_interrupt_install(port->sys_irq, k1x_pcie_pic_isr, k1x, "k1x-pcie"); + rt_hw_interrupt_umask(port->sys_irq); + + /* Init ID */ + dw_pcie_dbi_ro_writable_enable(pci, RT_TRUE); + dw_pcie_writew_dbi(pci, PCIR_VENDOR, K1X_PCIE_VENDOR_ID); + dw_pcie_writew_dbi(pci, PCIR_DEVICE, k1X_PCIE_DEVICE_ID); + dw_pcie_dbi_ro_writable_enable(pci, RT_FALSE); + + if ((err = dw_pcie_host_init(port))) + { + LOG_E("Failed to initialize host"); + return err; + } + + return RT_EOK; +} + +/* Local cpu interrupt, vendor specific */ +static void k1x_pcie_isr(int irqno, void *param) +{ + rt_uint32_t reg, reg_ahb; + struct k1x_pcie *k1x = param; + + reg = k1x_pcie_readl_elbi(k1x, PCIE_ELBI_EP_DMA_IRQ_STATUS); + /* Write 0 to clear the irq*/ + k1x_pcie_writel_elbi(k1x, PCIE_ELBI_EP_DMA_IRQ_STATUS, 0); + reg_ahb = k1x_pcie_phy_ahb_readl(k1x, K1X_PHY_AHB_IRQSTATUS_MSI); + +_repeat: + if (reg & PC_TO_EP_INT) + { + LOG_I("EP ISR"); + } + if (reg_ahb & DMA_READ_INT) + { + LOG_I("DMA ISR"); + } + + reg = k1x_pcie_readl_elbi(k1x, PCIE_ELBI_EP_DMA_IRQ_STATUS); + if (reg & PC_TO_EP_INT) + { + k1x_pcie_writel_elbi(k1x, PCIE_ELBI_EP_DMA_IRQ_STATUS, 0); + goto _repeat; + } +} + +/* Wait porta rterm done */ +static void porta_rterm(struct k1x_pcie *k1x) +{ + rt_uint32_t val; + int rd_data, count = 0; + + k1x_pcie_conf0_reg_writel(k1x, 0, 0x4000003f); + + val = k1x_pcie_conf0_reg_readl(k1x, 0); + val &= 0xbfffffff; + k1x_pcie_conf0_reg_writel(k1x, 0, val); + + /* Set refclk model */ + val = k1x_pcie_phy0_reg_readl(k1x, 0x17 << 2); + val |= 0x1 << 10; + k1x_pcie_phy0_reg_writel(k1x, 0x17 << 2, val); + + val = k1x_pcie_phy0_reg_readl(k1x, 0x17 << 2); + val &= ~(0x3 << 8); + k1x_pcie_phy0_reg_writel(k1x, 0x17 << 2, val); + + /* Driver mode */ + val = k1x_pcie_phy0_reg_readl(k1x, 0x17 << 2); + val |= 0x1 << 8; + k1x_pcie_phy0_reg_writel(k1x, 0x17 << 2, val); + + val = k1x_pcie_phy0_reg_readl(k1x, 0x12 << 2); + val &= 0xffff0fff; + k1x_pcie_phy0_reg_writel(k1x, 0x12 << 2, val); + + val = k1x_pcie_phy0_reg_readl(k1x, 0x12 << 2); + val |= 0x00002000; + k1x_pcie_phy0_reg_writel(k1x, 0x12 << 2, val); + + val = k1x_pcie_phy0_reg_readl(k1x, 0x13 << 2); + val |= 0x1 << 4; + k1x_pcie_phy0_reg_writel(k1x, 0x13 << 2, val); + + val = k1x_pcie_phy0_reg_readl(k1x, 0x12 << 2); + val &= 0xfff0ffff; + k1x_pcie_phy0_reg_writel(k1x, 0x12 << 2, val); + + k1x_pcie_phy0_reg_writel(k1x, 0x02 << 2, 0x00000b78); + + k1x_pcie_phy0_reg_writel(k1x, 0x06 << 2, 0x00000400); + + /* Wait pm0 rterm done */ + do { + rd_data = k1x_pcie_phy0_reg_readl(k1x, 0x21 * 4); + + if (count++ > 5000) + { + LOG_E("Read PCIe%d phy rd_data time out", 0); + break; + } + } while (((rd_data >> 10) & 0x1) == 0); /* Waiting PCIe portA readonly_reg2[2] r_tune_done==1 */ +} + +/* Force rterm value to porta/b/c */ +static void rterm_force(struct k1x_pcie *k1x, rt_uint32_t pcie_rcal) +{ + rt_uint32_t val = 0; + int lane = k1x->num_lanes; + + /* 2. Write pma0 rterm value LSB[3:0](read0nly1[3:0]) to lane0/1 rx_reg1 */ + for (int i = 0; i < lane; ++i) + { + val = k1x_pcie_phy_reg_readl(k1x, ((0x14 << 2) + 0x400 * i)); + val &= ~(0xf << 8); + val |= (pcie_rcal & 0xf) << 8; + k1x_pcie_phy_reg_writel(k1x, ((0x14 << 2) + 0x400 * i), val); + } + /* 3. Set lane0/1 rx_reg4 bit5=0 */ + for (int i = 0; i < lane; ++i) + { + val = k1x_pcie_phy_reg_readl(k1x, ((0x15 << 2) + 0x400 * i)); + val &= ~(1 << 5); + k1x_pcie_phy_reg_writel(k1x, ((0x15 << 2) + 0x400 * i), val); + } + + /* 4. Write pma0 rterm value MSB[7:4](readonly1[7:4]) to lane0/1 tx_reg1[7:4] */ + for (int i = 0; i < lane; ++i) + { + val = k1x_pcie_phy_reg_readl(k1x, ((0x19 << 2) + 0x400 * i)); + val &= ~(0xf << 12); + val |= ((pcie_rcal >> 4) & 0xf) << 12; + k1x_pcie_phy_reg_writel(k1x, ((0x19 << 2) + 0x400 * i), val); + } + + /* 5. Set lane0/1 tx_reg3 bit1=1 */ + for (int i = 0; i < lane; ++i) + { + val = k1x_pcie_phy_reg_readl(k1x, ((0x19 << 2) + 0x400 * i)); + val |= 1 << 25; + k1x_pcie_phy_reg_writel(k1x, ((0x19 << 2) + 0x400 * i), val); + } + + /* 6. Adjust rc calrefclk freq */ + val = k1x_pcie_phy_reg_readl(k1x, 0x8 << 2); + val &= ~(0x7 << 29); + val |= 0x3 << 29; + k1x_pcie_phy_reg_writel(k1x, 0x8 << 2, val); + + /* 7. Set lane0/1 rc_cal_reg1[6]=1 */ + for (int i = 0; i < lane; ++i) + { + val = k1x_pcie_phy_reg_readl(k1x, ((0x8 << 2) + 0x400 * i)); + val &= ~(1 << 22); + k1x_pcie_phy_reg_writel(k1x, ((0x8 << 2) + 0x400 * i), val); + } + for (int i = 0; i < lane; ++i) + { + val = k1x_pcie_phy_reg_readl(k1x, ((0x8 << 2) + 0x400 * i)); + val |= 1 << 22; + k1x_pcie_phy_reg_writel(k1x, ((0x8 << 2) + 0x400 * i), val); + } +} + +static rt_err_t init_phy(struct k1x_pcie *k1x) +{ + int count = 0; + rt_uint32_t reg, rd_data, pcie_rcal, val = 0; + + if (k1x->port_id != 0) + { + if (!porta_init_done) + { + porta_rterm(k1x); + pcie_rcal = k1x_pcie_phy0_reg_readl(k1x, 0x21 << 2); + + val = k1x_pcie_conf0_reg_readl(k1x, 0); + val &= ~0x4000003f; + k1x_pcie_conf0_reg_writel(k1x, 0, val); + } + else + { + pcie_rcal = k1x_pcie_phy0_reg_readl(k1x, 0x21 << 2); + } + } + else + { + count = 0; + do { + rd_data = k1x_pcie_phy0_reg_readl(k1x, 0x21 * 4); + + if (count++ > 5000) + { + LOG_E("Read PCIe%d phy rd_data time out", 0); + break; + } + } while (((rd_data >> 10) & 0x1) == 0); + pcie_rcal = k1x_pcie_phy0_reg_readl(k1x, 0x21 << 2); + } + + k1x->pcie_rcal = pcie_rcal; + + /* Disable ltssm and phy */ + reg = k1x_pcie_readl(k1x, PCIECTRL_K1X_CONF_DEVICE_CMD); + reg &= ~0x7f; + k1x_pcie_writel(k1x, PCIECTRL_K1X_CONF_DEVICE_CMD, reg); + + /* Soft rstc */ + reg = k1x_pcie_readl(k1x, PCIE_CTRL_LOGIC); + reg |= 1 << 0; + k1x_pcie_writel(k1x, PCIE_CTRL_LOGIC, reg); + + rt_thread_mdelay(2); + + /* Soft no rstc */ + reg = k1x_pcie_readl(k1x, PCIE_CTRL_LOGIC); + reg &= ~(1 << 0); + k1x_pcie_writel(k1x, PCIE_CTRL_LOGIC, reg); + + reg = k1x_pcie_readl(k1x, PCIECTRL_K1X_CONF_DEVICE_CMD); + reg |= 0x3f; + k1x_pcie_writel(k1x, PCIECTRL_K1X_CONF_DEVICE_CMD, reg); + + rterm_force(k1x, pcie_rcal); + + val = k1x_pcie_readl(k1x, PCIECTRL_K1X_CONF_DEVICE_CMD); + val &= 0xbfffffff; + k1x_pcie_writel(k1x, PCIECTRL_K1X_CONF_DEVICE_CMD, val); + + /* Set refclk model */ + val = k1x_pcie_phy_reg_readl(k1x, 0x17 << 2); + val |= 0x1 << 10; + k1x_pcie_phy_reg_writel(k1x, 0x17 << 2, val); + + val = k1x_pcie_phy_reg_readl(k1x, 0x17 << 2); + val &= ~(0x3 << 8); + k1x_pcie_phy_reg_writel(k1x, 0x17 << 2, val); + + val = k1x_pcie_phy_reg_readl(k1x, 0x400 + (0x17 << 2)); + val |= 0x1 << 10; + k1x_pcie_phy_reg_writel(k1x, 0x400 + (0x17 << 2), val); + + val = k1x_pcie_phy_reg_readl(k1x, 0x400 + (0x17 << 2)); + val &= ~(0x3 << 8); + k1x_pcie_phy_reg_writel(k1x, 0x400 + (0x17 << 2), val); + + /* Driver mode */ + val = k1x_pcie_phy_reg_readl(k1x, 0x17 << 2); + val |= 0x1 << 8; + k1x_pcie_phy_reg_writel(k1x, 0x17 << 2, val); + + val = k1x_pcie_phy_reg_readl(k1x, 0x400 + (0x17 << 2)); + val |= 0x1 << 8; + k1x_pcie_phy_reg_writel(k1x, 0x400 + (0x17 << 2), val); + + val = k1x_pcie_phy_reg_readl(k1x, 0x12 << 2); + val &= 0xffff0fff; + k1x_pcie_phy_reg_writel(k1x, 0x12 << 2, val); + + val = k1x_pcie_phy_reg_readl(k1x, 0x12 << 2); + val |= 0x00002000; + k1x_pcie_phy_reg_writel(k1x, 0x12 << 2, val); + + val = k1x_pcie_phy_reg_readl(k1x, 0x13 << 2); + val |= 0x1 << 4; + k1x_pcie_phy_reg_writel(k1x, 0x13 << 2, val); + + if (k1x->port_id == 0) + { + val = k1x_pcie_phy0_reg_readl(k1x, 0x14 << 2); + val |= 0x1 << 3; + k1x_pcie_phy0_reg_writel(k1x, 0x14 << 2, val); + } + + /* pll_reg1 of lane0, disable ssc pll_reg4[3:0]=4'h0 */ + val = k1x_pcie_phy_reg_readl(k1x, 0x12 << 2); + val &= 0xfff0ffff; + k1x_pcie_phy_reg_writel(k1x, 0x12 << 2, val); + + /* PU_ADDR_CLK_CFG of lane0 */ + k1x_pcie_phy_reg_writel(k1x, 0x02 << 2, 0x00000b78); + + /* PU_ADDR_CLK_CFG of lane1 */ + k1x_pcie_phy_reg_writel(k1x, 0x400 + (0x02 << 2), 0x00000b78); + + /* Force rcv done */ + k1x_pcie_phy_reg_writel(k1x, 0x06 << 2, 0x00000400); + + /* Waiting pll lock */ + do { + rd_data = k1x_pcie_phy_reg_readl(k1x, 0x8); + + if (count++ > 5000) + { + LOG_E("Read PCIe%d phy rd_data time out", k1x->port_id); + break; + } + } while ((rd_data & 0x1) == 0); + + if (k1x->port_id == 0) + { + porta_init_done = RT_TRUE; + } + + return RT_EOK; +} + +static void k1x_pcie_hold_phy_rst(struct k1x_pcie *k1x) +{ + rt_uint32_t reg; + + reg = k1x_pcie_readl(k1x, PCIECTRL_K1X_CONF_DEVICE_CMD); + + if (reg & APP_HOLD_PHY_RST) + { + LOG_D("Phy reset already held"); + return; + } + + reg |= APP_HOLD_PHY_RST; + k1x_pcie_writel(k1x, PCIECTRL_K1X_CONF_DEVICE_CMD, reg); +} + +#ifdef RT_USING_PM +static rt_err_t k1x_pcie_dw_pcie_pm_suspend(const struct rt_device *device, rt_uint8_t mode) +{ + rt_uint32_t val; + struct k1x_pcie *k1x = device->user_data; + struct dw_pcie *pci = &k1x->pci; + + if (k1x->mode != DW_PCIE_RC_TYPE) + { + return RT_EOK; + } + + /* Clear MSE */ + val = dw_pcie_readl_dbi(pci, PCIR_COMMAND); + val &= ~PCIM_CMD_MEMEN; + dw_pcie_writel_dbi(pci, PCIR_COMMAND, val); + + return RT_EOK; +} + +static void k1x_pcie_dw_pcie_pm_resume(const struct rt_device *device, rt_uint8_t mode) +{ + rt_uint32_t val; + struct k1x_pcie *k1x = device->user_data; + struct dw_pcie *pci = &k1x->pci; + + if (k1x->mode != DW_PCIE_RC_TYPE) + { + return; + } + + /* Set MSE */ + val = dw_pcie_readl_dbi(pci, PCIR_COMMAND); + val |= PCIM_CMD_MEMEN; + dw_pcie_writel_dbi(pci, PCIR_COMMAND, val); +} + +static const struct rt_device_pm_ops k1x_pcie_dw_pcie_pm_ops = +{ + .suspend = k1x_pcie_dw_pcie_pm_suspend, + .resume = k1x_pcie_dw_pcie_pm_resume, +}; +#endif /* RT_USING_PM */ + +static rt_err_t k1x_pcie_dw_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + rt_uint32_t reg; + struct dw_pcie *pci; + struct rt_device *dev = &pdev->parent; + struct k1x_pcie *k1x = rt_calloc(1, sizeof(*k1x)); + const struct k1x_pcie_soc_data *data = pdev->id->data; + + if (!k1x) + { + return -RT_ENOMEM; + } + k1x->mode = data->mode; + + pci = &k1x->pci; + pci->dev = dev; + pci->ops = &dw_pcie_ops; + pci->priv = k1x; + + if (!(k1x->base = rt_dm_dev_iomap_by_name(dev, "k1x_conf"))) + { + err = -RT_EIO; + goto _fail; + } + + if (!(k1x->phy_ahb = rt_dm_dev_iomap_by_name(dev, "phy_ahb"))) + { + err = -RT_EIO; + goto _fail; + } + + if (!(k1x->phy_addr = rt_dm_dev_iomap_by_name(dev, "phy_addr"))) + { + err = -RT_EIO; + goto _fail; + } + + if (!(k1x->conf0_addr = rt_dm_dev_iomap_by_name(dev, "conf0_addr"))) + { + err = -RT_EIO; + goto _fail; + } + + if (!(k1x->phy0_addr = rt_dm_dev_iomap_by_name(dev, "phy0_addr"))) + { + err = -RT_EIO; + goto _fail; + } + + if ((k1x->irq = rt_dm_dev_get_irq(dev, 1)) < 0) + { + err = k1x->irq; + goto _fail; + } + + if ((err = rt_dm_dev_prop_read_u32(dev, "k1x,pcie-port", &k1x->port_id))) + { + LOG_E("Failed to get pcie's port id"); + goto _fail; + } + + if (rt_dm_dev_prop_read_u32(dev, "num-lanes", &k1x->num_lanes)) + { + LOG_W("Failed to get pcie's port num-lanes"); + k1x->num_lanes = 1; + } + + if (k1x->num_lanes < 1 || k1x->num_lanes > 2) + { + LOG_W("Configuration of num-lanes is invalid"); + k1x->num_lanes = 1; + } + + k1x->pwr_on_pin = rt_pin_get_named_pin(dev, "k1x,pwr_on", 0, + RT_NULL, &k1x->pwr_on_active_val); + + k1x->clk_master = rt_clk_get_by_index(dev, 0); + if (rt_is_err(k1x->clk_master)) + { + err = rt_ptr_err(k1x->clk_master); + goto _fail; + } + + if ((err = rt_clk_prepare_enable(k1x->clk_master))) + { + goto _fail; + } + + /* PCIE0 and usb use combo phy and rstc */ + k1x->rstc = rt_reset_control_get_by_index(dev, 0); + if (rt_is_err(k1x->rstc)) + { + err = rt_ptr_err(k1x->rstc); + goto _fail; + } + + k1x_pcie_hold_phy_rst(k1x); + + rt_reset_control_deassert(k1x->rstc); + + if ((err = init_phy(k1x))) + { + goto _fail; + } + + if ((err = rt_dm_dev_prop_read_u32(dev, "max-link-speed", &k1x->link_gen))) + { + goto _fail; + } + if (k1x->link_gen < 0 || k1x->link_gen > 3) + { + k1x->link_gen = 3; + } + + rt_hw_interrupt_install(k1x->irq, k1x_pcie_isr, k1x, "k1x-pcie-vs"); + rt_hw_interrupt_umask(k1x->irq); + + switch (k1x->mode) + { + case DW_PCIE_RC_TYPE: + reg = k1x_pcie_readl(k1x, PCIECTRL_K1X_CONF_DEVICE_CMD); + reg |= DEVICE_TYPE_RC | PCIE_AUX_PWR_DET; + k1x_pcie_writel(k1x, PCIECTRL_K1X_CONF_DEVICE_CMD, reg); + + reg = k1x_pcie_readl(k1x, PCIE_CTRL_LOGIC); + reg |= PCIE_IGNORE_PERSTN; + k1x_pcie_writel(k1x, PCIE_CTRL_LOGIC, reg); + + /* Power on the interface */ + if (k1x->pwr_on_pin >= 0) + { + rt_pin_write(k1x->pwr_on_pin, k1x->pwr_on_active_val); + rt_pin_mode(k1x->pwr_on_pin, PIN_MODE_OUTPUT); + } + + err = k1x_add_pcie_port(k1x, dev); + break; + + case DW_PCIE_EP_TYPE: + reg = k1x_pcie_readl(k1x, PCIECTRL_K1X_CONF_DEVICE_CMD); + reg &= ~DEVICE_TYPE_RC; + k1x_pcie_writel(k1x, PCIECTRL_K1X_CONF_DEVICE_CMD, reg); + + err = k1x_add_pcie_ep(k1x, dev); + break; + + default: + /* It's impossible */ + RT_ASSERT(0); + break; + } + + if (err) + { + goto _free_irq; + } + +#ifdef RT_USING_PM + rt_pm_device_register(dev, &k1x_pcie_dw_pcie_pm_ops); +#endif + + dev->user_data = k1x; + + return RT_EOK; + +_free_irq: + rt_hw_interrupt_mask(k1x->irq); + rt_pic_detach_irq(k1x->irq, k1x); + + rt_clk_disable_unprepare(k1x->clk_master); + +_fail: + if (k1x->base) + { + rt_iounmap(k1x->base); + } + if (k1x->phy_ahb) + { + rt_iounmap(k1x->phy_ahb); + } + if (k1x->phy_addr) + { + rt_iounmap(k1x->phy_addr); + } + if (k1x->conf0_addr) + { + rt_iounmap(k1x->conf0_addr); + } + if (k1x->phy0_addr) + { + rt_iounmap(k1x->phy0_addr); + } + if (!rt_is_err_or_null(k1x->clk_master)) + { + rt_clk_put(k1x->clk_master); + } + if (!rt_is_err_or_null(k1x->rstc)) + { + rt_reset_control_put(k1x->rstc); + } + if (k1x->pci.port.msi_data) + { + rt_dma_free_coherent(dev, sizeof(rt_uint64_t), k1x->pci.port.msi_data, k1x->pci.port.msi_data_phy); + } + if (k1x->msix_data) + { + rt_dma_free_coherent(dev, sizeof(rt_uint64_t), k1x->msix_data, k1x->msix_data_phy); + } + + rt_free(k1x); + + return err; +} + +static const struct k1x_pcie_soc_data k1x_pcie_rc_soc_data = +{ + .mode = DW_PCIE_RC_TYPE, +}; + +static const struct k1x_pcie_soc_data k1x_pcie_ep_soc_data = +{ + .mode = DW_PCIE_EP_TYPE, +}; + +static const struct rt_ofw_node_id k1x_pcie_dw_ofw_ids[] = +{ + { .compatible = "k1x,dwc-pcie", .data = &k1x_pcie_rc_soc_data, }, + { .compatible = "k1x,dwc-pcie-ep", .data = &k1x_pcie_ep_soc_data, }, + { /* sentinel */ } +}; + +static struct rt_platform_driver k1x_pcie_dw_driver = +{ + .name = "dw-pcie-k1x", + .ids = k1x_pcie_dw_ofw_ids, + + .probe = k1x_pcie_dw_probe, +}; +RT_PLATFORM_DRIVER_EXPORT(k1x_pcie_dw_driver); diff --git a/bsp/spacemit/dm/pin/Kconfig b/bsp/spacemit/dm/pin/Kconfig new file mode 100644 index 000000000000..b4a0fbd0fcfa --- /dev/null +++ b/bsp/spacemit/dm/pin/Kconfig @@ -0,0 +1,5 @@ +config RT_PIN_K1X + bool "Spacemit K1X GPIO GPIO support" + depends on RT_USING_OFW + depends on RT_USING_ADT_BITMAP + default y diff --git a/bsp/spacemit/dm/pin/SConscript b/bsp/spacemit/dm/pin/SConscript new file mode 100644 index 000000000000..b91f5b9d9cc8 --- /dev/null +++ b/bsp/spacemit/dm/pin/SConscript @@ -0,0 +1,13 @@ +from building import * + +group = [] +src = [] +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../include', cwd + '/../../../../components/drivers/pin'] + +if GetDepend(['RT_PIN_K1X']): + src += ['pin-k1x.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/spacemit/dm/pin/pin-k1x.c b/bsp/spacemit/dm/pin/pin-k1x.c new file mode 100644 index 000000000000..b7ff6235ed29 --- /dev/null +++ b/bsp/spacemit/dm/pin/pin-k1x.c @@ -0,0 +1,421 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#include +#include +#include +#include + +#define DBG_TAG "pin.k1" +#define DBG_LVL DBG_INFO +#include + +#include "dev_pin_dm.h" + +#define GPLR 0x0 +#define GPDR 0xc +#define GPSR 0x18 +#define GPCR 0x24 +#define GRER 0x30 +#define GFER 0x3c +#define GEDR 0x48 +#define GSDR 0x54 +#define GCDR 0x60 +#define GSRER 0x6c +#define GCRER 0x78 +#define GSFER 0x84 +#define GCFER 0x90 +#define GAPMASK 0x9c +#define GCPMASK 0xa8 + +#define K1X_BANK_GPIO_NUMBER 32 +#define BANK_GPIO_MASK (K1X_BANK_GPIO_NUMBER - 1) + +#define k1x_gpio_to_bank_idx(gpio) ((gpio) / K1X_BANK_GPIO_NUMBER) +#define k1x_gpio_to_bank_offset(gpio) ((gpio) & BANK_GPIO_MASK) + +struct k1x_gpio_bank +{ + void *reg_bank; + rt_uint32_t irq_mask; + rt_uint32_t irq_rising_edge; + rt_uint32_t irq_falling_edge; + + RT_BITMAP_DECLARE(value, K1X_BANK_GPIO_NUMBER); +}; + +struct k1x_gpio_chip +{ + struct rt_device_pin parent; + + int irq; + void *reg_base; + + unsigned int nbank; + struct k1x_gpio_bank *banks; +}; + +#define raw_to_k1x_gpio_chip(raw) rt_container_of(raw, struct k1x_gpio_chip, parent) + +static void k1x_pin_mode(struct rt_device *device, rt_base_t pin, rt_uint8_t mode) +{ + rt_uint32_t bit, offset; + struct k1x_gpio_chip *k1x_chip = raw_to_k1x_gpio_chip(device); + struct k1x_gpio_bank *bank = &k1x_chip->banks[k1x_gpio_to_bank_idx(pin)]; + + offset = k1x_gpio_to_bank_offset(pin); + bit = RT_BIT(offset); + + switch (mode) + { + case PIN_MODE_OUTPUT: + case PIN_MODE_OUTPUT_OD: + HWREG32(bank->reg_bank + (rt_bitmap_test_bit(bank->value, offset) ? GPSR : GPCR)) = bit; + HWREG32(bank->reg_bank + GSDR) = bit; + break; + + case PIN_MODE_INPUT: + case PIN_MODE_INPUT_PULLUP: + case PIN_MODE_INPUT_PULLDOWN: + HWREG32(bank->reg_bank + GCDR) = bit; + break; + + default: + break; + } +} + +static void k1x_pin_write(struct rt_device *device, rt_base_t pin, rt_uint8_t value) +{ + rt_uint32_t bit, offset, reg; + struct k1x_gpio_chip *k1x_chip = raw_to_k1x_gpio_chip(device); + struct k1x_gpio_bank *bank = &k1x_chip->banks[k1x_gpio_to_bank_idx(pin)]; + + offset = k1x_gpio_to_bank_offset(pin); + bit = RT_BIT(offset); + + if (HWREG32(bank->reg_bank + GPDR) & bit) + { + if (value) + { + reg = GPSR; + rt_bitmap_set_bit(bank->value, offset); + } + else + { + reg = GPCR; + rt_bitmap_clear_bit(bank->value, offset); + } + + HWREG32(bank->reg_bank + reg) = bit; + } +} + +static rt_ssize_t k1x_pin_read(struct rt_device *device, rt_base_t pin) +{ + rt_uint32_t bit; + struct k1x_gpio_chip *k1x_chip = raw_to_k1x_gpio_chip(device); + struct k1x_gpio_bank *bank = &k1x_chip->banks[k1x_gpio_to_bank_idx(pin)]; + + bit = RT_BIT(k1x_gpio_to_bank_offset(pin)); + + return !!(HWREG32(bank->reg_bank + GPLR) & bit); +} + +static rt_err_t k1x_pin_irq_enable(struct rt_device *device, rt_base_t pin, rt_uint8_t enabled) +{ + rt_uint32_t bit; + struct k1x_gpio_chip *k1x_chip = raw_to_k1x_gpio_chip(device); + struct k1x_gpio_bank *bank = &k1x_chip->banks[k1x_gpio_to_bank_idx(pin)]; + + bit = RT_BIT(k1x_gpio_to_bank_offset(pin)); + + if (enabled) + { + bank->irq_mask |= bit; + + /* Set the bit of rising and falling edge detection if the gpio has. */ + HWREG32(bank->reg_bank + GSRER) = bit & bank->irq_rising_edge; + HWREG32(bank->reg_bank + GSFER) = bit & bank->irq_falling_edge; + } + else + { + bank->irq_mask &= ~bit; + + /* Clear the bit of rising and falling edge detection. */ + HWREG32(bank->reg_bank + GCRER) = bit; + HWREG32(bank->reg_bank + GCFER) = bit; + } + + return RT_EOK; +} + +static rt_err_t k1x_pin_irq_mode(struct rt_device *device, rt_base_t pin, rt_uint8_t mode) +{ + rt_uint32_t bit; + struct k1x_gpio_chip *k1x_chip = raw_to_k1x_gpio_chip(device); + struct k1x_gpio_bank *bank = &k1x_chip->banks[k1x_gpio_to_bank_idx(pin)]; + + bit = RT_BIT(k1x_gpio_to_bank_offset(pin)); + + if (mode == PIN_IRQ_MODE_RISING) + { + bank->irq_rising_edge |= bit; + HWREG32(bank->reg_bank + GSRER) = bit; + } + else + { + bank->irq_rising_edge &= ~bit; + HWREG32(bank->reg_bank + GCRER) = bit; + } + + if (mode == PIN_IRQ_MODE_FALLING) + { + bank->irq_falling_edge |= bit; + HWREG32(bank->reg_bank + GSFER) = bit; + } + else + { + bank->irq_falling_edge &= ~bit; + HWREG32(bank->reg_bank + GCFER) = bit; + } + + return RT_EOK; +} + +static rt_ssize_t k1x_pin_parse(struct rt_device *device, + struct rt_ofw_cell_args *args, rt_uint32_t *flags) +{ + rt_base_t gpio_pin; + rt_err_t err = RT_EOK; + + if (flags) + { + *flags = args->args[1]; + } + + gpio_pin = args->args[0]; + + for (int i = 0;; ++i) + { + rt_base_t gpio_start, pad_start; + struct rt_device_pin *pinctrl; + struct rt_ofw_cell_args gpio_ranges; + + if (rt_ofw_parse_phandle_cells(device->ofw_node, "gpio-ranges", + "#gpio-range-cells", i, &gpio_ranges)) + { + break; + } + + gpio_start = gpio_ranges.args[0]; + pad_start = gpio_ranges.args[1]; + + if (gpio_pin < gpio_start || gpio_pin > gpio_start + gpio_ranges.args[2]) + { + rt_ofw_node_put(gpio_ranges.data); + continue; + } + + if (!(pinctrl = rt_ofw_data(gpio_ranges.data))) + { + err = -RT_EIO; + goto _end; + } + + err = pin_gpio_request(pinctrl, pad_start + (gpio_pin - gpio_start), args->args[1]); + + _end: + rt_ofw_node_put(gpio_ranges.data); + + break; + } + + return err ? : gpio_pin; +} + +static const struct rt_pin_ops k1x_pin_ops = +{ + .pin_mode = k1x_pin_mode, + .pin_write = k1x_pin_write, + .pin_read = k1x_pin_read, + .pin_irq_enable = k1x_pin_irq_enable, + .pin_irq_mode = k1x_pin_irq_mode, + .pin_parse = k1x_pin_parse, +}; + +static void k1x_gpio_isr(int irqno, void *param) +{ + int n; + rt_uint32_t gedr; + rt_bitmap_t pending; + struct k1x_gpio_bank *bank; + struct k1x_gpio_chip *k1x_chip = param; + + for (int i = 0; i < k1x_chip->nbank; ++i) + { + bank = &k1x_chip->banks[i]; + + gedr = HWREG32(bank->reg_bank + GEDR); + if (!gedr) + { + continue; + } + + HWREG32(bank->reg_bank + GEDR) = gedr; + gedr = gedr & bank->irq_mask; + + if (!gedr) + { + continue; + } + pending = gedr; + + rt_bitmap_for_each_set_bit(&pending, n, RT_BITS_PER_LONG) + { + rt_base_t pin = (i * K1X_BANK_GPIO_NUMBER) | (n & BANK_GPIO_MASK); + + HWREG32(bank->reg_bank + GEDR) = (1 << k1x_gpio_to_bank_offset(pin)); + + pin_pic_handle_isr(&k1x_chip->parent, pin); + } + } +} + +static rt_err_t k1x_gpio_probe(struct rt_platform_device *pdev) +{ + int i = 0; + rt_err_t err; + const char *name; + struct rt_clk *clk = RT_NULL; + struct rt_device *dev = &pdev->parent; + struct rt_ofw_node *np = dev->ofw_node, *child; + struct k1x_gpio_bank *bank; + struct k1x_gpio_chip *k1x_chip = rt_calloc(1, sizeof(*k1x_chip)); + + if (!k1x_chip) + { + return -RT_ENOMEM; + } + + if (!(k1x_chip->reg_base = rt_dm_dev_iomap(dev, 0))) + { + err = -RT_EIO; + goto _fail; + } + + if ((k1x_chip->irq = rt_dm_dev_get_irq(dev, 0)) < 0) + { + err = k1x_chip->irq; + goto _fail; + } + + k1x_chip->nbank = rt_ofw_get_child_count(np); + k1x_chip->banks = rt_calloc(k1x_chip->nbank, sizeof(*k1x_chip->banks)); + + if (!k1x_chip->banks) + { + err = -RT_ENOMEM; + goto _fail; + } + + rt_ofw_foreach_child_node(np, child) + { + rt_uint32_t offset; + + if ((err = rt_ofw_prop_read_u32(child, "reg-offset", &offset))) + { + rt_ofw_node_put(child); + goto _fail; + } + + k1x_chip->banks[i++].reg_bank = k1x_chip->reg_base + offset; + } + + clk = rt_clk_get_by_index(dev, 0); + if (rt_is_err(clk)) + { + err = rt_ptr_err(clk); + goto _fail; + } + + if ((err = rt_clk_prepare_enable(clk))) + { + LOG_E("Fail to enable gpio clock"); + goto _fail; + } + + rt_dm_dev_set_name_auto(&k1x_chip->parent.parent, "gpio"); + name = rt_dm_dev_get_name(&k1x_chip->parent.parent); + + rt_hw_interrupt_install(k1x_chip->irq, k1x_gpio_isr, k1x_chip, name); + rt_hw_interrupt_umask(k1x_chip->irq); + + k1x_chip->parent.ops = &k1x_pin_ops; + k1x_chip->parent.parent.ofw_node = np; + pin_api_init(&k1x_chip->parent, k1x_chip->nbank * K1X_BANK_GPIO_NUMBER); + pin_pic_init(&k1x_chip->parent, k1x_chip->irq); + + rt_ofw_data(np) = &k1x_chip->parent; + + /* Clear all GPIO edge detects */ + for (i = 0; i < k1x_chip->nbank; ++i) + { + bank = &k1x_chip->banks[i]; + HWREG32(bank->reg_bank + GCFER) = 0xffffffff; + HWREG32(bank->reg_bank + GCRER) = 0xffffffff; + /* Unmask edge detection to AP. */ + HWREG32(bank->reg_bank + GAPMASK) = 0xffffffff; + } + + return RT_EOK; +_fail: + if (!rt_is_err_or_null(clk)) + { + rt_clk_disable_unprepare(clk); + rt_clk_put(clk); + } + + if (k1x_chip->reg_base) + { + rt_iounmap(k1x_chip->reg_base); + } + + if (k1x_chip->banks) + { + rt_free(k1x_chip->banks); + } + + rt_free(k1x_chip); + + return err; +} + +static const struct rt_ofw_node_id k1x_gpio_ofw_ids[] = +{ + { .compatible = "spacemit,k1x-gpio" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver k1x_gpio_driver = +{ + .name = "k1x-gpio", + .ids = k1x_gpio_ofw_ids, + + .probe = k1x_gpio_probe, +}; + +static int k1x_gpio_register(void) +{ + rt_platform_driver_register(&k1x_gpio_driver); + + return 0; +} +INIT_SUBSYS_EXPORT(k1x_gpio_register); diff --git a/bsp/spacemit/dm/pinctrl/Kconfig b/bsp/spacemit/dm/pinctrl/Kconfig new file mode 100644 index 000000000000..4b2512a158f1 --- /dev/null +++ b/bsp/spacemit/dm/pinctrl/Kconfig @@ -0,0 +1,5 @@ +config RT_PINCTRL_SPACEMIT_PMIC + bool "Pinctrl and GPIO driver for Spacemit PMIC" + depends on RT_USING_PINCTRL + depends on RT_MFD_SPACEMIT_PMIC + default n diff --git a/bsp/spacemit/dm/pinctrl/SConscript b/bsp/spacemit/dm/pinctrl/SConscript new file mode 100644 index 000000000000..1f89d5044006 --- /dev/null +++ b/bsp/spacemit/dm/pinctrl/SConscript @@ -0,0 +1,13 @@ +from building import * + +group = [] +src = [] +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../include'] + +if GetDepend(['RT_PINCTRL_SPACEMIT_PMIC']): + src += ['spacemit-pmic-pinctrl.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/spacemit/dm/pinctrl/spacemit-pmic-pinctrl.c b/bsp/spacemit/dm/pinctrl/spacemit-pmic-pinctrl.c new file mode 100644 index 000000000000..b546b894b0cd --- /dev/null +++ b/bsp/spacemit/dm/pinctrl/spacemit-pmic-pinctrl.c @@ -0,0 +1,364 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#include +#include + +#define DBG_TAG "pinctrl.spacemit-pmic" +#define DBG_LVL DBG_INFO +#include + +#define __SPACEMIT_PINCTRL_INTERNAL +#include + +struct spacemit_pmic_pinctrl +{ + struct rt_device_pin parent; + + rt_uint32_t npins; + + struct spacemit_pmic *pmic; + const struct spacemit_pmic_pin_data *data; +}; + +#define raw_to_spacemit_pmic_pinctrl(raw) rt_container_of(raw, struct spacemit_pmic_pinctrl, parent) + +static rt_err_t spacemit_pmic_pinctrl_set_mux(struct spacemit_pmic_pinctrl *pmic_pinctrl, + rt_uint32_t function, rt_base_t pin) +{ + int i; + rt_err_t err; + const char *funcname; + struct spacemit_pmic *pmic = pmic_pinctrl->pmic; + const struct spacemit_pmic_pin_data *data = pmic_pinctrl->data; + const struct spacemit_pmic_pin_func_desc *pinfunc_desc = data->pinfunc_desc; + + funcname = data->pinmux_funcs[function]; + + for (i = 0; i < data->pin_mux_nr; ++i) + { + if (!rt_strcmp(funcname, pinfunc_desc[i].name) && pin == pinfunc_desc[i].pin_id) + { + /* Set the first */ + err = spacemit_pmic_update_bits(pmic, + pinfunc_desc[i].func_reg, + pinfunc_desc[i].func_mask, + pinfunc_desc[i].en_val << (__rt_ffs(pinfunc_desc[i].func_mask) - 1)); + if (err) + { + LOG_E("Set PIN%d, function:%s, failed", pin, funcname); + return err; + } + + /* Set the next if it have */ + if (pinfunc_desc[i].ha_sub) + { + err = spacemit_pmic_update_bits(pmic, + pinfunc_desc[i].sub_reg, + pinfunc_desc[i].sub_mask, + pinfunc_desc[i].sube_val << (__rt_ffs(pinfunc_desc[i].sub_mask) - 1)); + if (err) + { + LOG_E("Set PIN%d, function:%s, failed", pin, funcname); + return err; + } + } + + break; + } + } + + if (i >= data->pin_mux_nr) + { + LOG_E("Unsupported PIN%d, function:%s", pin, funcname); + return -RT_EINVAL; + } + + return RT_EOK; +} + +static void spacemit_pmic_pinctrl_mode(struct rt_device *device, rt_base_t pin, rt_uint8_t mode) +{ + struct spacemit_pmic_pinctrl *pmic_pinctrl = raw_to_spacemit_pmic_pinctrl(device); + + switch (mode) + { + case PIN_MODE_OUTPUT: + spacemit_pmic_pinctrl_set_mux(pmic_pinctrl, 1, pin); + break; + + case PIN_MODE_INPUT: + spacemit_pmic_pinctrl_set_mux(pmic_pinctrl, 0, pin); + break; + + default: + break; + } +} + +static void spacemit_pmic_pinctrl_write(struct rt_device *device, rt_base_t pin, + rt_uint8_t value) +{ + rt_err_t err; + const struct spacemit_pmic_pin_config_desc *pinconf_desc; + struct spacemit_pmic_pinctrl *pmic_pinctrl = raw_to_spacemit_pmic_pinctrl(device); + + pinconf_desc = pmic_pinctrl->data->pinconf_desc; + + err = spacemit_pmic_update_bits(pmic_pinctrl->pmic, + pinconf_desc[pin].output.reg, + pinconf_desc[pin].output.msk, + value ? pinconf_desc[pin].output.msk : 0); + + if (err) + { + LOG_E("Set PIN%d, val:%d, failed", pin, value); + } +} + +static rt_ssize_t spacemit_pmic_pinctrl_read(struct rt_device *device, rt_base_t pin) +{ + rt_ssize_t val; + const struct spacemit_pmic_pin_config_desc *pinconf_desc; + struct spacemit_pmic_pinctrl *pmic_pinctrl = raw_to_spacemit_pmic_pinctrl(device); + + pinconf_desc = pmic_pinctrl->data->pinconf_desc; + + if ((val = spacemit_pmic_read(pmic_pinctrl->pmic, pinconf_desc[pin].input.reg)) < 0) + { + LOG_E("Get PIN%d, direction failed", pin); + return val; + } + + val = val & pinconf_desc[pin].input.msk; + val >>= __rt_ffs(pinconf_desc[pin].input.msk) - 1; + + return val; +} + +static rt_ssize_t spacemit_pmic_pin_parse(struct rt_device *device, + struct rt_ofw_cell_args *args, rt_uint32_t *flags) +{ + if (flags) + { + *flags = args->args[1]; + } + + return args->args[0]; +} + +static const struct rt_pin_ctrl_conf_params spacemit_pmic_pinctrl_params[] = +{ + { "bias-disable", PIN_CONFIG_BIAS_DISABLE }, + { "bias-pull-down", PIN_CONFIG_BIAS_PULL_DOWN }, + { "bias-pull-up", PIN_CONFIG_BIAS_PULL_UP }, + { "drive-open-drain", PIN_CONFIG_DRIVE_OPEN_DRAIN }, + { "drive-push-pull", PIN_CONFIG_DRIVE_PUSH_PULL }, + { "drive-open-source", PIN_CONFIG_DRIVE_OPEN_SOURCE }, + { "input-debounce", PIN_CONFIG_INPUT_DEBOUNCE }, + { "input-schmitt-disable", PIN_CONFIG_INPUT_SCHMITT_ENABLE }, + { "input-schmitt-enable", PIN_CONFIG_INPUT_SCHMITT_ENABLE }, + { "output-high", PIN_CONFIG_OUTPUT }, + { "output-low", PIN_CONFIG_OUTPUT }, +}; + +static rt_bool_t spacemit_pmic_pinctrl_param_parse(const char *name, rt_uint32_t *out_param) +{ + for (int i = 0; i < RT_ARRAY_SIZE(spacemit_pmic_pinctrl_params); ++i) + { + if (!rt_strcmp(spacemit_pmic_pinctrl_params[i].propname, name)) + { + *out_param = spacemit_pmic_pinctrl_params[i].param; + return RT_TRUE; + } + } + + return RT_FALSE; +} + +static rt_err_t spacemit_pmic_pinctrl_confs_apply(struct rt_device *device, void *fw_conf_np) +{ + rt_err_t err; + rt_ubase_t pin; + rt_uint32_t function, param; + const char *string; + struct rt_ofw_prop *pins_prop, *prop; + struct spacemit_pmic_pinctrl *pmic_pinctrl = raw_to_spacemit_pmic_pinctrl(device); + const struct spacemit_pmic_pin_data *data = pmic_pinctrl->data; + const struct spacemit_pmic_pin_config_desc *pinconf_desc = data->pinconf_desc; + struct spacemit_pmic *pmic = pmic_pinctrl->pmic; + + /** + * led_pins: led-pins { + * pins = "PIN3"; + * function = "sleep"; + * bias-disable = <0>; + * drive-open-drain = <0x1>; + * }; + */ + + if ((err = rt_ofw_prop_read_string(fw_conf_np, "function", &string))) + { + return err; + } + + function = data->pin_mux_nr; + + for (int i = 0; i < data->pin_mux_nr; ++i) + { + if (!rt_strcmp(data->pinmux_funcs[i], string)) + { + function = i; + } + } + + if (function >= data->pin_mux_nr) + { + return -RT_EINVAL; + } + + rt_ofw_foreach_prop_string(fw_conf_np, "pins", pins_prop, string) + { + pin = 0; + string += sizeof("PIN") - 1; + + while (*string) + { + pin *= 10; + pin += *string - '0'; + + ++string; + } + + if (spacemit_pmic_pinctrl_set_mux(pmic_pinctrl, function, pin)) + { + return err; + } + + rt_ofw_foreach_prop(((struct rt_ofw_node *)fw_conf_np), prop) + { + rt_uint32_t reg, msk; + + if (!rt_strcmp(prop->name, "pins") || !rt_strcmp(prop->name, "function")) + { + continue; + } + + if (!spacemit_pmic_pinctrl_param_parse(prop->name, ¶m)) + { + return -RT_ENOSYS; + } + + switch (param) + { + case PIN_CONFIG_BIAS_DISABLE: + case PIN_CONFIG_BIAS_PULL_DOWN: + case PIN_CONFIG_BIAS_PULL_UP: + reg = pinconf_desc[pin].pup.reg; + msk = pinconf_desc[pin].pup.msk; + break; + case PIN_CONFIG_DRIVE_OPEN_DRAIN: + case PIN_CONFIG_DRIVE_PUSH_PULL: + case PIN_CONFIG_DRIVE_OPEN_SOURCE: + reg = pinconf_desc[pin].od.reg; + msk = pinconf_desc[pin].od.msk; + break; + case PIN_CONFIG_INPUT_DEBOUNCE: + reg = pinconf_desc[pin].deb.reg; + msk = pinconf_desc[pin].deb.timemsk; + break; + case PIN_CONFIG_INPUT_SCHMITT_ENABLE: + reg = pinconf_desc[pin].deb.reg; + msk = pinconf_desc[pin].deb.en.msk; + break; + case PIN_CONFIG_OUTPUT: + reg = pinconf_desc[pin].output.reg; + msk = pinconf_desc[pin].output.msk; + break; + default: + LOG_E("To fixed your code"); + RT_ASSERT(0); + break; + } + + err = spacemit_pmic_update_bits(pmic, reg, msk, + fdt32_to_cpu(*(fdt32_t *)prop->value) << (__rt_ffs(msk) - 1)); + if (err) + { + LOG_E("Set reg:%x, msk:%x failed", reg, msk); + return -RT_EINVAL; + } + } + } + + return RT_EOK; +} + +static const struct rt_pin_ops spacemit_pmic_pinctrl_ops = +{ + .pin_mode = spacemit_pmic_pinctrl_mode, + .pin_write = spacemit_pmic_pinctrl_write, + .pin_read = spacemit_pmic_pinctrl_read, + .pin_parse = spacemit_pmic_pin_parse, + .pin_ctrl_confs_apply = spacemit_pmic_pinctrl_confs_apply, +}; + +static rt_err_t spacemit_pmic_pinctrl_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + struct rt_device *dev = &pdev->parent; + struct spacemit_pmic *pmic = pdev->priv; + struct spacemit_pmic_pinctrl *pmic_pinctrl = rt_calloc(1, sizeof(*pmic_pinctrl)); + + if (!pmic_pinctrl) + { + return -RT_ENOMEM; + } + + pmic_pinctrl->pmic = pmic; + pmic_pinctrl->data = pdev->id->data; + + if ((err = rt_dm_dev_prop_read_u32(dev, "spacemit,npins", &pmic_pinctrl->npins))) + { + goto _fail; + } + + pmic_pinctrl->parent.ops = &spacemit_pmic_pinctrl_ops; + rt_ofw_data(dev->ofw_node) = &pmic_pinctrl->parent; + + return RT_EOK; + +_fail: + rt_free(pmic_pinctrl); + + return err; +} + +static const struct rt_ofw_node_id spacemit_pmic_pinctrl_ofw_ids[] = +{ + { .compatible = "pmic,pinctrl,spm8821", .data = &spm8821_pinctrl_data }, + { /* sentinel */ } +}; + +static struct rt_platform_driver spacemit_pmic_pinctrl_driver = +{ + .name = "spacemit-pmic-pinctrl", + .ids = spacemit_pmic_pinctrl_ofw_ids, + + .probe = spacemit_pmic_pinctrl_probe, +}; + +static int spacemit_pmic_pinctrl_register(void) +{ + rt_platform_driver_register(&spacemit_pmic_pinctrl_driver); + + return 0; +} +INIT_SUBSYS_EXPORT(spacemit_pmic_pinctrl_register); diff --git a/bsp/spacemit/dm/pmdomain/Kconfig b/bsp/spacemit/dm/pmdomain/Kconfig new file mode 100644 index 000000000000..fc0b03ed886d --- /dev/null +++ b/bsp/spacemit/dm/pmdomain/Kconfig @@ -0,0 +1,6 @@ +config RT_PMDOMAIN_K1X + bool "Spacemit k1x" + depends on RT_MFD_SYSCON + depends on RT_USING_CLK + depends on RT_USING_REGULATOR + default y diff --git a/bsp/spacemit/dm/pmdomain/SConscript b/bsp/spacemit/dm/pmdomain/SConscript new file mode 100644 index 000000000000..13765f24355c --- /dev/null +++ b/bsp/spacemit/dm/pmdomain/SConscript @@ -0,0 +1,12 @@ +from building import * + +cwd = GetCurrentDir() +src = [] +CPPPATH = [cwd + '/../include'] + +if GetDepend(['RT_PMDOMAIN_K1X']): + src += ['pm-domain-k1x.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/spacemit/dm/pmdomain/pm-domain-k1x.c b/bsp/spacemit/dm/pmdomain/pm-domain-k1x.c new file mode 100644 index 000000000000..5f20d701ec5d --- /dev/null +++ b/bsp/spacemit/dm/pmdomain/pm-domain-k1x.c @@ -0,0 +1,582 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#include +#include +#include + +#include +#include + +#define DBG_TAG "pm-domain.spacemit.k1x" +#define DBG_LVL DBG_INFO +#include + +#define MAX_REGULATOR_PER_DOMAIN 5 + +#define APMU_POWER_STATUS_REG 0xf0 +#define MPMU_AWUCRM_REG 0x104c + +struct spacemit_pmu; + +struct spacemit_pm_domain_param +{ + rt_uint32_t reg_pwr_ctrl; + rt_uint32_t pm_qos; + rt_uint32_t bit_hw_mode; + rt_uint32_t bit_sleep2; + rt_uint32_t bit_sleep1; + rt_uint32_t bit_isolation; + rt_uint32_t bit_auto_pwr_on; + rt_uint32_t bit_hw_pwr_stat; + rt_uint32_t bit_pwr_stat; + rt_uint32_t use_hw; +}; + +struct spacemit_pm_domain +{ + struct rt_dm_power_domain parent; + + int index; + int supply_count; + int ref_handle_pm_domain; + struct spacemit_pmu *pmu; + struct rt_regulator *supply[MAX_REGULATOR_PER_DOMAIN]; + + struct spacemit_pm_domain_param param; +}; + +#define raw_to_spacemit_pm_domain(raw) rt_container_of(raw, struct spacemit_pm_domain, parent) + +struct spacemit_pmu +{ + struct rt_dm_power_domain_proxy parent; + + struct rt_syscon *mpmu_regmap; + struct rt_syscon *apmu_regmap; + + rt_uint32_t num_domains; + struct spacemit_pm_domain *domains; +}; + +#define raw_to_spacemit_pmu(raw) rt_container_of(raw, struct spacemit_pmu, parent) + +static rt_err_t spacemit_pd_power_on(struct rt_dm_power_domain *domain) +{ + int loop; + rt_err_t err; + rt_uint32_t val; + struct spacemit_pmu *pmu; + struct spacemit_pm_domain *spd = raw_to_spacemit_pm_domain(domain); + + if (spd->param.reg_pwr_ctrl == 0) + { + return RT_EOK; + } + + if (spd->ref_handle_pm_domain > 0) + { + return RT_EOK; + } + + /* Enable the supply */ + for (int loop = 0; loop < spd->supply_count; ++loop) + { + if ((err = rt_regulator_enable(spd->supply[loop])) && spd->supply[loop]) + { + return err; + } + } + + pmu = spd->pmu; + + rt_syscon_read(pmu->apmu_regmap, APMU_POWER_STATUS_REG, &val); + + if (val & (1 << spd->param.bit_pwr_stat)) + { + if (spd->index == K1X_PMU_LCD_PWR_DOMAIN) + { + return RT_EOK; + } + + if (!spd->param.use_hw) + { + /* This is the sw type */ + rt_syscon_read(pmu->apmu_regmap, spd->param.reg_pwr_ctrl, &val); + val &= ~(1 << spd->param.bit_isolation); + rt_syscon_write(pmu->apmu_regmap, spd->param.reg_pwr_ctrl, val); + + rt_hw_us_delay(12); + + /* MCU power off */ + rt_syscon_read(pmu->apmu_regmap, spd->param.reg_pwr_ctrl, &val); + val &= ~((1 << spd->param.bit_sleep1) | (1 << spd->param.bit_sleep2)); + rt_syscon_write(pmu->apmu_regmap, spd->param.reg_pwr_ctrl, val); + + rt_hw_us_delay(12); + + for (loop = 10000; loop >= 0; --loop) + { + rt_syscon_read(pmu->apmu_regmap, APMU_POWER_STATUS_REG, &val); + + if ((val & (1 << spd->param.bit_pwr_stat)) == 0) + { + break; + } + + rt_hw_us_delay(5); + } + } + else + { + /* LCD */ + rt_syscon_read(pmu->apmu_regmap, spd->param.reg_pwr_ctrl, &val); + val &= ~(1 << spd->param.bit_auto_pwr_on); + val &= ~(1 << spd->param.bit_hw_mode); + rt_syscon_write(pmu->apmu_regmap, spd->param.reg_pwr_ctrl, val); + + rt_hw_us_delay(20); + + for (loop = 10000; loop >= 0; --loop) + { + rt_syscon_read(pmu->apmu_regmap, APMU_POWER_STATUS_REG, &val); + + if ((val & (1 << spd->param.bit_hw_pwr_stat)) == 0) + { + break; + } + + rt_hw_us_delay(5); + } + } + + if (loop < 0) + { + LOG_E("Power on Domain(%d) fail", spd->index); + return -RT_EBUSY; + } + } + + if (!spd->param.use_hw) + { + /* mcu power on */ + rt_syscon_read(pmu->apmu_regmap, spd->param.reg_pwr_ctrl, &val); + val |= (1 << spd->param.bit_sleep1); + rt_syscon_write(pmu->apmu_regmap, spd->param.reg_pwr_ctrl, val); + + rt_hw_us_delay(22); + + rt_syscon_read(pmu->apmu_regmap, spd->param.reg_pwr_ctrl, &val); + val |= (1 << spd->param.bit_sleep2) | (1 << spd->param.bit_sleep1); + rt_syscon_write(pmu->apmu_regmap, spd->param.reg_pwr_ctrl, val); + + rt_hw_us_delay(22); + + /* disable isolation */ + rt_syscon_read(pmu->apmu_regmap, spd->param.reg_pwr_ctrl, &val); + val |= (1 << spd->param.bit_isolation); + rt_syscon_write(pmu->apmu_regmap, spd->param.reg_pwr_ctrl, val); + + rt_hw_us_delay(12); + + for (loop = 10000; loop >= 0; --loop) + { + rt_syscon_read(pmu->apmu_regmap, APMU_POWER_STATUS_REG, &val); + + if (val & (1 << spd->param.bit_pwr_stat)) + { + break; + } + + rt_hw_us_delay(5); + } + } + else + { + /* LCD */ + rt_syscon_read(pmu->apmu_regmap, spd->param.reg_pwr_ctrl, &val); + val |= (1 << spd->param.bit_auto_pwr_on); + val |= (1 << spd->param.bit_hw_mode); + rt_syscon_write(pmu->apmu_regmap, spd->param.reg_pwr_ctrl, val); + + rt_hw_us_delay(300); + + for (loop = 10000; loop >= 0; --loop) + { + rt_syscon_read(pmu->apmu_regmap, APMU_POWER_STATUS_REG, &val); + + if (val & (1 << spd->param.bit_hw_pwr_stat)) + { + break; + } + + rt_hw_us_delay(5); + } + } + + if (loop < 0) + { + LOG_E("Power on Domain(%d) fail", spd->index); + return -RT_EBUSY; + } + + return RT_EOK; +} + +static rt_err_t spacemit_pd_power_off(struct rt_dm_power_domain *domain) +{ + int loop; + rt_err_t err; + rt_uint32_t val; + struct spacemit_pmu *pmu; + struct spacemit_pm_domain *spd = raw_to_spacemit_pm_domain(domain); + + if (spd->param.reg_pwr_ctrl == 0) + { + return RT_EOK; + } + + if (spd->ref_handle_pm_domain > 0) + { + return RT_EOK; + } + + pmu = spd->pmu; + + if (!spd->param.use_hw) + { + /* this is the sw type */ + rt_syscon_read(pmu->apmu_regmap, spd->param.reg_pwr_ctrl, &val); + val &= ~(1 << spd->param.bit_isolation); + rt_syscon_write(pmu->apmu_regmap, spd->param.reg_pwr_ctrl, val); + + rt_hw_us_delay(12); + + /* mcu power off */ + rt_syscon_read(pmu->apmu_regmap, spd->param.reg_pwr_ctrl, &val); + val &= ~((1 << spd->param.bit_sleep1) | (1 << spd->param.bit_sleep2)); + rt_syscon_write(pmu->apmu_regmap, spd->param.reg_pwr_ctrl, val); + + rt_hw_us_delay(12); + + for (loop = 10000; loop >= 0; --loop) + { + rt_syscon_read(pmu->apmu_regmap, APMU_POWER_STATUS_REG, &val); + + if ((val & (1 << spd->param.bit_pwr_stat)) == 0) + { + break; + } + + rt_hw_us_delay(5); + } + } + else + { + /* LCD */ + rt_syscon_read(pmu->apmu_regmap, spd->param.reg_pwr_ctrl, &val); + val &= ~(1 << spd->param.bit_auto_pwr_on); + val &= ~(1 << spd->param.bit_hw_mode); + rt_syscon_write(pmu->apmu_regmap, spd->param.reg_pwr_ctrl, val); + + rt_hw_us_delay(20); + + for (loop = 10000; loop >= 0; --loop) + { + rt_syscon_read(pmu->apmu_regmap, APMU_POWER_STATUS_REG, &val); + + if ((val & (1 << spd->param.bit_hw_pwr_stat)) == 0) + { + break; + } + + rt_hw_us_delay(5); + } + } + + if (loop < 0) + { + LOG_E("Power off Domain(%d) fail", spd->index); + return -RT_EBUSY; + } + + /* enable the supply */ + for (loop = 0; loop < spd->supply_count; ++loop) + { + if ((err = rt_regulator_disable(spd->supply[loop])) && spd->supply[loop]) + { + return err; + } + } + + return RT_EOK; +} + +static rt_err_t spacemit_pd_attach_dev(struct rt_dm_power_domain *domain, + struct rt_device *dev) +{ + struct spacemit_pm_domain *spd = raw_to_spacemit_pm_domain(domain); + + if (rt_ofw_prop_read_bool(dev->ofw_node, "pwr-domain,pm-runtime,no-sleep")) + { + ++spd->ref_handle_pm_domain; + } + + return RT_EOK; +} + +static rt_err_t spacemit_pd_detach_dev(struct rt_dm_power_domain *domain, + struct rt_device *dev) +{ + struct spacemit_pm_domain *spd = raw_to_spacemit_pm_domain(domain); + + if (rt_ofw_prop_read_bool(dev->ofw_node, "pwr-domain,pm-runtime,no-sleep")) + { + --spd->ref_handle_pm_domain; + } + + return RT_EOK; +} + +static struct rt_dm_power_domain *spacemit_pmdomain_proxy_ofw_parse( + struct rt_dm_power_domain_proxy *proxy, struct rt_ofw_cell_args *args) +{ + struct spacemit_pmu *pmu = raw_to_spacemit_pmu(proxy); + + return &pmu->domains[args->args[0]].parent; +} + +static rt_err_t spacemit_pm_add_one_domain(struct spacemit_pmu *pmu, + struct rt_ofw_node *np) +{ + rt_err_t err; + rt_uint32_t idx; + struct rt_device dev; + struct spacemit_pm_domain *spd; + struct rt_dm_power_domain *domain; + const char *strings[MAX_REGULATOR_PER_DOMAIN]; + + if ((err = rt_ofw_prop_read_u32(np, "reg", &idx))) + { + LOG_E("Failed to read %s domain id (reg) error = %s", + rt_ofw_node_full_name(np), rt_strerror(err)); + return err; + } + + spd = &pmu->domains[idx]; + spd->index = idx; + + if ((err = rt_ofw_prop_read_u32(np, "pm_qos", &spd->param.pm_qos))) + { + return -RT_EINVAL; + } + + rt_ofw_prop_read_u32(np, "reg_pwr_ctrl", &spd->param.reg_pwr_ctrl); + rt_ofw_prop_read_u32(np, "bit_hw_mode", &spd->param.bit_hw_mode); + rt_ofw_prop_read_u32(np, "bit_sleep2", &spd->param.bit_sleep2); + rt_ofw_prop_read_u32(np, "bit_sleep1", &spd->param.bit_sleep1); + rt_ofw_prop_read_u32(np, "bit_isolation", &spd->param.bit_isolation); + rt_ofw_prop_read_u32(np, "bit_auto_pwr_on", &spd->param.bit_auto_pwr_on); + rt_ofw_prop_read_u32(np, "bit_hw_pwr_stat", &spd->param.bit_hw_pwr_stat); + rt_ofw_prop_read_u32(np, "bit_pwr_stat", &spd->param.bit_pwr_stat); + rt_ofw_prop_read_u32(np, "use_hw", &spd->param.use_hw); + + spd->supply_count = rt_ofw_prop_read_string_array_index(np, "vin-supply-names", + 0, RT_ARRAY_SIZE(strings), strings); + + if (spd->supply_count > 0) + { + dev.ofw_node = np; + + for (int i = 0; i < spd->supply_count; ++i) + { + spd->supply[i] = rt_regulator_get(&dev, strings[i]); + + if (rt_is_err(spd->supply[i])) + { + LOG_E("Regulator supply %s get failed", strings[i]); + return rt_ptr_err(spd->supply[i]); + } + } + } + else + { + spd->supply_count = 0; + } + + spd->pmu = pmu; + + domain = &spd->parent; + domain->power_on = spacemit_pd_power_on; + domain->power_off = spacemit_pd_power_off; + domain->attach_dev = spacemit_pd_attach_dev; + domain->detach_dev = spacemit_pd_detach_dev; + + if ((err = rt_dm_power_domain_register(domain))) + { + return err; + } + + rt_ofw_data(np) = domain; + + return RT_EOK; +} + +static rt_err_t spacemit_pm_add_subdomain(struct spacemit_pmu *pmu, + struct rt_ofw_node *parent) +{ + rt_err_t err = RT_EOK; + rt_uint32_t idx; + struct rt_ofw_node *np; + struct spacemit_pm_domain *child_spd, *parent_spd; + + rt_ofw_foreach_child_node(parent, np) + { + if ((err = rt_ofw_prop_read_u32(np, "reg", &idx))) + { + LOG_E("Failed to read %s domain id (reg) error = %s", + rt_ofw_node_full_name(parent), rt_strerror(err)); + goto _err; + } + + parent_spd = &pmu->domains[idx]; + + if ((err = spacemit_pm_add_one_domain(pmu, np))) + { + LOG_E("Failed to handle node %s error = %s", + rt_ofw_node_full_name(np), rt_strerror(err)); + goto _err; + } + + if ((err = rt_ofw_prop_read_u32(np, "reg", &idx))) + { + LOG_E("Failed to read %s domain id (reg) error = %s", + rt_ofw_node_full_name(np), rt_strerror(err)); + goto _err; + } + + child_spd = &pmu->domains[idx]; + + if ((err = rt_dm_power_domain_register_child(&parent_spd->parent, + &child_spd->parent))) + { + LOG_E("Failed to handle subdomain node %s error = %s", + rt_ofw_node_full_name(np), rt_strerror(err)); + } + + spacemit_pm_add_subdomain(pmu, np); + } + +_err: + rt_ofw_node_put(np); + + return err; +} + +static rt_err_t spacemit_pmdomain_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + struct rt_device *dev = &pdev->parent; + struct rt_ofw_node *np = dev->ofw_node, *child; + struct spacemit_pmu *pmu = rt_calloc(1, sizeof(*pmu)); + + if (!pmu) + { + return -RT_ENOMEM; + } + + pmu->mpmu_regmap = rt_syscon_find_by_ofw_compatible("spacemit,spacemit-mpmu"); + pmu->apmu_regmap = rt_syscon_find_by_ofw_compatible("spacemit,spacemit-apmu"); + + if (!pmu->mpmu_regmap || !pmu->apmu_regmap) + { + err = -RT_EINVAL; + goto _fail; + } + + if (rt_dm_dev_prop_read_u32(dev, "domains", &pmu->num_domains)) + { + err = -RT_EINVAL; + goto _fail; + } + + if (!(pmu->domains = rt_calloc(pmu->num_domains, sizeof(*pmu->domains)))) + { + err = -RT_EINVAL; + goto _fail; + } + + rt_ofw_foreach_available_child_node(np, child) + { + if ((err = spacemit_pm_add_one_domain(pmu, child))) + { + LOG_E("Failed to handle node %s error = %s", + rt_ofw_node_full_name(child), rt_strerror(err)); + + rt_ofw_node_put(child); + goto _fail; + } + + if ((err = spacemit_pm_add_subdomain(pmu, child))) + { + LOG_E("Failed to handle subdomain node %s error = %s", + rt_ofw_node_full_name(child), rt_strerror(err)); + + rt_ofw_node_put(child); + goto _fail; + } + } + + pmu->parent.ofw_parse = spacemit_pmdomain_proxy_ofw_parse; + rt_dm_power_domain_proxy_ofw_bind(&pmu->parent, np); + + return RT_EOK; + +_fail: + if (pmu->domains) + { + for (int i = 0; i < pmu->num_domains; ++i) + { + struct spacemit_pm_domain *domain = &pmu->domains[i]; + + if (domain) + { + rt_dm_power_domain_unregister(&domain->parent); + } + } + + rt_free(pmu->domains); + } + rt_free(pmu); + + return err; +} + +static const struct rt_ofw_node_id spacemit_pmdomain_ofw_ids[] = +{ + { .compatible = "spacemit,power-controller", }, + { /* sentinel */ } +}; + +static struct rt_platform_driver spacemit_pmdomain_driver = +{ + .name = "spacemit-pmdomain", + .ids = spacemit_pmdomain_ofw_ids, + + .probe = spacemit_pmdomain_probe, +}; + +static int spacemit_pmdomain_drv_register(void) +{ + rt_platform_driver_register(&spacemit_pmdomain_driver); + + return 0; +} +INIT_SUBSYS_EXPORT(spacemit_pmdomain_drv_register); diff --git a/bsp/spacemit/dm/power/SConscript b/bsp/spacemit/dm/power/SConscript new file mode 100644 index 000000000000..0b84689e91c6 --- /dev/null +++ b/bsp/spacemit/dm/power/SConscript @@ -0,0 +1,11 @@ +from building import * + +cwd = GetCurrentDir() +objs = [] +list = os.listdir(cwd) + +for d in list: + path = os.path.join(cwd, d) + if os.path.isfile(os.path.join(path, 'SConscript')): + objs = objs + SConscript(os.path.join(d, 'SConscript')) +Return('objs') diff --git a/bsp/spacemit/dm/power/reset/Kconfig b/bsp/spacemit/dm/power/reset/Kconfig new file mode 100644 index 000000000000..d6d5e69849f4 --- /dev/null +++ b/bsp/spacemit/dm/power/reset/Kconfig @@ -0,0 +1,2 @@ +config RT_POWER_RESET_REBOOT_SPACEMIT + bool "Spacemit reboot" diff --git a/bsp/spacemit/dm/power/reset/SConscript b/bsp/spacemit/dm/power/reset/SConscript new file mode 100644 index 000000000000..943fda9cbafc --- /dev/null +++ b/bsp/spacemit/dm/power/reset/SConscript @@ -0,0 +1,12 @@ +from building import * + +cwd = GetCurrentDir() +src = [] +CPPPATH = [cwd + '/../../include'] + +if GetDepend(['RT_POWER_RESET_REBOOT_SPACEMIT']): + src += ['reboot-spacemit.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/spacemit/dm/power/reset/reboot-spacemit.c b/bsp/spacemit/dm/power/reset/reboot-spacemit.c new file mode 100644 index 000000000000..3fe266be0650 --- /dev/null +++ b/bsp/spacemit/dm/power/reset/reboot-spacemit.c @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#include +#include + +#define DBG_TAG "reset.reboot.spacemit" +#define DBG_LVL DBG_INFO +#include + +struct spacemit_reboot +{ + void *regs; +}; + +static rt_err_t spacemit_notify_reboot(struct rt_device *dev, char *cmd) +{ + struct spacemit_reboot *reboot = dev->user_data; + + if (cmd) + { + if (!rt_strcmp(cmd, "fastboot")) + { + HWREG32(reboot->regs) = 0x55a; + } + else if (!rt_strcmp(cmd, "uboot")) + { + HWREG32(reboot->regs) = 0x55f; + } + } + + return RT_EOK; +} + +static rt_err_t spacemit_reboot_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + struct rt_device *dev = &pdev->parent; + struct spacemit_reboot *reboot = rt_calloc(1, sizeof(*reboot)); + + if (!reboot) + { + return -RT_ENOMEM; + } + + if (!(reboot->regs = rt_dm_dev_iomap(dev, 0))) + { + err = -RT_ENOMEM; + goto _fail; + } + + if ((err = rt_dm_reboot_mode_register(dev, spacemit_notify_reboot))) + { + goto _fail; + } + + dev->user_data = reboot; + + return RT_EOK; + +_fail: + if (reboot->regs) + { + rt_iounmap(reboot->regs); + } + + rt_free(reboot); + + return err; +} + +static rt_err_t spacemit_reboot_remove(struct rt_platform_device *pdev) +{ + struct spacemit_reboot *reboot = pdev->parent.user_data; + + rt_dm_reboot_mode_unregister(&pdev->parent); + + rt_iounmap(reboot->regs); + + rt_free(reboot); + + return RT_EOK; +} + +static const struct rt_ofw_node_id spacemit_reboot_ofw_ids[] = +{ + { .compatible = "spacemit,k1x-reboot", }, + { /* sentinel */ } +}; + +static struct rt_platform_driver spacemit_reboot_driver = +{ + .name = "spacemit-reboot", + .ids = spacemit_reboot_ofw_ids, + + .probe = spacemit_reboot_probe, + .remove = spacemit_reboot_remove, +}; + +static int spacemit_reboot_drv_register(void) +{ + rt_platform_driver_register(&spacemit_reboot_driver); + + return 0; +} +INIT_SUBSYS_EXPORT(spacemit_reboot_drv_register); diff --git a/bsp/spacemit/dm/pwm/Kconfig b/bsp/spacemit/dm/pwm/Kconfig new file mode 100644 index 000000000000..152c82d8a29d --- /dev/null +++ b/bsp/spacemit/dm/pwm/Kconfig @@ -0,0 +1,4 @@ +config RT_PWM_PXA + bool "PXA PWM support" + depends on RT_USING_PWM + default n diff --git a/bsp/spacemit/dm/pwm/SConscript b/bsp/spacemit/dm/pwm/SConscript new file mode 100644 index 000000000000..e9e880eae3e2 --- /dev/null +++ b/bsp/spacemit/dm/pwm/SConscript @@ -0,0 +1,14 @@ +from building import * + +group = [] +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../include'] + +src = [] + +if GetDepend(['RT_PWM_PXA']): + src += ['pwm-pxa.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/spacemit/dm/pwm/pwm-pxa.c b/bsp/spacemit/dm/pwm/pwm-pxa.c new file mode 100644 index 000000000000..7131de805318 --- /dev/null +++ b/bsp/spacemit/dm/pwm/pwm-pxa.c @@ -0,0 +1,331 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#include +#include + +#define DBG_TAG "pwm.pxa" +#define DBG_LVL DBG_INFO +#include + +#define PWMCR 0x00 +#define PWMDCR 0x04 +#define PWMPCR 0x08 + +#define PWMCR_SD RT_BIT(6) +#define PWMDCR_FD RT_BIT(10) + +struct pxa_pwm +{ + struct rt_device_pwm parent; + + void *regs; + struct rt_clk *clk; + struct rt_reset_control *rstc; + + int dcr_fd; /* Controller PWM_DCR FD feature */ + int rcpu_pwm; /* PWM in rcpu domain */ + rt_bool_t enabled; + +#define QUIRK_HAS_SECONDARY_PWM 0 +#define QUIRK_HAS_PWM_DCR_FD 1 + rt_bitmap_t quirks; +}; + +#define raw_to_pxa_pwm(raw) rt_container_of(raw, struct pxa_pwm, parent) + +static rt_err_t pxa_pwm_toggle(struct pxa_pwm *pc, rt_bool_t enabled) +{ + rt_err_t err = RT_EOK; + + if (pc->enabled == enabled) + { + return err; + } + + if (pc->enabled) + { + rt_clk_disable_unprepare(pc->clk); + } + else + { + err = rt_clk_prepare_enable(pc->clk); + } + + pc->enabled = enabled; + + return err; +} + +static rt_err_t pxa_pwm_apply(struct pxa_pwm *pc, struct rt_pwm_configuration *pwm_cfg) +{ + rt_err_t err; + rt_bool_t enabled; + rt_uint32_t offset; + rt_uint64_t clk, duty_ns, period_ns; + rt_ubase_t period_cycles, prescale, pv, dc; + + if (pwm_cfg->complementary) + { + return -RT_EINVAL; + } + + enabled = pc->enabled; + + if ((err = pxa_pwm_toggle(pc, RT_FALSE))) + { + return err; + } + + /* + * period_ns = 10^9 * (PRESCALE + 1) * (PV + 1) / PWM_CLK_RATE + * duty_ns = 10^9 * (PRESCALE + 1) * DC / PWM_CLK_RATE + */ + duty_ns = enabled ? pwm_cfg->pulse : 0; + period_ns = pwm_cfg->period; + offset = pwm_cfg->channel ? 0x10 : 0; + + clk = rt_clk_get_rate(pc->clk); + clk *= period_ns; + rt_do_div(clk, 1000000000); + period_cycles = clk; + + if (period_cycles < 1) + { + period_cycles = 1; + } + prescale = (period_cycles - 1) / 1024; + pv = period_cycles / (prescale + 1) - 1; + + if (prescale > 63) + { + err = -RT_EINVAL; + goto _end; + } + + if (duty_ns == period_ns) + { + if (pc->quirks & RT_BIT(QUIRK_HAS_PWM_DCR_FD)) + { + if (pc->dcr_fd) + { + dc = PWMDCR_FD; + } + else + { + dc = (pv + 1) * duty_ns / period_ns; + + if (dc >= PWMDCR_FD) + { + dc = PWMDCR_FD - 1; + pv = dc - 1; + } + } + } + else + { + dc = PWMDCR_FD; + } + } + else + { + dc = ((rt_uint64_t)(pv + 1) * duty_ns) / period_ns; + } + + if (pc->quirks & RT_BIT(QUIRK_HAS_PWM_DCR_FD)) + { + prescale |= PWMCR_SD; + } + + HWREG32(pc->regs + offset + PWMCR) = prescale | PWMCR_SD; + HWREG32(pc->regs + offset + PWMDCR) = dc; + HWREG32(pc->regs + offset + PWMPCR) = pv; + +_end: + if (pc->enabled != enabled) + { + err = pxa_pwm_toggle(pc, RT_TRUE); + } + + return err; +} + +static rt_err_t pxa_pwm_control(struct rt_device_pwm *pwm, int cmd, void *args) +{ + rt_err_t err; + struct pxa_pwm *pc = raw_to_pxa_pwm(pwm); + struct rt_pwm_configuration *pwm_cfg = args; + + if (pwm_cfg->channel > 0) + { + if (pwm_cfg->channel > 1 || !pc->quirks & RT_BIT(QUIRK_HAS_SECONDARY_PWM)) + { + return -RT_EINVAL; + } + } + + /* RT_PWM framework have check args */ + switch (cmd) + { + case PWM_CMD_ENABLE: + case PWM_CMD_DISABLE: + err = pxa_pwm_toggle(pc, cmd == PWM_CMD_ENABLE); + break; + + case PWM_CMD_SET: + case PWM_CMD_SET_PERIOD: + case PWM_CMD_SET_PULSE: + err = pxa_pwm_apply(pc, pwm_cfg); + break; + + case PWM_CMD_GET: + err = -RT_ENOSYS; + break; + + default: + err = -RT_EINVAL; + break; + } + + return err; +} + +const static struct rt_pwm_ops pxa_pwm_ops = +{ + .control = pxa_pwm_control, +}; + +static void pxa_pwm_free(struct pxa_pwm *pc) +{ + if (pc->regs) + { + rt_iounmap(pc->regs); + } + + if (rt_is_err_or_null(pc->clk)) + { + rt_clk_put(pc->clk); + } + + if (rt_is_err_or_null(pc->rstc)) + { + rt_reset_control_assert(pc->rstc); + rt_reset_control_put(pc->rstc); + } + + rt_free(pc); +} + +static rt_err_t pxa_pwm_probe(struct rt_platform_device *pdev) +{ + int id; + rt_err_t err; + struct rt_device *dev = &pdev->parent; + struct pxa_pwm *pc = rt_calloc(1, sizeof(*pc)); + + if (!pc) + { + return -RT_ENOMEM; + } + + pc->quirks = pdev->id->data ? *(rt_ubase_t *)pdev->id->data : 0; + + if (pc->quirks & RT_BIT(QUIRK_HAS_PWM_DCR_FD)) + { + pc->dcr_fd = rt_dm_dev_prop_read_bool(dev, "k1x,pwm-disable-fd") ? 0 : 1; + pc->rcpu_pwm = rt_dm_dev_prop_read_bool(dev, "rcpu-pwm") ? 1 : 0; + } + + pc->regs = rt_dm_dev_iomap(dev, 0); + if (!pc->regs) + { + err = -RT_EIO; + goto _fail; + } + + pc->clk = rt_clk_get_by_index(dev, 0); + if (rt_is_err(pc->clk)) + { + err = rt_ptr_err(pc->clk); + goto _fail; + } + + pc->rstc = rt_reset_control_get_by_index(dev, 0); + if (rt_is_err(pc->rstc)) + { + err = rt_ptr_err(pc->rstc); + goto _fail; + } + rt_reset_control_deassert(pc->rstc); + + dev->user_data = pc; + + pc->parent.parent.ofw_node = dev->ofw_node; + + if ((id = pdev->dev_id) >= 0) + { + rt_dm_dev_set_name(&pc->parent.parent, "pwm%u", id); + } + else + { + rt_dm_dev_set_name_auto(&pc->parent.parent, "pwm"); + } + + rt_device_pwm_register(&pc->parent, + rt_dm_dev_get_name(&pc->parent.parent), &pxa_pwm_ops, pc); + + rt_dm_dev_bind_fwdata(dev, RT_NULL, pc); + + return RT_EOK; + +_fail: + pxa_pwm_free(pc); + + return err; +} + +static rt_err_t pxa_pwm_remove(struct rt_platform_device *pdev) +{ + struct rt_device *dev = &pdev->parent; + struct pxa_pwm *pc = dev->user_data; + + pxa_pwm_toggle(pc, RT_FALSE); + + rt_dm_dev_unbind_fwdata(dev, RT_NULL); + + rt_device_unregister(&pc->parent.parent); + + pxa_pwm_free(pc); + + return RT_EOK; +} + +static rt_bitmap_t has_secondary_pwm_quirk = RT_BIT(QUIRK_HAS_SECONDARY_PWM); +static rt_bitmap_t has_pwm_dcr_fd_quirk = RT_BIT(QUIRK_HAS_PWM_DCR_FD); + +static const struct rt_ofw_node_id pxa_pwm_ofw_ids[] = +{ + { .compatible = "marvell,pxa250-pwm", }, + { .compatible = "marvell,pxa270-pwm", .data = &has_secondary_pwm_quirk }, + { .compatible = "marvell,pxa168-pwm", }, + { .compatible = "marvell,pxa910-pwm", }, + { .compatible = "spacemit,k1x-pwm", .data = &has_pwm_dcr_fd_quirk }, + { /* sentinel */ } +}; + +static struct rt_platform_driver pxa_pwm_driver = +{ + .name = "pxa-pwm", + .ids = pxa_pwm_ofw_ids, + + .probe = pxa_pwm_probe, + .remove = pxa_pwm_remove, +}; +RT_PLATFORM_DRIVER_EXPORT(pxa_pwm_driver); diff --git a/bsp/spacemit/dm/regulator/Kconfig b/bsp/spacemit/dm/regulator/Kconfig new file mode 100644 index 000000000000..ad93c9818649 --- /dev/null +++ b/bsp/spacemit/dm/regulator/Kconfig @@ -0,0 +1,5 @@ +config RT_REGULATOR_SPACEMIT_PMIC + bool "Spacemit PMIC Power regulators" + depends on RT_MFD_SPACEMIT_PMIC + depends on RT_USING_PIN + default y diff --git a/bsp/spacemit/dm/regulator/SConscript b/bsp/spacemit/dm/regulator/SConscript new file mode 100644 index 000000000000..48bce18d883a --- /dev/null +++ b/bsp/spacemit/dm/regulator/SConscript @@ -0,0 +1,12 @@ +from building import * + +cwd = GetCurrentDir() +src = [] +CPPPATH = [cwd + '/../include', cwd + '/../../../../components/drivers/regulator'] + +if GetDepend(['RT_REGULATOR_SPACEMIT_PMIC']): + src += ['regulator-spacemit-pmic.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/spacemit/dm/regulator/regulator-spacemit-pmic.c b/bsp/spacemit/dm/regulator/regulator-spacemit-pmic.c new file mode 100644 index 000000000000..731c083da10c --- /dev/null +++ b/bsp/spacemit/dm/regulator/regulator-spacemit-pmic.c @@ -0,0 +1,413 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#define DBG_TAG "regulator.spacemit-pmic" +#define DBG_LVL DBG_INFO +#include + +#include "regulator_dm.h" + +#define __SPACEMIT_REGULATOR_INTERNAL +static const struct rt_regulator_ops pmic_dcdc_ldo_ops, pmic_switch_ops; + +#include + +struct spacemit_pmic_regulator +{ + struct rt_regulator_node parent; + struct rt_regulator_param param; + + struct rt_device device; + struct spacemit_pmic *pmic; + struct rt_ofw_node *ofw_node; + + const struct spacemit_pmic_regulator_desc *desc; +}; + +#define raw_to_spacemit_pmic_regulator(raw) rt_container_of(raw, struct spacemit_pmic_regulator, parent) + +static int regulator_voltage_from_selector(struct spacemit_pmic_regulator *pmic_reg, + int selector) +{ + int uvolt = -1; + const struct spacemit_pmic_regulator_desc *desc = pmic_reg->desc; + + if (desc->ranges_nr) + { + const struct spacemit_pmic_regulator_range *range = &desc->ranges[0]; + + for (int i = desc->ranges_nr - 1; i >= 0; --i, ++range) + { + if (range->min_sel <= selector && range->max_sel >= selector) + { + if (range->min_sel > selector || range->max_sel < selector) + { + return -RT_EINVAL; + } + + uvolt = range->min + (selector - range->min_sel) * range->step; + + break; + } + } + } + else if (desc->voltages_nr) + { + if (selector >= desc->voltages_nr) + { + return -RT_EINVAL; + } + + return desc->uvolt_min + (desc->uvolt_step * selector); + } + else + { + LOG_E("Regulator %s-%s voltages info not found", desc->name, desc->supply_name); + } + + return uvolt; +} + +static int regulator_voltage_to_selector_range(struct spacemit_pmic_regulator *pmic_reg, + int min_uvolt, int max_uvolt) +{ + int selector = 0, max, uvolt, i; + const struct spacemit_pmic_regulator_range *range; + const struct spacemit_pmic_regulator_desc *desc = pmic_reg->desc; + + if (!desc->ranges) + { + return -RT_EINVAL; + } + + for (i = 0; i < desc->ranges_nr; ++i) + { + range = &desc->ranges[i]; + max = range->min + (range->max_sel - range->min_sel) * range->step; + + if (max < min_uvolt) + { + continue; + } + + if (range->min > min_uvolt) + { + selector = range->min_sel; + } + else if (range->step == 0) + { + selector = range->max_sel; + } + else + { + selector = RT_DIV_ROUND_UP(min_uvolt - range->min, range->step) + + range->min_sel; + } + + uvolt = regulator_voltage_from_selector(pmic_reg, selector); + + if (uvolt >= min_uvolt && uvolt <= max_uvolt) + { + break; + } + } + + if (i == desc->ranges_nr) + { + return -RT_EINVAL; + } + + return selector; +} + +static int regulator_voltage_to_selector(struct spacemit_pmic_regulator *pmic_reg, + int min_uvolt, int max_uvolt) +{ + int selector, uvolt; + + /* Allow uvolt_step to be 0 for fixed voltage */ + if (pmic_reg->desc->voltages_nr == 1 && pmic_reg->desc->uvolt_step == 0) + { + if (min_uvolt <= pmic_reg->desc->uvolt_min && pmic_reg->desc->uvolt_min <= max_uvolt) + { + return 0; + } + else + { + return -RT_EINVAL; + } + } + + if (!pmic_reg->desc->uvolt_step) + { + return -RT_EINVAL; + } + + if (min_uvolt < pmic_reg->desc->uvolt_min) + { + min_uvolt = pmic_reg->desc->uvolt_min; + } + + selector = RT_DIV_ROUND_UP(min_uvolt - pmic_reg->desc->uvolt_min, pmic_reg->desc->uvolt_step); + + if (selector < 0) + { + return selector; + } + + /* Map back into a voltage to verify we're still in bounds */ + uvolt = regulator_voltage_from_selector(pmic_reg, selector); + + if (uvolt < min_uvolt || uvolt > max_uvolt) + { + return -RT_EINVAL; + } + + return selector; +} + +static rt_err_t spacemit_pmic_regulator_enable(struct rt_regulator_node *reg_np) +{ + rt_uint32_t val; + struct spacemit_pmic_regulator *pmic_reg = raw_to_spacemit_pmic_regulator(reg_np); + + val = pmic_reg->desc->enable_val; + + if (!val) + { + val = pmic_reg->desc->enable_mask; + } + + return spacemit_pmic_update_bits(pmic_reg->pmic, pmic_reg->desc->enable_reg, + pmic_reg->desc->enable_mask, val); +} + +static rt_err_t spacemit_pmic_regulator_disable(struct rt_regulator_node *reg_np) +{ + rt_uint32_t val; + struct spacemit_pmic_regulator *pmic_reg = raw_to_spacemit_pmic_regulator(reg_np); + + val = pmic_reg->desc->disable_val; + + return spacemit_pmic_update_bits(pmic_reg->pmic, pmic_reg->desc->enable_reg, + pmic_reg->desc->enable_mask, val); +} + +static rt_bool_t spacemit_pmic_regulator_is_enabled(struct rt_regulator_node *reg_np) +{ + rt_uint32_t val; + struct spacemit_pmic_regulator *pmic_reg = raw_to_spacemit_pmic_regulator(reg_np); + + val = spacemit_pmic_read(pmic_reg->pmic, pmic_reg->desc->enable_reg); + + if ((rt_err_t)val < 0) + { + return RT_FALSE; + } + + val &= pmic_reg->desc->enable_mask; + + if (pmic_reg->desc->enable_val) + { + return val == pmic_reg->desc->enable_val; + } + + return val != 0; +} + +static rt_err_t spacemit_pmic_regulator_set_voltage(struct rt_regulator_node *reg_np, + int min_uvolt, int max_uvolt) +{ + int selector; + struct spacemit_pmic_regulator *pmic_reg = raw_to_spacemit_pmic_regulator(reg_np); + + selector = regulator_voltage_to_selector(pmic_reg, min_uvolt, max_uvolt); + + if (selector < 0) + { + if (selector == -RT_EINVAL) + { + selector = regulator_voltage_to_selector_range(pmic_reg, + min_uvolt, max_uvolt); + + if (selector < 0) + { + return -RT_EINVAL; + } + } + } + + selector <<= __rt_ffs(pmic_reg->desc->vsel_mask) - 1; + + return spacemit_pmic_update_bits(pmic_reg->pmic, pmic_reg->desc->vsel_reg, + pmic_reg->desc->vsel_mask, selector); +} + +static int spacemit_pmic_regulator_get_voltage(struct rt_regulator_node *reg_np) +{ + int uvolt; + rt_uint32_t val; + struct spacemit_pmic_regulator *pmic_reg = raw_to_spacemit_pmic_regulator(reg_np); + + val = spacemit_pmic_read(pmic_reg->pmic, pmic_reg->desc->vsel_reg); + + if ((rt_err_t)val < 0) + { + return val; + } + + val &= pmic_reg->desc->vsel_mask; + val >>= __rt_ffs(pmic_reg->desc->vsel_mask) - 1; + + uvolt = regulator_voltage_from_selector(pmic_reg, val); + + return uvolt < 0 ? -RT_EINVAL : uvolt; +} + +static const struct rt_regulator_ops pmic_dcdc_ldo_ops = +{ + .enable = spacemit_pmic_regulator_enable, + .disable = spacemit_pmic_regulator_disable, + .is_enabled = spacemit_pmic_regulator_is_enabled, + .set_voltage = spacemit_pmic_regulator_set_voltage, + .get_voltage = spacemit_pmic_regulator_get_voltage, +}; + +static const struct rt_regulator_ops pmic_switch_ops = +{ + .enable = spacemit_pmic_regulator_enable, + .disable = spacemit_pmic_regulator_disable, + .is_enabled = spacemit_pmic_regulator_is_enabled, +}; + +static rt_err_t append_spacemit_pmic_regulator(struct spacemit_pmic *pmic, + struct rt_ofw_node *np, const struct spacemit_pmic_regulator_desc *desc, int id) +{ + rt_err_t err = RT_EOK; + struct rt_regulator_node *rgp; + struct spacemit_pmic_regulator *pmic_reg; + + pmic_reg = rt_calloc(1, sizeof(*pmic_reg)); + + if (!pmic_reg) + { + return -RT_ENOMEM; + } + + pmic_reg->pmic = pmic; + pmic_reg->desc = &desc[id]; + + regulator_ofw_parse(np, &pmic_reg->param); + + rgp = &pmic_reg->parent; + rgp->supply_name = pmic_reg->param.name; + rgp->ops = pmic_reg->desc->ops; + rgp->param = &pmic_reg->param; + rgp->dev = &pmic_reg->device; + + rgp->dev->ofw_node = np; + + if ((err = rt_regulator_register(rgp))) + { + goto _fail; + } + + return RT_EOK; + +_fail: + rt_free(pmic_reg); + + return err; +} + +static rt_err_t spacemit_pmic_regulator_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + struct rt_ofw_node *np, *regulators_np = pdev->parent.ofw_node; + struct spacemit_pmic *pmic = pdev->priv, *pmic_sub; + const struct spacemit_pmic_regulator_data *data = pdev->id->data; + struct spacemit_pmic_regulator *pmic_reg = rt_calloc(1, sizeof(*pmic_reg)); + + if (!pmic_reg) + { + return -RT_ENOMEM; + } + + if (rt_ofw_node_is_compatible(regulators_np, "pmic,regulator,pm853")) + { + if (!(pmic_sub = rt_calloc(1, sizeof(*pmic_sub)))) + { + err = -RT_ENOMEM; + goto _fail; + } + + rt_memcpy(pmic_sub, pmic, sizeof(*pmic)); + pmic_sub->addr_offset = 1; + + pmic_reg->pmic = pmic_sub; + } + else + { + pmic_reg->pmic = pmic; + } + + for (int i = 0; i < data->desc_nr; ++i) + { + const char *name = data->desc[i].name; + + if (!(np = rt_ofw_get_child_by_tag(regulators_np, name))) + { + continue; + } + + rt_ofw_node_put(np); + + if ((err = append_spacemit_pmic_regulator(pmic, np, data->desc, i))) + { + LOG_E("Append spacemit PMIC regulator %s fail error = %s", + rt_ofw_node_full_name(np), rt_strerror(err)); + + if (err == -RT_ENOMEM) + { + return err; + } + } + } + + return RT_EOK; +_fail: + rt_free(pmic_reg); + + return err; +} + +static const struct rt_ofw_node_id spacemit_pmic_regulator_ofw_ids[] = +{ + { .compatible = "pmic,regulator,spm8821", .data = &spm8821_regulator_data }, + { .compatible = "pmic,regulator,pm853", .data = &pm853_regulator_data }, + { .compatible = "pmic,regulator,sy8810l", .data = &sy8810l_regulator_data }, + { /* sentinel */ } +}; + +static struct rt_platform_driver spacemit_pmic_regulator_driver = +{ + .name = "spacemit-pmic-regulator", + .ids = spacemit_pmic_regulator_ofw_ids, + + .probe = spacemit_pmic_regulator_probe, +}; + +static int spacemit_pmic_regulator_register(void) +{ + rt_platform_driver_register(&spacemit_pmic_regulator_driver); + + return 0; +} +INIT_SUBSYS_EXPORT(spacemit_pmic_regulator_register); diff --git a/bsp/spacemit/dm/reset/Kconfig b/bsp/spacemit/dm/reset/Kconfig new file mode 100644 index 000000000000..b0b81e00898a --- /dev/null +++ b/bsp/spacemit/dm/reset/Kconfig @@ -0,0 +1,4 @@ +config RT_RESET_SPACEMIT_K1 + bool "Reset controller driver for Spacemit K1" + depends on RT_USING_RESET + default y diff --git a/bsp/spacemit/dm/reset/SConscript b/bsp/spacemit/dm/reset/SConscript new file mode 100644 index 000000000000..3994acfe37b3 --- /dev/null +++ b/bsp/spacemit/dm/reset/SConscript @@ -0,0 +1,13 @@ +from building import * + +group = [] +src = [] +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../include'] + +if GetDepend(['RT_RESET_SPACEMIT_K1']): + src += ['reset-spacemit-k1x.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/spacemit/dm/reset/reset-spacemit-k1x.c b/bsp/spacemit/dm/reset/reset-spacemit-k1x.c new file mode 100644 index 000000000000..567828e18e1b --- /dev/null +++ b/bsp/spacemit/dm/reset/reset-spacemit-k1x.c @@ -0,0 +1,332 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#include +#include + +#define DBG_TAG "reset.spacemit.k1x" +#define DBG_LVL DBG_INFO +#include + +#include +#include + +struct spacemit_reset_signal +{ + rt_uint32_t offset; + rt_uint32_t mask; + rt_uint32_t deassert_val; + rt_uint32_t assert_val; + enum cru_type type; +}; + +struct spacemit_reset +{ + struct rt_reset_controller parent; + + union + { + struct + { + void *mpmu_base; + void *apmu_base; + void *apbc_base; + void *apbs_base; + void *ciu_base; + void *dciu_base; + void *ddrc_base; + void *apbc2_base; + void *rcpu_base; + void *rcpu2_base; + void *audpmu_base; + void *audio_ctrl_base; + }; + void *mmio[CRU_BASE_TYPE_MAX]; + }; + + rt_uint32_t signals_nr; + const struct spacemit_reset_signal *signals; +}; + +#define RESET_SIGNAL(name, offset, mask, deassert_val, assert_val, type) \ +[RESET_##name] = \ +{ \ + offset, mask, deassert_val, assert_val, CRU_BASE_TYPE_##type, \ +} \ + +static const struct spacemit_reset_signal k1x_reset_signals[RESET_NUMBER] = +{ + RESET_SIGNAL(UART1, APBC_UART1_CLK_RST, RT_BIT(2), 0, RT_BIT(2), APBC), + RESET_SIGNAL(UART2, APBC_UART2_CLK_RST, RT_BIT(2), 0, RT_BIT(2), APBC), + RESET_SIGNAL(GPIO, APBC_GPIO_CLK_RST, RT_BIT(2), 0, RT_BIT(2), APBC), + RESET_SIGNAL(PWM0, APBC_PWM0_CLK_RST, RT_BIT(2) | RT_BIT(0), RT_BIT(0), RT_BIT(2), APBC), + RESET_SIGNAL(PWM1, APBC_PWM1_CLK_RST, RT_BIT(2) | RT_BIT(0), RT_BIT(0), RT_BIT(2), APBC), + RESET_SIGNAL(PWM2, APBC_PWM2_CLK_RST, RT_BIT(2) | RT_BIT(0), RT_BIT(0), RT_BIT(2), APBC), + RESET_SIGNAL(PWM3, APBC_PWM3_CLK_RST, RT_BIT(2) | RT_BIT(0), RT_BIT(0), RT_BIT(2), APBC), + RESET_SIGNAL(PWM4, APBC_PWM4_CLK_RST, RT_BIT(2) | RT_BIT(0), RT_BIT(0), RT_BIT(2), APBC), + RESET_SIGNAL(PWM5, APBC_PWM5_CLK_RST, RT_BIT(2) | RT_BIT(0), RT_BIT(0), RT_BIT(2), APBC), + RESET_SIGNAL(PWM6, APBC_PWM6_CLK_RST, RT_BIT(2) | RT_BIT(0), RT_BIT(0), RT_BIT(2), APBC), + RESET_SIGNAL(PWM7, APBC_PWM7_CLK_RST, RT_BIT(2) | RT_BIT(0), RT_BIT(0), RT_BIT(2), APBC), + RESET_SIGNAL(PWM8, APBC_PWM8_CLK_RST, RT_BIT(2) | RT_BIT(0), RT_BIT(0), RT_BIT(2), APBC), + RESET_SIGNAL(PWM9, APBC_PWM9_CLK_RST, RT_BIT(2) | RT_BIT(0), RT_BIT(0), RT_BIT(2), APBC), + RESET_SIGNAL(PWM10, APBC_PWM10_CLK_RST, RT_BIT(2) | RT_BIT(0), RT_BIT(0), RT_BIT(2), APBC), + RESET_SIGNAL(PWM11, APBC_PWM11_CLK_RST, RT_BIT(2) | RT_BIT(0), RT_BIT(0), RT_BIT(2), APBC), + RESET_SIGNAL(PWM12, APBC_PWM12_CLK_RST, RT_BIT(2) | RT_BIT(0), RT_BIT(0), RT_BIT(2), APBC), + RESET_SIGNAL(PWM13, APBC_PWM13_CLK_RST, RT_BIT(2) | RT_BIT(0), RT_BIT(0), RT_BIT(2), APBC), + RESET_SIGNAL(PWM14, APBC_PWM14_CLK_RST, RT_BIT(2) | RT_BIT(0), RT_BIT(0), RT_BIT(2), APBC), + RESET_SIGNAL(PWM15, APBC_PWM15_CLK_RST, RT_BIT(2) | RT_BIT(0), RT_BIT(0), RT_BIT(2), APBC), + RESET_SIGNAL(PWM16, APBC_PWM16_CLK_RST, RT_BIT(2) | RT_BIT(0), RT_BIT(0), RT_BIT(2), APBC), + RESET_SIGNAL(PWM17, APBC_PWM17_CLK_RST, RT_BIT(2) | RT_BIT(0), RT_BIT(0), RT_BIT(2), APBC), + RESET_SIGNAL(PWM18, APBC_PWM18_CLK_RST, RT_BIT(2) | RT_BIT(0), RT_BIT(0), RT_BIT(2), APBC), + RESET_SIGNAL(PWM19, APBC_PWM19_CLK_RST, RT_BIT(2) | RT_BIT(0), RT_BIT(0), RT_BIT(2), APBC), + RESET_SIGNAL(SSP3, APBC_SSP3_CLK_RST, RT_BIT(2), 0, RT_BIT(2), APBC), + RESET_SIGNAL(UART3, APBC_UART3_CLK_RST, RT_BIT(2), 0, RT_BIT(2), APBC), + RESET_SIGNAL(RTC, APBC_RTC_CLK_RST, RT_BIT(2), 0, RT_BIT(2), APBC), + RESET_SIGNAL(TWSI0, APBC_TWSI0_CLK_RST, RT_BIT(2), 0, RT_BIT(2), APBC), + RESET_SIGNAL(TIMERS1, APBC_TIMERS1_CLK_RST, RT_BIT(2), 0, RT_BIT(2), APBC), + RESET_SIGNAL(AIB, APBC_AIB_CLK_RST, RT_BIT(2), 0, RT_BIT(2), APBC), + RESET_SIGNAL(TIMERS2, APBC_TIMERS2_CLK_RST, RT_BIT(2), 0, RT_BIT(2), APBC), + RESET_SIGNAL(ONEWIRE, APBC_ONEWIRE_CLK_RST, RT_BIT(2), 0, RT_BIT(2), APBC), + RESET_SIGNAL(SSPA0, APBC_SSPA0_CLK_RST, RT_BIT(2), 0, RT_BIT(2), APBC), + RESET_SIGNAL(SSPA1, APBC_SSPA1_CLK_RST, RT_BIT(2), 0, RT_BIT(2), APBC), + RESET_SIGNAL(DRO, APBC_DRO_CLK_RST, RT_BIT(2), 0, RT_BIT(2), APBC), + RESET_SIGNAL(IR, APBC_IR_CLK_RST, RT_BIT(2), 0, RT_BIT(2), APBC), + RESET_SIGNAL(TWSI1, APBC_TWSI1_CLK_RST, RT_BIT(2), 0, RT_BIT(2), APBC), + RESET_SIGNAL(TSEN, APBC_TSEN_CLK_RST, RT_BIT(2), 0, RT_BIT(2), APBC), + RESET_SIGNAL(TWSI2, APBC_TWSI2_CLK_RST, RT_BIT(2), 0, RT_BIT(2), APBC), + RESET_SIGNAL(TWSI4, APBC_TWSI4_CLK_RST, RT_BIT(2), 0, RT_BIT(2), APBC), + RESET_SIGNAL(TWSI5, APBC_TWSI5_CLK_RST, RT_BIT(2), 0, RT_BIT(2), APBC), + RESET_SIGNAL(TWSI6, APBC_TWSI6_CLK_RST, RT_BIT(2), 0, RT_BIT(2), APBC), + RESET_SIGNAL(TWSI7, APBC_TWSI7_CLK_RST, RT_BIT(2), 0, RT_BIT(2), APBC), + RESET_SIGNAL(TWSI8, APBC_TWSI8_CLK_RST, RT_BIT(2), 0, RT_BIT(2), APBC), + RESET_SIGNAL(IPC_AP2AUD, APBC_IPC_AP2AUD_CLK_RST, RT_BIT(2), 0, RT_BIT(2), APBC), + RESET_SIGNAL(UART4, APBC_UART4_CLK_RST, RT_BIT(2), 0, RT_BIT(2), APBC), + RESET_SIGNAL(UART5, APBC_UART5_CLK_RST, RT_BIT(2), 0, RT_BIT(2), APBC), + RESET_SIGNAL(UART6, APBC_UART6_CLK_RST, RT_BIT(2), 0, RT_BIT(2), APBC), + RESET_SIGNAL(UART7, APBC_UART7_CLK_RST, RT_BIT(2), 0, RT_BIT(2), APBC), + RESET_SIGNAL(UART8, APBC_UART8_CLK_RST, RT_BIT(2), 0, RT_BIT(2), APBC), + RESET_SIGNAL(UART9, APBC_UART9_CLK_RST, RT_BIT(2), 0, RT_BIT(2), APBC), + RESET_SIGNAL(CAN0, APBC_CAN0_CLK_RST, RT_BIT(2), 0, RT_BIT(2), APBC), + /* MPMU */ + RESET_SIGNAL(WDT, MPMU_WDTPCR, RT_BIT(2), 0, RT_BIT(2), MPMU), + /* APMU */ + RESET_SIGNAL(JPG, APMU_JPG_CLK_RES_CTRL, RT_BIT(0), RT_BIT(0), 0, APMU), + RESET_SIGNAL(CSI, APMU_CSI_CCIC2_CLK_RES_CTRL, RT_BIT(1), RT_BIT(1), 0, APMU), + RESET_SIGNAL(CCIC2_PHY, APMU_CSI_CCIC2_CLK_RES_CTRL, RT_BIT(2), RT_BIT(2), 0, APMU), + RESET_SIGNAL(CCIC3_PHY, APMU_CSI_CCIC2_CLK_RES_CTRL, RT_BIT(29), RT_BIT(29), 0, APMU), + RESET_SIGNAL(ISP, APMU_ISP_CLK_RES_CTRL, RT_BIT(0), RT_BIT(0), 0, APMU), + RESET_SIGNAL(ISP_AHB, APMU_ISP_CLK_RES_CTRL, RT_BIT(3), RT_BIT(3), 0, APMU), + RESET_SIGNAL(ISP_CI, APMU_ISP_CLK_RES_CTRL, RT_BIT(16), RT_BIT(16), 0, APMU), + RESET_SIGNAL(ISP_CPP, APMU_ISP_CLK_RES_CTRL, RT_BIT(27), RT_BIT(27), 0, APMU), + RESET_SIGNAL(LCD, APMU_LCD_CLK_RES_CTRL1, RT_BIT(4), RT_BIT(4), 0, APMU), + RESET_SIGNAL(DSI_ESC, APMU_LCD_CLK_RES_CTRL1, RT_BIT(3), RT_BIT(3), 0, APMU), + RESET_SIGNAL(V2D, APMU_LCD_CLK_RES_CTRL1, RT_BIT(27), RT_BIT(27), 0, APMU), + RESET_SIGNAL(MIPI, APMU_LCD_CLK_RES_CTRL1, RT_BIT(15), RT_BIT(15), 0, APMU), + RESET_SIGNAL(LCD_SPI, APMU_LCD_SPI_CLK_RES_CTRL, RT_BIT(0), RT_BIT(0), 0, APMU), + RESET_SIGNAL(LCD_SPI_BUS, APMU_LCD_SPI_CLK_RES_CTRL, RT_BIT(4), RT_BIT(4), 0, APMU), + RESET_SIGNAL(LCD_SPI_HBUS, APMU_LCD_SPI_CLK_RES_CTRL, RT_BIT(2), RT_BIT(2), 0, APMU), + RESET_SIGNAL(LCD_MCLK, APMU_LCD_CLK_RES_CTRL2, RT_BIT(9), RT_BIT(9), 0, APMU), + RESET_SIGNAL(CCIC_4X, APMU_CCIC_CLK_RES_CTRL, RT_BIT(1), RT_BIT(1), 0, APMU), + RESET_SIGNAL(CCIC1_PHY, APMU_CCIC_CLK_RES_CTRL, RT_BIT(2), RT_BIT(2), 0, APMU), + RESET_SIGNAL(SDH_AXI, APMU_SDH0_CLK_RES_CTRL, RT_BIT(0), RT_BIT(0), 0, APMU), + RESET_SIGNAL(SDH0, APMU_SDH0_CLK_RES_CTRL, RT_BIT(1), RT_BIT(1), 0, APMU), + RESET_SIGNAL(SDH1, APMU_SDH1_CLK_RES_CTRL, RT_BIT(1), RT_BIT(1), 0, APMU), + RESET_SIGNAL(USB_AXI, APMU_USB_CLK_RES_CTRL, RT_BIT(0), RT_BIT(0), 0, APMU), + RESET_SIGNAL(USBP1_AXI, APMU_USB_CLK_RES_CTRL, RT_BIT(4), RT_BIT(4), 0, APMU), + RESET_SIGNAL(USB3_0, APMU_USB_CLK_RES_CTRL, RT_BIT(9) | RT_BIT(10) | RT_BIT(11), RT_BIT(9) | RT_BIT(10) | RT_BIT(11), 0, APMU), + RESET_SIGNAL(QSPI, APMU_QSPI_CLK_RES_CTRL, RT_BIT(1), RT_BIT(1), 0, APMU), + RESET_SIGNAL(QSPI_BUS, APMU_QSPI_CLK_RES_CTRL, RT_BIT(0), RT_BIT(0), 0, APMU), + RESET_SIGNAL(DMA, APMU_DMA_CLK_RES_CTRL, RT_BIT(0), RT_BIT(0), 0, APMU), + RESET_SIGNAL(AES, APMU_AES_CLK_RES_CTRL, RT_BIT(4), RT_BIT(4), 0, APMU), + RESET_SIGNAL(VPU, APMU_VPU_CLK_RES_CTRL, RT_BIT(0), RT_BIT(0), 0, APMU), + RESET_SIGNAL(GPU, APMU_GPU_CLK_RES_CTRL, RT_BIT(1), RT_BIT(1), 0, APMU), + RESET_SIGNAL(SDH2, APMU_SDH2_CLK_RES_CTRL, RT_BIT(1), RT_BIT(1), 0, APMU), + RESET_SIGNAL(MC, APMU_PMUA_MC_CTRL, RT_BIT(0), RT_BIT(0), 0, APMU), + RESET_SIGNAL(EM_AXI, APMU_PMUA_EM_CLK_RES_CTRL, RT_BIT(0), RT_BIT(0), 0, APMU), + RESET_SIGNAL(EM, APMU_PMUA_EM_CLK_RES_CTRL, RT_BIT(1), RT_BIT(1), 0, APMU), + RESET_SIGNAL(AUDIO_SYS, APMU_AUDIO_CLK_RES_CTRL, RT_BIT(0) | RT_BIT(2) | RT_BIT(3), RT_BIT(0) | RT_BIT(2) | RT_BIT(3), 0, APMU), + RESET_SIGNAL(HDMI, APMU_HDMI_CLK_RES_CTRL, RT_BIT(9), RT_BIT(9), 0, APMU), + RESET_SIGNAL(PCIE0, APMU_PCIE_CLK_RES_CTRL_0, RT_BIT(3) | RT_BIT(4) | RT_BIT(5) | RT_BIT(8), RT_BIT(3) | RT_BIT(4) | RT_BIT(5), RT_BIT(8), APMU), + RESET_SIGNAL(PCIE1, APMU_PCIE_CLK_RES_CTRL_1, RT_BIT(3) | RT_BIT(4) | RT_BIT(5) | RT_BIT(8), RT_BIT(3) | RT_BIT(4) | RT_BIT(5), RT_BIT(8), APMU), + RESET_SIGNAL(PCIE2, APMU_PCIE_CLK_RES_CTRL_2, 0x138, 0x38, 0x100, APMU), + RESET_SIGNAL(EMAC0, APMU_EMAC0_CLK_RES_CTRL, RT_BIT(1), RT_BIT(1), 0, APMU), + RESET_SIGNAL(EMAC1, APMU_EMAC1_CLK_RES_CTRL, RT_BIT(1), RT_BIT(1), 0, APMU), + /* APBC2 */ + RESET_SIGNAL(SEC_UART1, APBC2_UART1_CLK_RST, RT_BIT(2), 0, RT_BIT(2), APBC2), + RESET_SIGNAL(SEC_SSP2, APBC2_SSP2_CLK_RST, RT_BIT(2), 0, RT_BIT(2), APBC2), + RESET_SIGNAL(SEC_TWSI3, APBC2_TWSI3_CLK_RST, RT_BIT(2), 0, RT_BIT(2), APBC2), + RESET_SIGNAL(SEC_RTC, APBC2_RTC_CLK_RST, RT_BIT(2), 0, RT_BIT(2), APBC2), + RESET_SIGNAL(SEC_TIMERS0, APBC2_TIMERS0_CLK_RST, RT_BIT(2), 0, RT_BIT(2), APBC2), + RESET_SIGNAL(SEC_KPC, APBC2_KPC_CLK_RST, RT_BIT(2), 0, RT_BIT(2), APBC2), + RESET_SIGNAL(SEC_GPIO, APBC2_GPIO_CLK_RST, RT_BIT(2), 0, RT_BIT(2), APBC2), + /* RCPU */ + RESET_SIGNAL(RCPU_HDMIAUDIO, RCPU_HDMI_CLK_RST, RT_BIT(0), RT_BIT(0), 0, RCPU), + RESET_SIGNAL(RCPU_CAN, RCPU_CAN_CLK_RST, RT_BIT(0), RT_BIT(0), 0, RCPU), + /* RCPU */ + RESET_SIGNAL(RCPU_I2C0, RCPU_I2C0_CLK_RST, RT_BIT(0), RT_BIT(0), 0, RCPU), + RESET_SIGNAL(RCPU_SSP0, RCPU_SSP0_CLK_RST, RT_BIT(0), RT_BIT(0), 0, RCPU), + RESET_SIGNAL(RCPU_IR, RCPU_IR_CLK_RST, RT_BIT(0), RT_BIT(0), 0, RCPU), + RESET_SIGNAL(RCPU_UART0, RCPU_UART0_CLK_RST, RT_BIT(0), RT_BIT(0), 0, RCPU), + RESET_SIGNAL(RCPU_UART1, RCPU_UART1_CLK_RST, RT_BIT(0), RT_BIT(0), 0, RCPU), + /* RCPU2 */ + RESET_SIGNAL(RCPU2_PWM0, RCPU2_PWM0_CLK_RST, RT_BIT(2) | RT_BIT(0), RT_BIT(0), RT_BIT(2), RCPU2), + RESET_SIGNAL(RCPU2_PWM1, RCPU2_PWM1_CLK_RST, RT_BIT(2) | RT_BIT(0), RT_BIT(0), RT_BIT(2), RCPU2), + RESET_SIGNAL(RCPU2_PWM2, RCPU2_PWM2_CLK_RST, RT_BIT(2) | RT_BIT(0), RT_BIT(0), RT_BIT(2), RCPU2), + RESET_SIGNAL(RCPU2_PWM3, RCPU2_PWM3_CLK_RST, RT_BIT(2) | RT_BIT(0), RT_BIT(0), RT_BIT(2), RCPU2), + RESET_SIGNAL(RCPU2_PWM4, RCPU2_PWM4_CLK_RST, RT_BIT(2) | RT_BIT(0), RT_BIT(0), RT_BIT(2), RCPU2), + RESET_SIGNAL(RCPU2_PWM5, RCPU2_PWM5_CLK_RST, RT_BIT(2) | RT_BIT(0), RT_BIT(0), RT_BIT(2), RCPU2), + RESET_SIGNAL(RCPU2_PWM6, RCPU2_PWM6_CLK_RST, RT_BIT(2) | RT_BIT(0), RT_BIT(0), RT_BIT(2), RCPU2), + RESET_SIGNAL(RCPU2_PWM7, RCPU2_PWM7_CLK_RST, RT_BIT(2) | RT_BIT(0), RT_BIT(0), RT_BIT(2), RCPU2), + RESET_SIGNAL(RCPU2_PWM8, RCPU2_PWM8_CLK_RST, RT_BIT(2) | RT_BIT(0), RT_BIT(0), RT_BIT(2), RCPU2), + RESET_SIGNAL(RCPU2_PWM9, RCPU2_PWM9_CLK_RST, RT_BIT(2) | RT_BIT(0), RT_BIT(0), RT_BIT(2), RCPU2), +}; + +static rt_uint32_t spacemit_reset_read(struct spacemit_reset *reset, + rt_uint32_t id) +{ + const struct spacemit_reset_signal *signal = &reset->signals[id]; + + return HWREG32(reset->mmio[signal->type] + signal->offset); +} + +static void spacemit_reset_write(struct spacemit_reset *reset, + rt_uint32_t value, rt_uint32_t id) +{ + const struct spacemit_reset_signal *signal = &reset->signals[id]; + + HWREG32(reset->mmio[signal->type] + signal->offset) = value; +} + +static void spacemit_reset_set(struct spacemit_reset *reset, + rt_uint32_t id, rt_bool_t assert) +{ + rt_uint32_t value = spacemit_reset_read(reset, id); + + value &= ~reset->signals[id].mask; + + if (assert) + { + value |=reset->signals[id].assert_val; + } + else + { + value |= reset->signals[id].deassert_val; + } + + spacemit_reset_write(reset, value, id); +} + +static rt_err_t spacemit_reset_update(struct rt_reset_control *rstc, + rt_ubase_t id, rt_bool_t assert) +{ + rt_ubase_t level; + struct spacemit_reset *reset = rstc->rstcer->priv; + + if (id == RESET_TWSI8) + { + return RT_EOK; + } + + level = rt_spin_lock_irqsave(&k1_cru_lock); + + spacemit_reset_set(reset, id, assert); + + rt_spin_unlock_irqrestore(&k1_cru_lock, level); + + return RT_EOK; +} + +static rt_err_t spacemit_reset_assert(struct rt_reset_control *rstc) +{ + return spacemit_reset_update(rstc, rstc->id, RT_TRUE); +} + +static rt_err_t spacemit_reset_deassert(struct rt_reset_control *rstc) +{ + return spacemit_reset_update(rstc, rstc->id, RT_FALSE); +} + +const static struct rt_reset_control_ops spacemit_reset_ops = +{ + .assert = spacemit_reset_assert, + .deassert = spacemit_reset_deassert, +}; + +static rt_err_t spacemit_reset_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + struct rt_device *dev = &pdev->parent; + struct spacemit_reset *reset = rt_calloc(1, sizeof(*reset)); + + if (!reset) + { + return -RT_ENOMEM; + } + + for (int i = 0; i < CRU_BASE_TYPE_AUDPMU; ++i) + { + reset->mmio[i] = rt_dm_dev_iomap(dev, i); + + if (!reset->mmio[i]) + { + err = -RT_EIO; + goto _fail; + } + } + + reset->signals_nr = RT_ARRAY_SIZE(k1x_reset_signals); + reset->signals = k1x_reset_signals; + + reset->parent.priv = reset; + reset->parent.ofw_node = dev->ofw_node; + reset->parent.ops = &spacemit_reset_ops; + + if ((err = rt_reset_controller_register(&reset->parent))) + { + goto _fail; + } + + return RT_EOK; + +_fail: + for (int i = 0; i < CRU_BASE_TYPE_AUDPMU; ++i) + { + if (reset->mmio[i]) + { + rt_iounmap(reset->mmio[i]); + } + } + + rt_free(reset); + + return err; +} + +static const struct rt_ofw_node_id spacemit_reset_ofw_ids[] = +{ + { .compatible = "spacemit,k1x-reset" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver spacemit_reset_driver = +{ + .name = "reset-spacemit", + .ids = spacemit_reset_ofw_ids, + + .probe = spacemit_reset_probe, +}; + +static int spacemit_reset_register(void) +{ + rt_platform_driver_register(&spacemit_reset_driver); + + return 0; +} +INIT_SUBSYS_EXPORT(spacemit_reset_register); diff --git a/bsp/spacemit/dm/rtc/Kconfig b/bsp/spacemit/dm/rtc/Kconfig new file mode 100644 index 000000000000..cb30ec14fa2a --- /dev/null +++ b/bsp/spacemit/dm/rtc/Kconfig @@ -0,0 +1,4 @@ +config RT_RTC_SPACEMIT_PMIC + bool "Spacemit PMIC RTC" + depends on RT_MFD_SPACEMIT_PMIC + default y diff --git a/bsp/spacemit/dm/rtc/SConscript b/bsp/spacemit/dm/rtc/SConscript new file mode 100644 index 000000000000..f8c1b2efb11c --- /dev/null +++ b/bsp/spacemit/dm/rtc/SConscript @@ -0,0 +1,13 @@ +from building import * + +group = [] +src = [] +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../include', cwd + '/../../../../components/drivers/rtc'] + +if GetDepend(['RT_RTC_SPACEMIT_PMIC']): + src += ['rtc-spacemit-pmic.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/spacemit/dm/rtc/rtc-spacemit-pmic.c b/bsp/spacemit/dm/rtc/rtc-spacemit-pmic.c new file mode 100644 index 000000000000..afd55640feac --- /dev/null +++ b/bsp/spacemit/dm/rtc/rtc-spacemit-pmic.c @@ -0,0 +1,592 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#define DBG_TAG "rtc.spacemit-pmic" +#define DBG_LVL DBG_INFO +#include + +#include "rtc_dm.h" + +#define __SPACEMIT_RTC_INTERNAL +#include + +#define SPACEMIT_PMIC_RTC_READ_RETRIES 10 +#define SPACEMIT_PMIC_RTC_WRITE_RETRIES 10 + +struct spacemit_pmic_rtc +{ + struct rt_device parent; + + int irq; + struct spacemit_pmic *pmic; + const struct spacemit_pmic_rtc_regdesc *desc; +}; + +#define raw_to_spacemit_pmic_rtc(raw) rt_container_of(raw, struct spacemit_pmic_rtc, parent) + +static rt_err_t spacemit_pmic_rtc_read_time(struct spacemit_pmic_rtc *pmic_rtc, time_t *sec) +{ + rt_bool_t stable = RT_FALSE; + unsigned int v[6], pre_v[6] = {0}; + struct tm tm = {0}; + struct spacemit_pmic *pmic = pmic_rtc->pmic; + + if ((signed)(pre_v[0] = spacemit_pmic_read(pmic, pmic_rtc->desc->cnt_s.reg)) < 0) + { + LOG_E("Failed to read second: %s", rt_strerror(pre_v[0])); + return -RT_EINVAL; + } + + if ((signed)(pre_v[1] = spacemit_pmic_read(pmic, pmic_rtc->desc->cnt_mi.reg)) < 0) + { + LOG_E("Failed to read minute: %s", rt_strerror(pre_v[1])); + return -RT_EINVAL; + } + + if ((signed)(pre_v[2] = spacemit_pmic_read(pmic, pmic_rtc->desc->cnt_h.reg)) < 0) + { + LOG_E("Failed to read hour: %s", rt_strerror(pre_v[2])); + return -RT_EINVAL; + } + + if ((signed)(pre_v[3] = spacemit_pmic_read(pmic, pmic_rtc->desc->cnt_d.reg)) < 0) + { + LOG_E("Failed to read day: %s", rt_strerror(pre_v[3])); + return -RT_EINVAL; + } + + if ((signed)(pre_v[4] = spacemit_pmic_read(pmic, pmic_rtc->desc->cnt_mo.reg)) < 0) + { + LOG_E("Failed to read month: %s", rt_strerror(pre_v[4])); + return -RT_EINVAL; + } + + if ((signed)(pre_v[5] = spacemit_pmic_read(pmic, pmic_rtc->desc->cnt_y.reg)) < 0) + { + LOG_E("Failed to read year: %s", rt_strerror(pre_v[5])); + return -RT_EINVAL; + } + + for (int retries = 0; retries < SPACEMIT_PMIC_RTC_READ_RETRIES; ++retries) + { + if ((signed)(v[0] = spacemit_pmic_read(pmic, pmic_rtc->desc->cnt_s.reg)) < 0) + { + LOG_E("Failed to read second: %s", rt_strerror(v[0])); + return -RT_EINVAL; + } + + if ((signed)(v[1] = spacemit_pmic_read(pmic, pmic_rtc->desc->cnt_mi.reg)) < 0) + { + LOG_E("Failed to read minute: %s", rt_strerror(v[1])); + return -RT_EINVAL; + } + + if ((signed)(v[2] = spacemit_pmic_read(pmic, pmic_rtc->desc->cnt_h.reg)) < 0) + { + LOG_E("Failed to read hour: %s", rt_strerror(v[2])); + return -RT_EINVAL; + } + + if ((signed)(v[3] = spacemit_pmic_read(pmic, pmic_rtc->desc->cnt_d.reg)) < 0) + { + LOG_E("Failed to read day: %s", rt_strerror(v[3])); + return -RT_EINVAL; + } + + if ((signed)(v[4] = spacemit_pmic_read(pmic, pmic_rtc->desc->cnt_mo.reg)) < 0) + { + LOG_E("Failed to read month: %s", rt_strerror(v[4])); + return -RT_EINVAL; + } + + if ((signed)(v[5] = spacemit_pmic_read(pmic, pmic_rtc->desc->cnt_y.reg)) < 0) + { + LOG_E("Failed to read year: %s", rt_strerror(v[5])); + return -RT_EINVAL; + } + + if ((pre_v[0] == v[0]) && (pre_v[1] == v[1]) && + (pre_v[2] == v[2]) && (pre_v[3] == v[3]) && + (pre_v[4] == v[4]) && (pre_v[5] == v[5])) + { + stable = RT_TRUE; + break; + } + else + { + pre_v[0] = v[0]; + pre_v[1] = v[1]; + pre_v[2] = v[2]; + pre_v[3] = v[3]; + pre_v[4] = v[4]; + pre_v[5] = v[5]; + } + } + + if (!stable) + { + LOG_E("RTC counter did not stabilize"); + return -RT_ETIMEOUT; + } + + tm.tm_sec = v[0] & pmic_rtc->desc->cnt_s.msk; + tm.tm_min = v[1] & pmic_rtc->desc->cnt_mi.msk; + tm.tm_hour = v[2] & pmic_rtc->desc->cnt_h.msk; + tm.tm_mday = (v[3] & pmic_rtc->desc->cnt_d.msk) + 1; + tm.tm_mon = (v[4] & pmic_rtc->desc->cnt_mo.msk); + tm.tm_year = (v[5] & pmic_rtc->desc->cnt_y.msk) + 100; + + *sec = mktime(&tm); + + return RT_EOK; +} + +static rt_err_t spacemit_pmic_rtc_set_time(struct spacemit_pmic_rtc *pmic_rtc, time_t *sec) +{ + rt_err_t err; + rt_bool_t verified = RT_FALSE; + unsigned int v[6]; + struct tm tm_buf, *tm; + union spacemit_pmic_rtc_ctl_desc rtc_ctl; + struct spacemit_pmic *pmic = pmic_rtc->pmic; + + tm = localtime_r(sec, &tm_buf); + + if (!tm) + { + return -RT_EINVAL; + } + + if ((signed)(rtc_ctl.val = spacemit_pmic_read(pmic, pmic_rtc->desc->rtc_ctl.reg)) < 0) + { + LOG_E("Failed to read rtc ctrl: %s", rt_strerror(rtc_ctl.val)); + return -RT_EINVAL; + } + + /* Disbale rtc first */ + rtc_ctl.bits.rtc_en = 0; + + if ((err = spacemit_pmic_update_bits(pmic, pmic_rtc->desc->rtc_ctl.reg, 0xff, rtc_ctl.val))) + { + LOG_E("Failed to set rtc ctrl register: %s", rt_strerror(err)); + return -RT_EINVAL; + } + + for (int retries = 0; retries < SPACEMIT_PMIC_RTC_WRITE_RETRIES; ++retries) + { + if ((err = spacemit_pmic_update_bits(pmic, + pmic_rtc->desc->cnt_s.reg, pmic_rtc->desc->cnt_s.msk, tm->tm_sec))) + { + LOG_E("Failed to update second: %s", rt_strerror(err)); + return -RT_EINVAL; + } + + if ((err = spacemit_pmic_update_bits(pmic, + pmic_rtc->desc->cnt_mi.reg, pmic_rtc->desc->cnt_mi.msk, tm->tm_min))) + { + LOG_E("Failed to update minutes: %s", rt_strerror(err)); + return -RT_EINVAL; + } + + if ((err = spacemit_pmic_update_bits(pmic, + pmic_rtc->desc->cnt_h.reg, pmic_rtc->desc->cnt_h.msk, tm->tm_hour))) + { + LOG_E("Failed to update hour: %s", rt_strerror(err)); + return -RT_EINVAL; + } + + if ((err = spacemit_pmic_update_bits(pmic, + pmic_rtc->desc->cnt_d.reg, pmic_rtc->desc->cnt_d.msk, tm->tm_mday - 1))) + { + LOG_E("Failed to update day: %s", rt_strerror(err)); + return -RT_EINVAL; + } + + if ((err = spacemit_pmic_update_bits(pmic, + pmic_rtc->desc->cnt_mo.reg, pmic_rtc->desc->cnt_mo.msk, tm->tm_mon))) + { + LOG_E("Failed to update month: %s", rt_strerror(err)); + return -RT_EINVAL; + } + + if ((err = spacemit_pmic_update_bits(pmic, + pmic_rtc->desc->cnt_y.reg, pmic_rtc->desc->cnt_y.msk, tm->tm_year - 100))) + { + LOG_E("Failed to update month: %s", rt_strerror(err)); + return -RT_EINVAL; + } + + /* Read again */ + if ((signed)(v[0] = spacemit_pmic_read(pmic, pmic_rtc->desc->cnt_s.reg)) < 0) + { + LOG_E("Failed to read second: %s", rt_strerror(v[0])); + return -RT_EINVAL; + } + v[0] = v[0] & pmic_rtc->desc->cnt_s.msk; + + if ((signed)(v[1] = spacemit_pmic_read(pmic, pmic_rtc->desc->cnt_mi.reg)) < 0) + { + LOG_E("Failed to read minute: %s", rt_strerror(v[1])); + return -RT_EINVAL; + } + v[1] = v[1] & pmic_rtc->desc->cnt_mi.msk; + + if ((signed)(v[2] = spacemit_pmic_read(pmic, pmic_rtc->desc->cnt_h.reg)) < 0) + { + LOG_E("Failed to read hour: %s", rt_strerror(v[2])); + return -RT_EINVAL; + } + v[2] = v[2] & pmic_rtc->desc->cnt_h.msk; + + if ((signed)(v[3] = spacemit_pmic_read(pmic, pmic_rtc->desc->cnt_d.reg)) < 0) + { + LOG_E("Failed to read day: %s", rt_strerror(v[3])); + return -RT_EINVAL; + } + v[3] = v[3] & pmic_rtc->desc->cnt_d.msk; + + if ((signed)(v[4] = spacemit_pmic_read(pmic, pmic_rtc->desc->cnt_mo.reg)) < 0) + { + LOG_E("Failed to read month: %s", rt_strerror(v[4])); + return -RT_EINVAL; + } + v[4] = v[4] & pmic_rtc->desc->cnt_mo.msk; + + if ((signed)(v[5] = spacemit_pmic_read(pmic, pmic_rtc->desc->cnt_y.reg)) < 0) + { + LOG_E("Failed to read year: %s", rt_strerror(v[5])); + return -RT_EINVAL; + } + v[5] = v[5] & pmic_rtc->desc->cnt_y.msk; + + if ((v[0] == (pmic_rtc->desc->cnt_s.msk & tm->tm_sec)) && + (v[1] == (pmic_rtc->desc->cnt_mi.msk & tm->tm_min)) && + (v[2] == (pmic_rtc->desc->cnt_h.msk & tm->tm_hour)) && + ((v[3] + 1) == (pmic_rtc->desc->cnt_d.msk & tm->tm_mday)) && + (v[4] == (pmic_rtc->desc->cnt_mo.msk & tm->tm_mon)) && + (v[5] == (pmic_rtc->desc->cnt_y.msk & (tm->tm_year - 100)))) + { + verified = RT_TRUE; + break; + } + } + + if (!verified) + { + LOG_E("RTC time write verification timed out"); + return -RT_ETIMEOUT; + } + + /* Enable rtc last */ + rtc_ctl.bits.rtc_en = 1; + + if ((err = spacemit_pmic_update_bits(pmic, pmic_rtc->desc->rtc_ctl.reg, 0xff, rtc_ctl.val))) + { + LOG_E("Failed to set rtc ctrl register: %s", rt_strerror(err)); + return -RT_EINVAL; + } + + return RT_EOK; +} + +static rt_err_t spacemit_pmic_rtc_read_alarm(struct spacemit_pmic_rtc *pmic_rtc, + struct rt_rtc_wkalarm *alarm) +{ + unsigned int v[6]; + union spacemit_pmic_rtc_ctl_desc rtc_ctl; + struct spacemit_pmic *pmic = pmic_rtc->pmic; + + if ((signed)(v[0] = spacemit_pmic_read(pmic, pmic_rtc->desc->alarm_s.reg)) < 0) + { + LOG_E("Failed to read alarm second: %s", rt_strerror(v[0])); + return -RT_EINVAL; + } + + if ((signed)(v[1] = spacemit_pmic_read(pmic, pmic_rtc->desc->alarm_mi.reg)) < 0) + { + LOG_E("Failed to read alarm minute: %s", rt_strerror(v[1])); + return -RT_EINVAL; + } + + if ((signed)(v[2] = spacemit_pmic_read(pmic, pmic_rtc->desc->alarm_h.reg)) < 0) + { + LOG_E("Failed to read alarm hour: %s", rt_strerror(v[2])); + return -RT_EINVAL; + } + + if ((signed)(v[3] = spacemit_pmic_read(pmic, pmic_rtc->desc->alarm_d.reg)) < 0) + { + LOG_E("Failed to read alarm day: %s", rt_strerror(v[3])); + return -RT_EINVAL; + } + + if ((signed)(v[4] = spacemit_pmic_read(pmic, pmic_rtc->desc->alarm_mo.reg)) < 0) + { + LOG_E("Failed to read alarm month: %s", rt_strerror(v[4])); + return -RT_EINVAL; + } + + if ((signed)(v[5] = spacemit_pmic_read(pmic, pmic_rtc->desc->alarm_y.reg)) < 0) + { + LOG_E("Failed to read alarm year: %s", rt_strerror(v[5])); + return -RT_EINVAL; + } + + /* 2000:1:1:0:0:0 */ + alarm->tm_sec = v[0] & pmic_rtc->desc->alarm_s.msk; + alarm->tm_min = v[1] & pmic_rtc->desc->alarm_mi.msk; + alarm->tm_hour = v[2] & pmic_rtc->desc->alarm_h.msk; + alarm->tm_mday = (v[3] & pmic_rtc->desc->alarm_d.msk) + 1; + alarm->tm_mon = (v[4] & pmic_rtc->desc->alarm_mo.msk); + alarm->tm_year = (v[5] & pmic_rtc->desc->alarm_y.msk) + 100; + + if ((signed)(rtc_ctl.val = spacemit_pmic_read(pmic, pmic_rtc->desc->rtc_ctl.reg)) < 0) + { + LOG_E("Failed to read alarm second: %s", rt_strerror(rtc_ctl.val)); + return -RT_EINVAL; + } + + alarm->enable = !!rtc_ctl.bits.alarm_en; + + return RT_EOK; +} + +static rt_err_t spacemit_pmic_rtc_set_alarm(struct spacemit_pmic_rtc *pmic_rtc, + struct rt_rtc_wkalarm *alarm) +{ + rt_err_t err; + union spacemit_pmic_rtc_ctl_desc rtc_ctl; + struct spacemit_pmic *pmic = pmic_rtc->pmic; + + /* Disable the alrm function first */ + if ((signed)(rtc_ctl.val = spacemit_pmic_read(pmic, pmic_rtc->desc->rtc_ctl.reg)) < 0) + { + LOG_E("Failed to read rtc ctrl register: %s", rt_strerror(rtc_ctl.val)); + return -RT_EINVAL; + } + + rtc_ctl.bits.alarm_en = 0; + + if ((err = spacemit_pmic_update_bits(pmic, pmic_rtc->desc->rtc_ctl.reg, 0xff, rtc_ctl.val))) + { + LOG_E("Failed to set rtc ctrl register: %s", rt_strerror(err)); + return -RT_EINVAL; + } + + if ((err = spacemit_pmic_update_bits(pmic, + pmic_rtc->desc->alarm_s.reg, pmic_rtc->desc->alarm_s.msk, alarm->tm_sec))) + { + LOG_E("Failed to update alrm second: %s", rt_strerror(err)); + return -RT_EINVAL; + } + + if ((err = spacemit_pmic_update_bits(pmic, + pmic_rtc->desc->alarm_mi.reg, pmic_rtc->desc->alarm_mi.msk, alarm->tm_min))) + { + LOG_E("Failed to update alarm minutes: %s", rt_strerror(err)); + return -RT_EINVAL; + } + + if ((err = spacemit_pmic_update_bits(pmic, + pmic_rtc->desc->alarm_h.reg, pmic_rtc->desc->alarm_h.msk, alarm->tm_hour))) + { + LOG_E("Failed to update alarm hour: %s", rt_strerror(err)); + return -RT_EINVAL; + } + + if ((err = spacemit_pmic_update_bits(pmic, + pmic_rtc->desc->alarm_d.reg, pmic_rtc->desc->alarm_d.msk, alarm->tm_mday - 1))) + { + LOG_E("Failed to update alarm day: %s", rt_strerror(err)); + return -RT_EINVAL; + } + + if ((err = spacemit_pmic_update_bits(pmic, + pmic_rtc->desc->alarm_mo.reg, pmic_rtc->desc->alarm_mo.msk, alarm->tm_mon))) + { + LOG_E("Failed to update alarm month: %s", rt_strerror(err)); + return -RT_EINVAL; + } + + if ((err = spacemit_pmic_update_bits(pmic, + pmic_rtc->desc->alarm_y.reg, pmic_rtc->desc->alarm_y.msk, alarm->tm_year - 100))) + { + LOG_E("Failed to update month: %s", rt_strerror(err)); + return -RT_EINVAL; + } + + if (alarm->enable) + { + rtc_ctl.bits.alarm_en = 1; + + if ((err = spacemit_pmic_update_bits(pmic, pmic_rtc->desc->rtc_ctl.reg, 0xff, rtc_ctl.val))) + { + LOG_E("Failed to set rtc ctrl register: %s", rt_strerror(err)); + return -RT_EINVAL; + } + } + + return RT_EOK; +} + +static rt_err_t spacemit_pmic_rtc_control(rt_device_t dev, int cmd, void *args) +{ + rt_err_t err = RT_EOK; + struct spacemit_pmic_rtc *pmic_rtc = raw_to_spacemit_pmic_rtc(dev); + + if (!args) + { + return -RT_EINVAL; + } + + switch (cmd) + { + case RT_DEVICE_CTRL_RTC_GET_TIME: + err = spacemit_pmic_rtc_read_time(pmic_rtc, args); + break; + + case RT_DEVICE_CTRL_RTC_SET_TIME: + err = spacemit_pmic_rtc_set_time(pmic_rtc, args); + break; + + case RT_DEVICE_CTRL_RTC_GET_TIMEVAL: + err = spacemit_pmic_rtc_read_time(pmic_rtc, (time_t *)&((struct timeval *)args)->tv_sec); + break; + + case RT_DEVICE_CTRL_RTC_SET_TIMEVAL: + err = spacemit_pmic_rtc_set_time(pmic_rtc, (time_t *)&((struct timeval *)args)->tv_sec); + break; + + case RT_DEVICE_CTRL_RTC_GET_ALARM: + err = spacemit_pmic_rtc_read_alarm(pmic_rtc, args); + break; + + case RT_DEVICE_CTRL_RTC_SET_ALARM: + err = spacemit_pmic_rtc_set_alarm(pmic_rtc, args); + break; + + default: + err = -RT_EINVAL; + break; + } + + return err; +} + +#ifdef RT_USING_DEVICE_OPS +const static struct rt_device_ops spacemit_pmic_rtc_ops = +{ + .control = spacemit_pmic_rtc_control, +}; +#endif + +static void spacemit_pmic_rtc_isr(int irq, void *param) +{ + struct spacemit_pmic_rtc *pmic_rtc = param; + + rt_alarm_update(&pmic_rtc->parent, 1); +} + +static rt_err_t spacemit_pmic_rtc_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + const char *dev_name; + struct rt_device *dev = &pdev->parent; + struct spacemit_pmic *pmic = pdev->priv; + union spacemit_pmic_rtc_ctl_desc rtc_ctl; + struct spacemit_pmic_rtc *pmic_rtc = rt_calloc(1, sizeof(*pmic_rtc)); + + if (!pmic_rtc) + { + return -RT_ENOMEM; + } + + pmic_rtc->pmic = pmic; + pmic_rtc->desc = pdev->id->data; + + if ((pmic_rtc->irq = rt_dm_dev_get_irq(dev, 0)) < 0) + { + err = pmic_rtc->irq; + goto _fail; + } + + /* Enable the rtc function */ + if ((signed)(rtc_ctl.val = spacemit_pmic_read(pmic, pmic_rtc->desc->rtc_ctl.reg)) < 0) + { + err = rtc_ctl.val; + goto _fail; + } + + /* Internal 32k clk */ + rtc_ctl.bits.rtc_clk_sel = 1; + /* Enable rtc */ + rtc_ctl.bits.rtc_en = 1; + /* RTC clk out enable */ + rtc_ctl.bits.out_32k_en = 1; + /* Enable external crystal */ + rtc_ctl.bits.crystal_en = 1; + + if ((err = spacemit_pmic_update_bits(pmic, pmic_rtc->desc->rtc_ctl.reg, 0xff, rtc_ctl.val))) + { + goto _fail; + } + + pmic_rtc->parent.type = RT_Device_Class_RTC; +#ifdef RT_USING_DEVICE_OPS + pmic_rtc->parent.ops = &spacemit_pmic_rtc_ops; +#else + pmic_rtc->parent.control = spacemit_pmic_rtc_control; +#endif + + rtc_dev_set_name(&pmic_rtc->parent); + dev_name = rt_dm_dev_get_name(&pmic_rtc->parent); + rt_device_register(&pmic_rtc->parent, dev_name, RT_DEVICE_FLAG_RDWR); + + rt_hw_interrupt_install(pmic_rtc->irq, spacemit_pmic_rtc_isr, pmic_rtc, "rtc-spacemit-pmic"); + rt_hw_interrupt_umask(pmic_rtc->irq); + + dev->user_data = pmic_rtc; + + return RT_EOK; +_fail: + rt_free(pmic_rtc); + + return err; +} + +static rt_err_t spacemit_pmic_rtc_remove(struct rt_platform_device *pdev) +{ + struct spacemit_pmic_rtc *pmic_rtc = pdev->parent.user_data; + + rt_hw_interrupt_mask(pmic_rtc->irq); + rt_pic_detach_irq(pmic_rtc->irq, pmic_rtc); + + rt_device_unregister(&pmic_rtc->parent); + + rt_free(pmic_rtc); + + return RT_EOK; +} + +static const struct rt_ofw_node_id spacemit_pmic_rtc_ofw_ids[] = +{ + { .compatible = "pmic,rtc,spm8821", .data = &spm8821_regdesc }, + { /* sentinel */ } +}; + +static struct rt_platform_driver spacemit_pmic_rtc_driver = +{ + .name = "spacemit-pmic-rtc", + .ids = spacemit_pmic_rtc_ofw_ids, + + .probe = spacemit_pmic_rtc_probe, + .remove = spacemit_pmic_rtc_remove, +}; +RT_PLATFORM_DRIVER_EXPORT(spacemit_pmic_rtc_driver); diff --git a/bsp/spacemit/dm/sdio/Kconfig b/bsp/spacemit/dm/sdio/Kconfig new file mode 100644 index 000000000000..73ed5f66e9a6 --- /dev/null +++ b/bsp/spacemit/dm/sdio/Kconfig @@ -0,0 +1,5 @@ +config RT_SDIO_SDHCI_SPACEMIT_K1X + bool "Spacemit k1x MSHC SDHCI" + depends on RT_USING_OFW + select RT_USING_SDHCI + default n diff --git a/bsp/spacemit/dm/sdio/SConscript b/bsp/spacemit/dm/sdio/SConscript new file mode 100644 index 000000000000..1974720468e0 --- /dev/null +++ b/bsp/spacemit/dm/sdio/SConscript @@ -0,0 +1,12 @@ +from building import * + +cwd = GetCurrentDir() +src = [] +CPPPATH = [cwd + '/../include', cwd + '/../../../../components/drivers/sdio'] + +if GetDepend(['RT_SDIO_SDHCI_SPACEMIT_K1X']): + src += ['sdhci-k1x.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/spacemit/dm/sdio/sdhci-k1x.c b/bsp/spacemit/dm/sdio/sdhci-k1x.c new file mode 100644 index 000000000000..91472cf2f004 --- /dev/null +++ b/bsp/spacemit/dm/sdio/sdhci-k1x.c @@ -0,0 +1,1577 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#include "dev_sdio_dm.h" +#include "dev_sdhci_dm.h" + +#define DBG_TAG "sdhci.k1x" +#define DBG_LVL DBG_INFO +#include + +#define CANDIDATE_WIN_NUM 3 +#define SELECT_DELAY_NUM 9 +#define WINDOW_1ST 0 +#define WINDOW_2ND 1 +#define WINDOW_3RD 2 + +#define RX_TUNING_WINDOW_THRESHOLD 80 +#define RX_TUNING_DLINE_REG 0x09 +#define TX_TUNING_DLINE_REG 0x00 +#define TX_TUNING_DELAYCODE 127 + +#define BOOTPART_NOACC_DEFAULT 0 + +/* SDH registers define */ +#define SDHC_OP_EXT_REG 0x108 +#define OVRRD_CLK_OEN 0x0800 +#define FORCE_CLK_ON 0x1000 + +#define SDHC_LEGACY_CTRL_REG 0x10c +#define GEN_PAD_CLK_ON 0x0040 + +#define SDHC_MMC_CTRL_REG 0x114 +#define MISC_INT_EN 0x0002 +#define MISC_INT 0x0004 +#define ENHANCE_STROBE_EN 0x0100 +#define MMC_HS400 0x0200 +#define MMC_HS200 0x0400 +#define MMC_CARD_MODE 0x1000 + +#define SDHC_TX_CFG_REG 0x11c +#define TX_INT_CLK_SEL 0x40000000 +#define TX_MUX_SEL 0x80000000 + +#define SDHC_PHY_CTRL_REG 0x160 +#define PHY_FUNC_EN 0x0001 +#define PHY_PLL_LOCK 0x0002 +#define HOST_LEGACY_MODE 0x80000000 + +#define SDHC_PHY_FUNC_REG 0x164 +#define PHY_TEST_EN 0x0080 +#define HS200_USE_RFIFO 0x8000 + +#define SDHC_PHY_DLLCFG 0x168 +#define DLL_PREDLY_NUM 0x04 +#define DLL_FULLDLY_RANGE 0x10 +#define DLL_VREG_CTRL 0x40 +#define DLL_ENABLE 0x80000000 +#define DLL_REFRESH_SWEN_SHIFT 0x1c +#define DLL_REFRESH_SW_SHIFT 0x1d + +#define SDHC_PHY_DLLCFG1 0x16c +#define DLL_REG2_CTRL 0x0c +#define DLL_REG3_CTRL_MASK 0xff +#define DLL_REG3_CTRL_SHIFT 0x10 +#define DLL_REG2_CTRL_MASK 0xff +#define DLL_REG2_CTRL_SHIFT 0x08 +#define DLL_REG1_CTRL 0x92 +#define DLL_REG1_CTRL_MASK 0xff +#define DLL_REG1_CTRL_SHIFT 0x00 + +#define SDHC_PHY_DLLSTS 0x170 +#define DLL_LOCK_STATE 0x01 + +#define SDHC_PHY_DLLSTS1 0x174 +#define DLL_MASTER_DELAY_MASK 0xff +#define DLL_MASTER_DELAY_SHIFT 0x10 + +#define SDHC_PHY_PADCFG_REG 0x178 +#define RX_BIAS_CTRL_SHIFT 0x5 +#define PHY_DRIVE_SEL_SHIFT 0x0 +#define PHY_DRIVE_SEL_MASK 0x7 +#define PHY_DRIVE_SEL_DEFAULT 0x4 + +#define RPM_DELAY 50 +#define MAX_74CLK_WAIT_COUNT 100 + +#define MMC1_IO_V18EN 0x04 +#define AKEY_ASFAR 0xbaba +#define AKEY_ASSAR 0xeb10 + +/* Spacemit private quirk, shared with the DT binding. */ +#define RT_SDHCI_QUIRK2_SET_AIB_MMC RT_BIT(27) + +#define SDHC_RX_CFG_REG 0x118 +#define RX_SDCLK_SEL0_MASK 0x03 +#define RX_SDCLK_SEL0_SHIFT 0x00 +#define RX_SDCLK_SEL0 0x02 +#define RX_SDCLK_SEL1_MASK 0x03 +#define RX_SDCLK_SEL1_SHIFT 0x02 +#define RX_SDCLK_SEL1 0x01 + +#define SDHC_DLINE_CTRL_REG 0x130 +#define DLINE_PU 0x01 +#define RX_DLINE_CODE_MASK 0xff +#define RX_DLINE_CODE_SHIFT 0x10 +#define TX_DLINE_CODE_MASK 0xff +#define TX_DLINE_CODE_SHIFT 0x18 + +#define SDHC_DLINE_CFG_REG 0x134 +#define RX_DLINE_REG_MASK 0xff +#define RX_DLINE_REG_SHIFT 0x00 +#define RX_DLINE_GAIN_MASK 0x1 +#define RX_DLINE_GAIN_SHIFT 0x8 +#define RX_DLINE_GAIN 0x1 +#define TX_DLINE_REG_MASK 0xff +#define TX_DLINE_REG_SHIFT 0x10 + +#define SDHC_RX_TUNE_DELAY_MIN 0x0 +#define SDHC_RX_TUNE_DELAY_MAX 0xff +#define SDHC_RX_TUNE_DELAY_STEP 0x1 + +#define MMC_CAP2_QUIRK_BREAK_SDR104 RT_BIT(30) + +enum window_type +{ + LEFT_WINDOW = 0, + MIDDLE_WINDOW = 1, + RIGHT_WINDOW = 2, +}; + +struct tuning_window +{ + rt_uint8_t type; + rt_uint8_t min_delay; + rt_uint8_t max_delay; +}; + +struct rx_tuning +{ + rt_uint8_t rx_dline_reg; + rt_uint8_t select_delay_num; + rt_uint8_t current_delay_index; + /* 0: biggest window, 1: bigger, 2: small */ + struct tuning_window windows[CANDIDATE_WIN_NUM]; + rt_uint8_t select_delay[SELECT_DELAY_NUM]; + + rt_uint32_t card_cid[4]; + rt_uint8_t window_limit; + rt_uint8_t tuning_fail; + rt_uint8_t window_type; +}; + +struct k1x_sdhci_data +{ + rt_uint32_t host_freq; + rt_uint32_t flags; + rt_uint32_t host_caps; + rt_uint32_t host_caps2; + rt_uint32_t host_caps_disable; + rt_uint32_t host_caps2_disable; + rt_uint32_t quirks; + rt_uint32_t quirks2; + rt_uint32_t pm_caps; + + rt_uint32_t aib_mmc1_io_reg; + rt_uint32_t apbc_asfar_reg; + rt_uint32_t apbc_assar_reg; + + rt_uint8_t tx_dline_reg; + rt_uint8_t tx_delaycode; + rt_uint8_t tx_delaycode_cnt; + rt_uint8_t tx_delaycode_array[2]; + rt_uint8_t phy_driver_sel; + struct rx_tuning rxtuning; + rt_uint8_t need_reset_dllcfg1; + rt_uint32_t prev_dllcfg1; + rt_uint32_t curr_dllcfg1; + rt_uint32_t new_dllcfg1; + rt_uint8_t dllcfg1_odd_reset; + rt_uint32_t rx_tuning_freq; +}; + +struct k1x_sdhci +{ + struct rt_sdhci_host *host; + + struct rt_clk *clk_core; + struct rt_clk *clk_io; + struct rt_clk *clk_aib; + struct rt_reset_control *rstc; + unsigned char power_mode; + + rt_bool_t pinctrl; + struct k1x_sdhci_data pdata; +}; + +static const rt_uint32_t tuning_patten4[16] = +{ + 0x00ff0fff, 0xccc3ccff, 0xffcc3cc3, 0xeffefffe, + 0xddffdfff, 0xfbfffbff, 0xff7fffbf, 0xefbdf777, + 0xf0fff0ff, 0x3cccfc0f, 0xcfcc33cc, 0xeeffefff, + 0xfdfffdff, 0xffbfffdf, 0xfff7ffbb, 0xde7b7ff7, +}; + +static const rt_uint32_t tuning_patten8[32] = +{ + 0xff00ffff, 0x0000ffff, 0xccccffff, 0xcccc33cc, + 0xcc3333cc, 0xffffcccc, 0xffffeeff, 0xffeeeeff, + 0xffddffff, 0xddddffff, 0xbbffffff, 0xbbffffff, + 0xffffffbb, 0xffffff77, 0x77ff7777, 0xffeeddbb, + 0x00ffffff, 0x00ffffff, 0xccffff00, 0xcc33cccc, + 0x3333cccc, 0xffcccccc, 0xffeeffff, 0xeeeeffff, + 0xddffffff, 0xddffffff, 0xffffffdd, 0xffffffbb, + 0xffffbbbb, 0xffff77ff, 0xff7777ff, 0xeeddbb77, +}; + +static void k1x_sdhci_set_clk_gate(struct rt_sdhci_host *host, rt_bool_t auto_gate) +{ + unsigned int reg; + + reg = rt_sdhci_readl(host, SDHC_OP_EXT_REG); + if (auto_gate) + { + reg &= ~(OVRRD_CLK_OEN | FORCE_CLK_ON); + } + else + { + reg |= OVRRD_CLK_OEN | FORCE_CLK_ON; + } + rt_sdhci_writel(host, reg, SDHC_OP_EXT_REG); +} + +static rt_bool_t k1x_sdhci_card_busy(struct rt_mmc_host *mmc) +{ + rt_bool_t res; + rt_uint32_t cmd, present_state; + struct rt_sdhci_host *host = rt_mmc_priv(mmc); + + /* Check whether DAT[0] is 0 */ + present_state = rt_sdhci_readl(host, RT_SDHCI_PRESENT_STATE); + res = !(present_state & RT_SDHCI_DATA_0_LVL_MASK); + + if (host->mmc->caps2 & MMC_CAP2_NO_MMC) + { + cmd = RT_SDHCI_GET_CMD(rt_sdhci_readw(host, RT_SDHCI_COMMAND)); + if (cmd == VOLTAGE_SWITCH && host->mmc->ios.signal_voltage == MMC_SIGNAL_VOLTAGE_180) + { + /* Recover the auto clock */ + k1x_sdhci_set_clk_gate(host, RT_TRUE); + } + } + + return res; +} + +static void k1x_sdhci_enable_sdio_irq_nolock(struct rt_sdhci_host *host, rt_bool_t enable) +{ + if (!(host->flags & RT_SDHCI_DEVICE_DEAD)) + { + if (enable) + { + host->ier |= RT_SDHCI_INT_CARD_INT; + } + else + { + host->ier &= ~RT_SDHCI_INT_CARD_INT; + } + + rt_sdhci_writel(host, host->ier, RT_SDHCI_INT_ENABLE); + rt_sdhci_writel(host, host->ier, RT_SDHCI_SIGNAL_ENABLE); + } +} + +static void k1x_sdhci_enable_sdio_irq(struct rt_mmc_host *mmc, rt_bool_t enable) +{ + rt_ubase_t level; + struct rt_sdhci_host *host = rt_mmc_priv(mmc); + + level = rt_spin_lock_irqsave(&host->lock); + k1x_sdhci_enable_sdio_irq_nolock(host, enable); + rt_spin_unlock_irqrestore(&host->lock, level); +} + +static void k1x_enable_sdio_irq(struct rt_mmc_host *mmc, int enable) +{ + rt_ubase_t level; + struct rt_sdhci_host *host = rt_mmc_priv(mmc); + + k1x_sdhci_enable_sdio_irq(mmc, enable); + + /* Avoid to read the SDIO_CCCR_INTx */ + level = rt_spin_lock_irqsave(&host->lock); + mmc->sdio_irq_pending = RT_TRUE; + rt_spin_unlock_irqrestore(&host->lock, level); +} + +static void k1x_sdhci_set_clock(struct rt_sdhci_host *host, unsigned int clock) +{ + rt_uint32_t reg, cmd; + struct rt_sdhci_pltfm_host *pltfm_host = rt_sdhci_priv(host); + struct k1x_sdhci *k1x = rt_sdhci_pltfm_priv(pltfm_host); + struct rt_mmc_host *mmc = host->mmc; + + /* + * According to the SDHC_TX_CFG_REG(0x11c), + * set TX_INT_CLK_SEL to gurantee the hold time + * at default speed mode or HS/SDR12/SDR25/SDR50 mode. + */ + reg = rt_sdhci_readl(host, SDHC_TX_CFG_REG); + if (mmc->ios.timing == MMCSD_TIMING_LEGACY || + mmc->ios.timing == MMCSD_TIMING_SD_HS || + mmc->ios.timing == MMCSD_TIMING_UHS_SDR12 || + mmc->ios.timing == MMCSD_TIMING_UHS_SDR25 || + mmc->ios.timing == MMCSD_TIMING_UHS_SDR50 || + mmc->ios.timing == MMCSD_TIMING_MMC_HS) + { + reg |= TX_INT_CLK_SEL; + } + else + { + reg &= ~TX_INT_CLK_SEL; + } + rt_sdhci_writel(host, reg, SDHC_TX_CFG_REG); + + /* set pinctrl state */ + if (k1x->pinctrl) + { + if (clock >= 200000000) + { + rt_pin_ctrl_confs_apply_by_name(mmc->parent, "fast"); + } + else if (clock == 0 || host->mmc->ios.bus_width < MMC_BUS_WIDTH_4) + { + rt_pin_ctrl_confs_apply_by_name(mmc->parent, "debug"); + } + else + { + rt_pin_ctrl_confs_apply_by_name(mmc->parent, "default"); + } + } + + rt_sdhci_set_clock(host, clock); + + if (host->mmc->caps2 & MMC_CAP2_NO_MMC) + { + /* + * According to the SD spec, during a signal voltage level switch, + * the clock must be closed for 5 ms. + * then, the host starts providing clk at 1.8 and the host checks whether + * DAT[3:0] is high after 1ms clk. + * + * For the above goal, temporarily disable the auto clk + * and keep clk always on for 1ms. + */ + cmd = RT_SDHCI_GET_CMD(rt_sdhci_readw(host, RT_SDHCI_COMMAND)); + + if (cmd == VOLTAGE_SWITCH && host->mmc->ios.signal_voltage == MMC_SIGNAL_VOLTAGE_180) + { + /* Disable auto clock */ + k1x_sdhci_set_clk_gate(host, 0); + } + } +}; + +static void k1x_sdhci_phy_dll_init(struct rt_sdhci_host *host) +{ + rt_uint32_t reg; + + /* Config dll_reg1 & dll_reg2 */ + reg = rt_sdhci_readl(host, SDHC_PHY_DLLCFG); + reg |= DLL_PREDLY_NUM | DLL_FULLDLY_RANGE | DLL_VREG_CTRL; + rt_sdhci_writel(host, reg, SDHC_PHY_DLLCFG); + + reg = rt_sdhci_readl(host, SDHC_PHY_DLLCFG1); + reg |= DLL_REG1_CTRL & DLL_REG1_CTRL_MASK; + rt_sdhci_writel(host, reg, SDHC_PHY_DLLCFG1); + + /* Dll enable */ + reg = rt_sdhci_readl(host, SDHC_PHY_DLLCFG); + reg |= DLL_ENABLE; + rt_sdhci_writel(host, reg, SDHC_PHY_DLLCFG); + + /* Wait dll lock */ + for (int i = 0; i < 100; ++i) + { + if (rt_sdhci_readl(host, SDHC_PHY_DLLSTS) & DLL_LOCK_STATE) + { + break; + } + + rt_hw_us_delay(10); + } +} + +static void k1x_sdhci_hs400_enhanced_strobe(struct rt_mmc_host *mmc, struct rt_mmcsd_io_cfg *ios) +{ + rt_uint32_t reg; + struct rt_sdhci_host *host = rt_mmc_priv(mmc); + + reg = rt_sdhci_readl(host, SDHC_MMC_CTRL_REG); + if (ios->enhanced_strobe) + { + reg |= ENHANCE_STROBE_EN; + } + else + { + reg &= ~ENHANCE_STROBE_EN; + } + rt_sdhci_writel(host, reg, SDHC_MMC_CTRL_REG); + + if (ios->enhanced_strobe) + { + k1x_sdhci_phy_dll_init(host); + } +} + +static int k1x_sdhci_start_signal_voltage_switch(struct rt_mmc_host *mmc, struct rt_mmcsd_io_cfg *ios) +{ + return rt_sdhci_start_signal_voltage_switch(mmc, ios); +} + +static void k1x_sw_rx_tuning_prepare(struct rt_sdhci_host *host, rt_uint8_t dline_reg) +{ + rt_uint32_t reg; + struct rt_mmc_host *mmc = host->mmc; + struct rt_mmcsd_io_cfg ios = mmc->ios; + + reg = rt_sdhci_readl(host, SDHC_DLINE_CFG_REG); + reg &= ~(RX_DLINE_REG_MASK << RX_DLINE_REG_SHIFT); + reg |= dline_reg << RX_DLINE_REG_SHIFT; + reg &= ~(RX_DLINE_GAIN_MASK << RX_DLINE_GAIN_SHIFT); + if (ios.timing == MMC_TIMING_UHS_SDR50 && (reg & 0x40)) + { + reg |= RX_DLINE_GAIN << RX_DLINE_GAIN_SHIFT; + } + rt_sdhci_writel(host, reg, SDHC_DLINE_CFG_REG); + + reg = rt_sdhci_readl(host, SDHC_DLINE_CTRL_REG); + reg |= DLINE_PU; + rt_sdhci_writel(host, reg, SDHC_DLINE_CTRL_REG); + rt_hw_us_delay(5); + + reg = rt_sdhci_readl(host, SDHC_RX_CFG_REG); + reg &= ~(RX_SDCLK_SEL1_MASK << RX_SDCLK_SEL1_SHIFT); + reg |= RX_SDCLK_SEL1 << RX_SDCLK_SEL1_SHIFT; + rt_sdhci_writel(host, reg, SDHC_RX_CFG_REG); + + if (mmc->ios.timing == MMC_TIMING_MMC_HS200) + { + reg = rt_sdhci_readl(host, SDHC_PHY_FUNC_REG); + reg |= HS200_USE_RFIFO; + rt_sdhci_writel(host, reg, SDHC_PHY_FUNC_REG); + } +} + +static void k1x_sw_rx_set_delaycode(struct rt_sdhci_host *host, rt_uint32_t delay) +{ + rt_uint32_t reg; + + reg = rt_sdhci_readl(host, SDHC_DLINE_CTRL_REG); + reg &= ~(RX_DLINE_CODE_MASK << RX_DLINE_CODE_SHIFT); + reg |= (delay & RX_DLINE_CODE_MASK) << RX_DLINE_CODE_SHIFT; + rt_sdhci_writel(host, reg, SDHC_DLINE_CTRL_REG); +} + +static void k1x_sw_tx_tuning_prepare(struct rt_sdhci_host *host) +{ + rt_uint32_t reg; + + /* Set TX_MUX_SEL */ + reg = rt_sdhci_readl(host, SDHC_TX_CFG_REG); + reg |= TX_MUX_SEL; + rt_sdhci_writel(host, reg, SDHC_TX_CFG_REG); + + reg = rt_sdhci_readl(host, SDHC_DLINE_CTRL_REG); + reg |= DLINE_PU; + rt_sdhci_writel(host, reg, SDHC_DLINE_CTRL_REG); + + rt_hw_us_delay(5); +} + +static void k1x_sw_tx_set_dlinereg(struct rt_sdhci_host *host, rt_uint8_t dline_reg) +{ + rt_uint32_t reg; + + reg = rt_sdhci_readl(host, SDHC_DLINE_CFG_REG); + reg &= ~(TX_DLINE_REG_MASK << TX_DLINE_REG_SHIFT); + reg |= dline_reg << TX_DLINE_REG_SHIFT; + rt_sdhci_writel(host, reg, SDHC_DLINE_CFG_REG); +} + +static void k1x_sw_tx_set_delaycode(struct rt_sdhci_host *host, rt_uint32_t delay) +{ + rt_uint32_t reg; + + reg = rt_sdhci_readl(host, SDHC_DLINE_CTRL_REG); + reg &= ~(TX_DLINE_CODE_MASK << TX_DLINE_CODE_SHIFT); + reg |= (delay & TX_DLINE_CODE_MASK) << TX_DLINE_CODE_SHIFT; + rt_sdhci_writel(host, reg, SDHC_DLINE_CTRL_REG); +} + +static void k1x_sdhci_clear_set_irqs(struct rt_sdhci_host *host, rt_uint32_t clr, rt_uint32_t set) +{ + rt_uint32_t ier; + + ier = rt_sdhci_readl(host, RT_SDHCI_INT_ENABLE); + ier &= ~clr; + ier |= set; + rt_sdhci_writel(host, ier, RT_SDHCI_INT_ENABLE); + rt_sdhci_writel(host, ier, RT_SDHCI_SIGNAL_ENABLE); +} + +static int k1x_tuning_patten_check(struct rt_sdhci_host *host, int point) +{ + int patten_len, err = 0; + rt_uint32_t read_patten, *tuning_patten; + + if (host->mmc->ios.bus_width == MMC_BUS_WIDTH_8) + { + tuning_patten = (rt_uint32_t *)tuning_patten8; + patten_len = RT_ARRAY_SIZE(tuning_patten8); + } + else + { + tuning_patten = (rt_uint32_t *)tuning_patten4; + patten_len = RT_ARRAY_SIZE(tuning_patten4); + } + + for (int i = 0; i < patten_len; ++i) + { + read_patten = rt_sdhci_readl(host, RT_SDHCI_BUFFER); + if (read_patten != tuning_patten[i]) + { + ++err; + } + } + + return err; +} + +static int k1x_send_tuning_cmd(struct rt_sdhci_host *host, rt_uint32_t opcode, + int point, rt_ubase_t level) +{ + int err = 0; + + rt_spin_unlock_irqrestore(&host->lock, level); + + rt_sdhci_send_tuning(host, opcode); + + level = rt_spin_lock_irqsave(&host->lock); + + if (!host->tuning_done) + { + LOG_E("Timeout waiting for Buffer Read Ready interrupt " + "during tuning procedure, resetting CMD and DATA"); + rt_sdhci_reset(host, RT_SDHCI_RESET_CMD | RT_SDHCI_RESET_DATA); + } + else + { + err = k1x_tuning_patten_check(host, point); + } + + host->tuning_done = 0; + + return err; +} + +static int k1x_sw_rx_select_window(struct rt_sdhci_host *host, rt_uint32_t opcode) +{ + int err = 0, min, max; + rt_uint16_t ctrl; + rt_uint32_t ier; + rt_ubase_t level = 0; + struct tuning_window tmp; + struct rt_mmc_host *mmc = host->mmc; + struct rt_sdhci_pltfm_host *pltfm_host = rt_sdhci_priv(host); + struct k1x_sdhci *k1x = rt_sdhci_pltfm_priv(pltfm_host); + struct k1x_sdhci_data *pdata = &k1x->pdata; + struct rx_tuning *rxtuning = &pdata->rxtuning; + + /* Change to pio mode during the tuning stage */ + level = rt_spin_lock_irqsave(&host->lock); + + ier = rt_sdhci_readl(host, RT_SDHCI_INT_ENABLE); + k1x_sdhci_clear_set_irqs(host, ier, RT_SDHCI_INT_DATA_AVAIL); + + min = SDHC_RX_TUNE_DELAY_MIN; + do { + /* Find the mininum delay first which can pass tuning */ + while (min < SDHC_RX_TUNE_DELAY_MAX) + { + k1x_sw_rx_set_delaycode(host, min); + + if (!mmc->ops->get_cd(mmc)) + { + rt_spin_unlock_irqrestore(&host->lock, level); + return -RT_EIO; + } + + err = k1x_send_tuning_cmd(host, opcode, min, level); + + if (err == -RT_EIO) + { + rt_spin_unlock_irqrestore(&host->lock, level); + return -RT_EIO; + } + + if (!err) + { + break; + } + + ctrl = rt_sdhci_readw(host, RT_SDHCI_HOST_CONTROL2); + ctrl &= ~(RT_SDHCI_CTRL_TUNED_CLK | RT_SDHCI_CTRL_EXEC_TUNING); + rt_sdhci_writew(host, ctrl, RT_SDHCI_HOST_CONTROL2); + min += SDHC_RX_TUNE_DELAY_STEP; + } + + /* find the maxinum delay which can not pass tuning */ + max = min + SDHC_RX_TUNE_DELAY_STEP; + + while (max < SDHC_RX_TUNE_DELAY_MAX) + { + k1x_sw_rx_set_delaycode(host, max); + if (!mmc->ops->get_cd(mmc)) + { + rt_spin_unlock_irqrestore(&host->lock, level); + return -RT_EIO; + } + + if ((err = k1x_send_tuning_cmd(host, opcode, max, level))) + { + ctrl = rt_sdhci_readw(host, RT_SDHCI_HOST_CONTROL2); + ctrl &= ~(RT_SDHCI_CTRL_TUNED_CLK | RT_SDHCI_CTRL_EXEC_TUNING); + rt_sdhci_writew(host, ctrl, RT_SDHCI_HOST_CONTROL2); + + if (err == -RT_EIO) + { + rt_spin_unlock_irqrestore(&host->lock, level); + return -RT_EIO; + } + + break; + } + max += SDHC_RX_TUNE_DELAY_STEP; + } + + /* Store the top 3 window */ + if ((max - min) >= rxtuning->window_limit) + { + tmp.max_delay = max; + tmp.min_delay = min; + tmp.type = pdata->rxtuning.window_type; + for (int i = 0; i < CANDIDATE_WIN_NUM; i++) + { + int len = rxtuning->windows[i].max_delay - rxtuning->windows[i].min_delay; + + if ((tmp.max_delay - tmp.min_delay) > len) + { + for (int j = CANDIDATE_WIN_NUM - 1; j > i; j--) + { + rxtuning->windows[j] = rxtuning->windows[j-1]; + } + + rxtuning->windows[i] = tmp; + break; + } + } + } + + min = max + SDHC_RX_TUNE_DELAY_STEP; + } while (min < SDHC_RX_TUNE_DELAY_MAX); + + k1x_sdhci_clear_set_irqs(host, RT_SDHCI_INT_DATA_AVAIL, ier); + rt_spin_unlock_irqrestore(&host->lock, level); + + return RT_EOK; +} + +static int k1x_sw_rx_select_delay(struct rt_sdhci_host *host) +{ + int win_len, min, max, mid; + struct tuning_window *window; + struct rt_sdhci_pltfm_host *pltfm_host = rt_sdhci_priv(host); + struct k1x_sdhci *k1x = rt_sdhci_pltfm_priv(pltfm_host); + struct k1x_sdhci_data *pdata = &k1x->pdata; + struct rx_tuning *tuning = &pdata->rxtuning; + + for (int i = 0; i < CANDIDATE_WIN_NUM; ++i) + { + window = &tuning->windows[i]; + min = window->min_delay; + max = window->max_delay; + mid = (min + max - 1) / 2; + win_len = max - min; + + if (win_len < tuning->window_limit) + { + continue; + } + + if (window->type == LEFT_WINDOW) + { + tuning->select_delay[tuning->select_delay_num++] = min + win_len / 4; + tuning->select_delay[tuning->select_delay_num++] = min + win_len / 3; + } + else if (window->type == RIGHT_WINDOW) + { + tuning->select_delay[tuning->select_delay_num++] = max - win_len / 4; + tuning->select_delay[tuning->select_delay_num++] = max - win_len / 3; + } + else + { + tuning->select_delay[tuning->select_delay_num++] = mid; + tuning->select_delay[tuning->select_delay_num++] = mid + win_len / 4; + tuning->select_delay[tuning->select_delay_num++] = mid - win_len / 4; + } + } + + return tuning->select_delay_num; +} + +static unsigned int k1x_sdhci_clk_get_max_clock(struct rt_sdhci_host *host) +{ + struct rt_sdhci_pltfm_host *pltfm_host = rt_sdhci_priv(host); + + return rt_clk_get_rate(pltfm_host->clk); +} + +static unsigned int k1x_get_max_timeout_count(struct rt_sdhci_host *host) +{ + /* + * The default sdhci code use the 1 << 27 as the max timeout counter + * to calculate the max_busy_timeout. + * aquilac sdhci support 1 << 29 as the timeout counter. + */ + return 1 << 29; +} + +static void k1x_sdhci_reset(struct rt_sdhci_host *host, rt_uint8_t mask) +{ + rt_uint32_t reg; + struct rt_sdhci_pltfm_host *pltfm_host = rt_sdhci_priv(host); + struct k1x_sdhci *k1x = rt_sdhci_pltfm_priv(pltfm_host); + struct k1x_sdhci_data *pdata = &k1x->pdata; + + rt_sdhci_reset(host, mask); + + if (mask != RT_SDHCI_RESET_ALL) + { + return; + } + + reg = rt_sdhci_readl(host, SDHC_PHY_CTRL_REG); + reg |= (PHY_FUNC_EN | PHY_PLL_LOCK); + rt_sdhci_writel(host, reg, SDHC_PHY_CTRL_REG); + + reg = rt_sdhci_readl(host, SDHC_PHY_PADCFG_REG); + reg |= (1 << RX_BIAS_CTRL_SHIFT); + + reg &= ~(PHY_DRIVE_SEL_MASK); + reg |= (pdata->phy_driver_sel & PHY_DRIVE_SEL_MASK) << PHY_DRIVE_SEL_SHIFT; + rt_sdhci_writel(host, reg, SDHC_PHY_PADCFG_REG); + + /* For EMMC */ + if (!(host->mmc->caps2 & MMC_CAP2_NO_MMC)) + { + /* MMC card mode */ + reg = rt_sdhci_readl(host, SDHC_MMC_CTRL_REG); + reg |= MMC_CARD_MODE; + rt_sdhci_writel(host, reg, SDHC_MMC_CTRL_REG); + } +} + +static void k1x_sdhci_set_uhs_signaling(struct rt_sdhci_host *host, unsigned timing) +{ + rt_uint16_t reg; + + if (timing == MMC_TIMING_MMC_HS200 || timing == MMC_TIMING_MMC_HS400) + { + reg = rt_sdhci_readw(host, SDHC_MMC_CTRL_REG); + reg |= (timing == MMC_TIMING_MMC_HS200) ? MMC_HS200 : MMC_HS400; + rt_sdhci_writew(host, reg, SDHC_MMC_CTRL_REG); + } + + rt_sdhci_set_uhs(host, timing); + + if (!(host->mmc->caps2 & MMC_CAP2_NO_SDIO)) + { + reg = rt_sdhci_readw(host, RT_SDHCI_HOST_CONTROL2); + rt_sdhci_writew(host, reg | RT_SDHCI_CTRL_VDD_180, RT_SDHCI_HOST_CONTROL2); + } +} + +static int k1x_sdhci_execute_sw_tuning(struct rt_sdhci_host *host, rt_uint32_t opcode) +{ + struct rt_mmc_host *mmc = host->mmc; + struct rt_mmcsd_io_cfg ios = mmc->ios; + struct rt_sdhci_pltfm_host *pltfm_host = rt_sdhci_priv(host); + struct k1x_sdhci *k1x = rt_sdhci_pltfm_priv(pltfm_host); + struct k1x_sdhci_data *pdata = &k1x->pdata; + struct rx_tuning *rxtuning = &pdata->rxtuning; + + /* + * Tuning is required for SDR50/SDR104, HS200/HS400 cards and + * if clock frequency is greater than 100MHz in these modes. + */ + if (host->clock < 100 * 1000 * 1000 || + !((ios.timing == MMC_TIMING_MMC_HS200) || + (ios.timing == MMC_TIMING_UHS_SDR50) || + (ios.timing == MMC_TIMING_UHS_SDR104))) + { + return 0; + } + + if (!(mmc->caps2 & MMC_CAP2_NO_SD) && !mmc->ops->get_cd(mmc)) + { + return 0; + } + + /* TX tuning config */ + if (host->mmc->caps2 & MMC_CAP2_NO_MMC) + { + k1x_sw_tx_set_dlinereg(host, pdata->tx_dline_reg); + k1x_sw_tx_set_delaycode(host, pdata->tx_delaycode); + k1x_sw_tx_tuning_prepare(host); + } + + rxtuning->select_delay_num = 0; + rxtuning->current_delay_index = 0; + rt_memset(rxtuning->windows, 0, sizeof(rxtuning->windows)); + rt_memset(rxtuning->select_delay, 0xFF, sizeof(rxtuning->select_delay)); + rt_memset(rxtuning->card_cid, 0, sizeof(rxtuning->card_cid)); + + /* Get pass window and caculate the select_delay */ + k1x_sw_rx_tuning_prepare(host, rxtuning->rx_dline_reg); + + if (k1x_sw_rx_select_window(host, opcode)) + { + rxtuning->tuning_fail = 1; + return -RT_EIO; + } + + if (!k1x_sw_rx_select_delay(host)) + { + rxtuning->tuning_fail = 1; + return -RT_EIO; + } + + /* Set the delay code and store card cid */ + k1x_sw_rx_set_delaycode(host, rxtuning->select_delay[0]); + rxtuning->tuning_fail = 0; + + return 0; +} + +static rt_uint32_t k1x_handle_interrupt(struct rt_sdhci_host *host, rt_uint32_t intmask) +{ + /* Handle sdio RT_SDHCI_INT_CARD_INT */ + if ((intmask & RT_SDHCI_INT_CARD_INT) && (host->ier & RT_SDHCI_INT_CARD_INT)) + { + if (!(host->flags & RT_SDHCI_DEVICE_DEAD)) + { + host->ier &= ~RT_SDHCI_INT_CARD_INT; + rt_sdhci_writel(host, host->ier, RT_SDHCI_INT_ENABLE); + rt_sdhci_writel(host, host->ier, RT_SDHCI_SIGNAL_ENABLE); + } + + /* Wakeup ksdioirqd thread */ + host->mmc->sdio_irq_pending = RT_TRUE; + if (host->mmc->rthost.sdio_irq_thread) + { + rt_thread_resume(host->mmc->rthost.sdio_irq_thread); + } + } + + /* Handle error interrupts */ + if (intmask & RT_SDHCI_INT_ERROR) + { + if (intmask & (RT_SDHCI_INT_CRC | RT_SDHCI_INT_DATA_CRC | RT_SDHCI_INT_DATA_END_BIT | RT_SDHCI_INT_AUTO_CMD_ERR)) + { + /* Handle crc error for sd device */ + if (host->mmc->caps2 & MMC_CAP2_NO_MMC) + { + host->mmc->caps2 |= MMC_CAP2_QUIRK_BREAK_SDR104; + } + } + } + + return intmask; +} + +static void k1x_set_aib_mmc1_io(struct rt_sdhci_host *host, int signal_voltage) +{ + void *aib_mmc1_io = RT_NULL; + void *apbc_asfar = RT_NULL; + void *apbc_assar = RT_NULL; + rt_uint32_t reg; + struct rt_sdhci_pltfm_host *pltfm_host = rt_sdhci_priv(host); + struct k1x_sdhci *k1x = rt_sdhci_pltfm_priv(pltfm_host); + struct k1x_sdhci_data *pdata = &k1x->pdata; + + if (!pdata->aib_mmc1_io_reg || !pdata->apbc_asfar_reg || + !pdata->apbc_assar_reg) + { + return; + } + + aib_mmc1_io = rt_ioremap((void *)(rt_ubase_t)pdata->aib_mmc1_io_reg, 4); + apbc_asfar = rt_ioremap((void *)(rt_ubase_t)pdata->apbc_asfar_reg, 4); + apbc_assar = rt_ioremap((void *)(rt_ubase_t)pdata->apbc_assar_reg, 4); + if (!aib_mmc1_io || !apbc_asfar || !apbc_assar) + { + LOG_E("Map AIB voltage control registers failed"); + goto _unmap; + } + + HWREG32(apbc_asfar) = AKEY_ASFAR; + HWREG32(apbc_assar) = AKEY_ASSAR; + reg = HWREG32(aib_mmc1_io); + + if (signal_voltage == MMC_SIGNAL_VOLTAGE_180) + { + reg |= MMC1_IO_V18EN; + } + else + { + reg &= ~MMC1_IO_V18EN; + } + + HWREG32(apbc_asfar) = AKEY_ASFAR; + HWREG32(apbc_assar) = AKEY_ASSAR; + HWREG32(aib_mmc1_io) = reg; + rt_hw_dsb(); + +_unmap: + if (apbc_assar) + { + rt_iounmap(apbc_assar); + } + if (apbc_asfar) + { + rt_iounmap(apbc_asfar); + } + if (aib_mmc1_io) + { + rt_iounmap(aib_mmc1_io); + } +} + +static void k1x_sdhci_voltage_switch(struct rt_sdhci_host *host) +{ + if (host->quirks2 & RT_SDHCI_QUIRK2_SET_AIB_MMC) + { + k1x_set_aib_mmc1_io(host, host->mmc->rthost.io_cfg.signal_voltage); + } +} + +static const struct rt_sdhci_ops k1x_sdhci_ops = +{ + .set_clock = k1x_sdhci_set_clock, + .get_max_clock = k1x_sdhci_clk_get_max_clock, + .get_max_timeout_count = k1x_get_max_timeout_count, + .set_bus_width = rt_sdhci_set_bus_width, + .reset = k1x_sdhci_reset, + .set_uhs_signaling = k1x_sdhci_set_uhs_signaling, + .platform_execute_tuning = k1x_sdhci_execute_sw_tuning, + .irq = k1x_handle_interrupt, + .set_power = rt_sdhci_set_power_and_bus_voltage, + .voltage_switch = k1x_sdhci_voltage_switch, +}; + +static int k1x_sdhci_pre_select_hs400(struct rt_mmc_host *mmc) +{ + rt_uint32_t reg; + struct rt_sdhci_host *host = rt_mmc_priv(mmc); + + reg = rt_sdhci_readl(host, SDHC_MMC_CTRL_REG); + reg |= MMC_HS400; + rt_sdhci_writel(host, reg, SDHC_MMC_CTRL_REG); + + return RT_EOK; +} + +static void k1x_sdhci_post_select_hs400(struct rt_mmc_host *mmc) +{ + struct rt_sdhci_host *host = rt_mmc_priv(mmc); + + k1x_sdhci_phy_dll_init(host); +} + +static void k1x_sdhci_pre_hs400_to_hs200(struct rt_mmc_host *mmc) +{ + rt_uint32_t reg; + struct rt_sdhci_host *host = rt_mmc_priv(mmc); + + reg = rt_sdhci_readl(host, SDHC_PHY_CTRL_REG); + reg &= ~(PHY_FUNC_EN | PHY_PLL_LOCK); + rt_sdhci_writel(host, reg, SDHC_PHY_CTRL_REG); + + reg = rt_sdhci_readl(host, SDHC_MMC_CTRL_REG); + reg &= ~(MMC_HS400 | MMC_HS200 | ENHANCE_STROBE_EN); + rt_sdhci_writel(host, reg, SDHC_MMC_CTRL_REG); + + reg = rt_sdhci_readl(host, SDHC_PHY_FUNC_REG); + reg &= ~HS200_USE_RFIFO; + rt_sdhci_writel(host, reg, SDHC_PHY_FUNC_REG); + + rt_hw_us_delay(5); + + reg = rt_sdhci_readl(host, SDHC_PHY_CTRL_REG); + reg |= PHY_FUNC_EN | PHY_PLL_LOCK; + rt_sdhci_writel(host, reg, SDHC_PHY_CTRL_REG); +} + +static struct rt_sdhci_pltfm_data sdhci_k1x_pdata = +{ + .ops = &k1x_sdhci_ops, + .quirks = RT_SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK + | RT_SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC + | RT_SDHCI_QUIRK_32BIT_ADMA_SIZE + | RT_SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, + .quirks2 = RT_SDHCI_QUIRK2_BROKEN_64_BIT_DMA, +}; + +static void k1x_sdhci_request(struct rt_mmc_host *mmc, + struct rt_mmcsd_req *mrq) +{ + struct rt_mmcsd_data *data = mrq->data; + void *original, *bounce; + rt_size_t length, alloc_length; + + if (!data || !data->buf) + { + rt_sdhci_start_request(mmc, mrq); + return; + } + + length = data->blks * data->blksize; + if (!(((rt_ubase_t)data->buf | length) & (RT_CPU_CACHE_LINE_SZ - 1))) + { + rt_sdhci_start_request(mmc, mrq); + return; + } + + alloc_length = RT_ALIGN(length, RT_CPU_CACHE_LINE_SZ); + bounce = rt_malloc_align(alloc_length, RT_CPU_CACHE_LINE_SZ); + if (!bounce) + { + mrq->cmd->err = -RT_ENOMEM; + data->err = -RT_ENOMEM; + rt_mmc_request_done(mmc, mrq); + return; + } + + original = data->buf; + if (data->flags & DATA_DIR_WRITE) + { + rt_memcpy(bounce, original, length); + } + else + { + rt_memset(bounce, 0, alloc_length); + } + + data->buf = bounce; + rt_sdhci_start_request(mmc, mrq); + rt_sem_take(&mmc->rthost.sem_ack, RT_WAITING_FOREVER); + + if ((data->flags & DATA_DIR_READ) && !mrq->cmd->err && !data->err) + { + rt_memcpy(original, bounce, length); + } + + data->buf = original; + rt_free_align(bounce); + + /* Pass the completion consumed above back to mmcsd_send_request(). */ + rt_sem_release(&mmc->rthost.sem_ack); +} + +#ifdef RT_USING_PM +static rt_err_t k1x_sdhci_pm_suspend(const struct rt_device *device, rt_uint8_t mode) +{ + rt_uint32_t reg; + rt_ubase_t level; + struct k1x_sdhci *k1x = device->user_data; + struct rt_sdhci_host *host = k1x->host; + + level = rt_spin_lock_irqsave(&host->lock); + host->runtime_suspended = RT_TRUE; + if (!(host->mmc->caps2 & MMC_CAP2_NO_MMC)) + { + reg = rt_sdhci_readl(host, SDHC_PHY_CTRL_REG); + reg &= ~PHY_FUNC_EN; + rt_sdhci_writel(host, reg, SDHC_PHY_CTRL_REG); + } + rt_spin_unlock_irqrestore(&host->lock, level); + + rt_clk_disable_unprepare(k1x->clk_io); + + if (!rt_is_err(k1x->clk_aib)) + { + rt_clk_disable_unprepare(k1x->clk_aib); + } + + if (!rt_is_err(k1x->clk_core)) + { + rt_clk_disable_unprepare(k1x->clk_core); + } + + return RT_EOK; +} + +static void k1x_sdhci_pm_resume(const struct rt_device *device, rt_uint8_t mode) +{ + rt_uint32_t reg; + rt_ubase_t level; + struct k1x_sdhci *k1x = device->user_data; + struct rt_sdhci_host *host = k1x->host; + + rt_clk_prepare_enable(k1x->clk_io); + + if (!rt_is_err(k1x->clk_aib)) + { + rt_clk_prepare_enable(k1x->clk_aib); + } + if (!rt_is_err(k1x->clk_core)) + { + rt_clk_prepare_enable(k1x->clk_core); + } + + level = rt_spin_lock_irqsave(&host->lock); + if (!(host->mmc->caps2 & MMC_CAP2_NO_MMC)) + { + reg = rt_sdhci_readl(host, SDHC_PHY_CTRL_REG); + reg |= PHY_FUNC_EN; + rt_sdhci_writel(host, reg, SDHC_PHY_CTRL_REG); + } + host->runtime_suspended = RT_FALSE; + rt_spin_unlock_irqrestore(&host->lock, level); +} + +static const struct rt_device_pm_ops k1x_sdhci_pm_ops = +{ + .suspend = k1x_sdhci_pm_suspend, + .resume = k1x_sdhci_pm_resume, +}; +#endif /* RT_USING_PM */ + +static rt_err_t k1x_sdhci_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + rt_uint32_t val; + struct k1x_sdhci *k1x; + struct k1x_sdhci_data *pdata; + struct rt_sdhci_host *host; + struct rt_sdhci_pltfm_host *pltfm_host; + struct rt_device *dev = &pdev->parent; + + host = rt_sdhci_pltfm_init(pdev, &sdhci_k1x_pdata, sizeof(*k1x)); + if (!host) + { + return -RT_ERROR; + } + + pltfm_host = rt_sdhci_priv(host); + k1x = rt_sdhci_pltfm_priv(pltfm_host); + pdata = &k1x->pdata; + + k1x->clk_io = rt_clk_get_by_name(dev, "sdh-io"); + if (rt_is_err(k1x->clk_io)) + { + k1x->clk_io = rt_clk_get_by_index(dev, 0); + } + if (rt_is_err(k1x->clk_io)) + { + err = rt_ptr_err(k1x->clk_io); + goto _fail; + } + pltfm_host->clk = k1x->clk_io; + + if ((err = rt_clk_prepare_enable(k1x->clk_io))) + { + goto _free_clk_io; + } + + k1x->clk_core = rt_clk_get_by_name(dev, "sdh-core"); + if (!rt_is_err(k1x->clk_core)) + { + if ((err = rt_clk_prepare_enable(k1x->clk_core))) + { + goto _free_clk_core; + } + } + + k1x->clk_aib = rt_clk_get_by_name(dev, "aib-clk"); + if (!rt_is_err(k1x->clk_aib)) + { + if ((err = rt_clk_prepare_enable(k1x->clk_aib))) + { + goto _free_clk_aib; + } + } + + k1x->rstc = rt_reset_control_get_by_index(dev, 0); + if (rt_is_err(k1x->rstc)) + { + err = rt_ptr_err(k1x->rstc); + goto _free_clk_aib; + } + + if ((err = rt_reset_control_deassert(k1x->rstc))) + { + goto _err_rst_get; + } + + if ((err = rt_mmc_of_parse(host->mmc))) + { + goto _err_rst_deassert; + } + + /* rt_mmc_of_parse() does not currently import this standard property. */ + if (rt_dm_dev_prop_read_bool(dev, "no-mmc")) + { + host->mmc->caps2 |= MMC_CAP2_NO_MMC; + } + + rt_sdhci_get_property(pdev); + + /* SDH io clk */ + if (!rt_dm_dev_prop_read_u32(dev, "spacemit,sdh-freq", &val)) + { + pdata->host_freq = val; + } + if (!rt_dm_dev_prop_read_u32(dev, "spacemit,sdh-flags", &val)) + { + pdata->flags |= val; + } + if (!rt_dm_dev_prop_read_u32(dev, "spacemit,sdh-host-caps", &val)) + { + pdata->host_caps |= val; + } + if (!rt_dm_dev_prop_read_u32(dev, "spacemit,sdh-host-caps2", &val)) + { + pdata->host_caps2 |= val; + } + if (!rt_dm_dev_prop_read_u32(dev, "spacemit,sdh-host-caps-disable", &val)) + { + pdata->host_caps_disable |= val; + } + if (!rt_dm_dev_prop_read_u32(dev, "spacemit,sdh-host-caps2-disable", &val)) + { + pdata->host_caps2_disable |= val; + } + if (!rt_dm_dev_prop_read_u32(dev, "spacemit,sdh-quirks", &val)) + { + pdata->quirks |= val; + } + if (!rt_dm_dev_prop_read_u32(dev, "spacemit,sdh-quirks2", &val)) + { + pdata->quirks2 |= val; + } + if (!rt_dm_dev_prop_read_u32(dev, "spacemit,aib_mmc1_io_reg", &val)) + { + pdata->aib_mmc1_io_reg = val; + } + else + { + pdata->aib_mmc1_io_reg = 0x0; + } + if (!rt_dm_dev_prop_read_u32(dev, "spacemit,apbc_asfar_reg", &val)) + { + pdata->apbc_asfar_reg = val; + } + else + { + pdata->apbc_asfar_reg = 0x0; + } + if (!rt_dm_dev_prop_read_u32(dev, "spacemit,apbc_assar_reg", &val)) + { + pdata->apbc_assar_reg = val; + } + else + { + pdata->apbc_assar_reg = 0x0; + } + /* Read rx tuning dline_reg */ + if (!rt_dm_dev_prop_read_u32(dev, "spacemit,rx_dline_reg", &val)) + { + pdata->rxtuning.rx_dline_reg = (rt_uint8_t)val; + } + else + { + pdata->rxtuning.rx_dline_reg = RX_TUNING_DLINE_REG; + } + /* Read rx tuning window limit */ + if (!rt_dm_dev_prop_read_u32(dev, "spacemit,rx_tuning_limit", &val)) + { + pdata->rxtuning.window_limit = (rt_uint8_t)val; + } + else + { + pdata->rxtuning.window_limit = RX_TUNING_WINDOW_THRESHOLD; + } + /* Read rx tuning window type */ + if (!rt_dm_dev_prop_read_u32(dev, "spacemit,rx_tuning_type", &val)) + { + pdata->rxtuning.window_type = (rt_uint8_t)val; + } + else + { + pdata->rxtuning.window_type = MIDDLE_WINDOW; + } + /* TX tuning dline_reg */ + if (!rt_dm_dev_prop_read_u32(dev, "spacemit,tx_dline_reg", &val)) + { + pdata->tx_dline_reg = (rt_uint8_t)val; + } + else + { + pdata->tx_dline_reg = TX_TUNING_DLINE_REG; + } + rt_uint32_t tx_delaycode_array[RT_ARRAY_SIZE(pdata->tx_delaycode_array)]; + int tx_delaycode_cnt = rt_dm_dev_prop_count_of_size(dev, + "spacemit,tx_delaycode", sizeof(rt_uint32_t)); + + if (tx_delaycode_cnt > 0) + { + if (tx_delaycode_cnt > RT_ARRAY_SIZE(pdata->tx_delaycode_array)) + { + tx_delaycode_cnt = RT_ARRAY_SIZE(pdata->tx_delaycode_array); + } + + if (rt_dm_dev_prop_read_u32_array_index(dev, "spacemit,tx_delaycode", + 0, tx_delaycode_cnt, tx_delaycode_array) == tx_delaycode_cnt) + { + for (int i = 0; i < tx_delaycode_cnt; ++i) + { + pdata->tx_delaycode_array[i] = tx_delaycode_array[i]; + } + pdata->tx_delaycode_cnt = tx_delaycode_cnt; + pdata->tx_delaycode = pdata->tx_delaycode_array[0]; + } + else + { + pdata->tx_delaycode_array[0] = TX_TUNING_DELAYCODE; + pdata->tx_delaycode_cnt = 1; + pdata->tx_delaycode = pdata->tx_delaycode_array[0]; + } + } + else + { + pdata->tx_delaycode_array[0] = TX_TUNING_DELAYCODE; + pdata->tx_delaycode_cnt = 1; + pdata->tx_delaycode = pdata->tx_delaycode_array[0]; + } + /* PHY driver select */ + if (!rt_dm_dev_prop_read_u32(dev, "spacemit,phy_driver_sel", &val)) + { + pdata->phy_driver_sel = (rt_uint8_t)val; + } + else + { + pdata->phy_driver_sel = PHY_DRIVE_SEL_DEFAULT; + } + /* Read rx tuning cpufreq, unit 1000Hz */ + if (!rt_dm_dev_prop_read_u32(dev, "spacemit,rx_tuning_freq", &val)) + { + pdata->rx_tuning_freq = val; + } + + if (pdata->quirks) + { + host->quirks |= pdata->quirks; + } + if (pdata->quirks2) + { + host->quirks2 |= pdata->quirks2; + } + if (pdata->host_caps) + { + host->mmc->caps |= pdata->host_caps; + } + if (pdata->host_caps2) + { + host->mmc->caps2 |= pdata->host_caps2; + } + if (pdata->pm_caps) + { + host->mmc->pm_caps |= pdata->pm_caps; + } + + if (!(host->mmc->caps2 & MMC_CAP2_NO_MMC)) + { + host->mmc_host_ops.hs400_prepare_ddr = k1x_sdhci_pre_select_hs400; + host->mmc_host_ops.hs400_complete = k1x_sdhci_post_select_hs400; + host->mmc_host_ops.hs400_downgrade = k1x_sdhci_pre_hs400_to_hs200; + if (host->mmc->caps2 & MMC_CAP2_HS400_ES) + { + host->mmc_host_ops.hs400_enhanced_strobe = k1x_sdhci_hs400_enhanced_strobe; + } + } + + if (host->mmc->caps2 & MMC_CAP2_NO_MMC) + { + /* Break sdr104 */ + if (host->mmc->caps2 & MMC_CAP2_QUIRK_BREAK_SDR104) + { + host->mmc->caps &= ~MMC_CAP_UHS_SDR104; + host->mmc->caps2 &= ~MMC_CAP2_QUIRK_BREAK_SDR104; + } + else + { + if (pdata->rxtuning.tuning_fail) + { + /* Fallback bus speed */ + host->mmc->caps &= ~MMC_CAP_UHS_SDR104; + pdata->rxtuning.tuning_fail = 0; + } + else if (!(pdata->host_caps_disable & MMC_CAP_UHS_SDR104) && + !(host->quirks2 & RT_SDHCI_QUIRK2_NO_1_8_V)) + { + /* Recovery sdr104 capability */ + host->mmc->caps |= MMC_CAP_UHS_SDR104; + } + } + } + + if (!(host->mmc->caps2 & MMC_CAP2_NO_SDIO)) + { + /* Disable MMC_CAP2_SDIO_IRQ_NOTHREAD */ + host->mmc->caps2 &= ~MMC_CAP2_SDIO_IRQ_NOTHREAD; + + /* + * Use the fake irq pending to avoid to read the SDIO_CCCR_INTx + * which sometimes return an abnormal value. + */ + host->mmc->sdio_irq_pending = RT_TRUE; + } + + host->mmc_host_ops.request = k1x_sdhci_request; + host->mmc_host_ops.start_signal_voltage_switch = k1x_sdhci_start_signal_voltage_switch; + host->mmc_host_ops.card_busy = k1x_sdhci_card_busy; + host->mmc_host_ops.enable_sdio_irq = k1x_enable_sdio_irq; + + /* Set IO clock rate */ + if (pdata->host_freq) + { + if ((err = rt_clk_set_rate(k1x->clk_io, pdata->host_freq))) + { + goto _fail; + } + } + else + { + goto _fail; + } + + if ((err = rt_sdhci_set_and_add_host(host))) + { + goto _fail; + } + + if (pdata->host_caps_disable) + { + host->mmc->caps &= ~pdata->host_caps_disable; + } + if (pdata->host_caps2_disable) + { + host->mmc->caps2 &= ~pdata->host_caps2_disable; + } + + if (host->mmc->caps2 & MMC_CAP2_NO_MMC) + { + k1x->pinctrl = RT_TRUE; + } + + dev->user_data = k1x; + +#ifdef RT_USING_PM + rt_pm_device_register(dev, &k1x_sdhci_pm_ops); +#endif + + return RT_EOK; + +_err_rst_deassert: + rt_reset_control_assert(k1x->rstc); + +_err_rst_get: + rt_reset_control_put(k1x->rstc); + k1x->rstc = RT_NULL; + + if (!rt_is_err(k1x->clk_aib)) + { + rt_clk_disable_unprepare(k1x->clk_aib); + } + +_free_clk_aib: + if (!rt_is_err(k1x->clk_aib)) + { + rt_clk_put(k1x->clk_aib); + } + k1x->clk_aib = RT_NULL; + + if (!rt_is_err(k1x->clk_core)) + { + rt_clk_disable_unprepare(k1x->clk_core); + } + +_free_clk_core: + if (!rt_is_err(k1x->clk_core)) + { + rt_clk_put(k1x->clk_core); + } + k1x->clk_core = RT_NULL; + + rt_clk_disable_unprepare(k1x->clk_io); + +_free_clk_io: + rt_clk_put(k1x->clk_io); + k1x->clk_io = RT_NULL; + +_fail: + rt_sdhci_pltfm_free(pdev); + + return err; +} + +static rt_err_t k1x_sdhci_remove(struct rt_platform_device *pdev) +{ + struct rt_sdhci_pltfm_host *pltfm_host; + struct k1x_sdhci *k1x = pdev->parent.user_data; + +#ifdef RT_USING_PM + rt_pm_device_unregister(&pdev->parent); +#endif + + pltfm_host = rt_sdhci_priv(k1x->host); + pltfm_host->clk = RT_NULL; + + rt_reset_control_assert(k1x->rstc); + + rt_clk_disable_unprepare(k1x->clk_aib); + rt_clk_disable_unprepare(k1x->clk_io); + rt_clk_disable_unprepare(k1x->clk_core); + + rt_reset_control_put(k1x->rstc); + rt_clk_put(k1x->clk_aib); + rt_clk_put(k1x->clk_io); + rt_clk_put(k1x->clk_core); + + return rt_sdhci_pltfm_remove(pdev); +} + +static const struct rt_ofw_node_id k1x_sdhci_ofw_ids[] = +{ + { .compatible = "spacemit,k1-x-sdhci" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver k1x_sdhci_driver = +{ + .name = "sdhci-iproc", + .ids = k1x_sdhci_ofw_ids, + + .probe = k1x_sdhci_probe, + .remove = k1x_sdhci_remove, +}; +RT_PLATFORM_DRIVER_EXPORT(k1x_sdhci_driver); diff --git a/bsp/spacemit/dm/serial/8250-pxa_k1x.c b/bsp/spacemit/dm/serial/8250-pxa_k1x.c new file mode 100644 index 000000000000..dfe4d8500e66 --- /dev/null +++ b/bsp/spacemit/dm/serial/8250-pxa_k1x.c @@ -0,0 +1,362 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#include +#include +#include +#include + +#include +#include "8250/8250.h" + +#define UART_XMIT_SIZE RT_DMA_PAGE_SIZE +#define DMA_BLOCK UART_XMIT_SIZE +#define DMA_BURST_SIZE 8 + +struct serial_pxa +{ + struct serial8250 parent; + + rt_bool_t device_ctrl_rts; + + struct rt_dma_slave_config rx_config; + struct rt_dma_slave_config tx_config; + struct rt_dma_slave_transfer rx_transfer; + struct rt_dma_slave_transfer tx_transfer; + + struct rt_dma_chan *dma_rx; + struct rt_dma_chan *dma_tx; + + struct rt_clk *fclk; + struct rt_clk *gclk; + struct rt_reset_control *rstc; +}; + +#define raw_to_serial_pxa(raw) rt_container_of(raw, struct serial_pxa, parent) + +static rt_err_t serial_pxa_isr(struct serial8250 *serial, int irq) +{ + rt_uint8_t iir; + rt_uint32_t ier; + + while (!((iir = serial->serial_in(serial, UART_IIR)) & UART_IIR_NO_INT)) + { + switch (iir & UART_IIR_ID) + { + /* RX data available */ + case UART_IIR_RDI: + /* RX timeout pending */ + case UART_IIR_RX_TIMEOUT: + while (serial->serial_in(serial, UART_LSR) & UART_LSR_DR) + { + rt_hw_serial_isr(&serial->parent, RT_SERIAL_EVENT_RX_IND); + } + break; + + /* TX holding register empty */ + case UART_IIR_THRI: + ier = serial->serial_in(serial, UART_IER); + ier &= ~UART_IER_THRI; /* Disable THRI */ + serial->serial_out(serial, UART_IER, ier); + break; + + /* Line status */ + case UART_IIR_RLSI: + /* Read to clear */ + serial->serial_in(serial, UART_LSR); + break; + } + } + + return RT_EOK; +} + +static rt_err_t serial_pxa_dma_enable(struct serial8250 *serial, rt_bool_t enabled) +{ + struct serial_pxa *pxa = raw_to_serial_pxa(serial); + + if (enabled) + { + rt_dma_chan_pause(pxa->dma_rx); + rt_dma_chan_pause(pxa->dma_tx); + } + else + { + rt_dma_chan_stop(pxa->dma_rx); + rt_dma_chan_stop(pxa->dma_tx); + } + + return RT_EOK; +} + +static rt_ssize_t serial_pxa_dma_tx(struct serial8250 *serial, const rt_uint8_t *buf, rt_size_t size) +{ + rt_err_t err; + struct serial_pxa *pxa = raw_to_serial_pxa(serial); + + pxa->tx_config.src_addr = (rt_ubase_t)rt_kmem_v2p((void *)buf); + + if ((err = rt_dma_chan_config(pxa->dma_tx, &pxa->tx_config))) + { + return err; + } + + pxa->tx_transfer.buffer_len = size; + pxa->tx_transfer.src_addr = pxa->tx_config.src_addr; + + if ((err = rt_dma_prep_single(pxa->dma_tx, &pxa->tx_transfer))) + { + return err; + } + + if ((err = rt_dma_chan_start(pxa->dma_tx))) + { + return err; + } + + return size; +} + +static rt_ssize_t serial_pxa_dma_rx(struct serial8250 *serial, rt_uint8_t *buf, rt_size_t size) +{ + rt_err_t err; + struct serial_pxa *pxa = raw_to_serial_pxa(serial); + + pxa->rx_config.dst_addr = (rt_ubase_t)rt_kmem_v2p(buf); + + if ((err = rt_dma_chan_config(pxa->dma_rx, &pxa->rx_config))) + { + return err; + } + + pxa->rx_transfer.buffer_len = size; + pxa->rx_transfer.dst_addr = pxa->rx_config.dst_addr; + + if ((err = rt_dma_prep_single(pxa->dma_rx, &pxa->rx_transfer))) + { + return err; + } + + if ((err = rt_dma_chan_start(pxa->dma_rx))) + { + return err; + } + + return size; +} + +static rt_err_t serial_pxa_early_setup(struct rt_fdt_earlycon *con, const char *options) +{ + struct serial8250 *serial = &early_serial8250; + + serial->base = (void *)con->mmio; + serial->size = con->size; + serial->iotype = PORT_MMIO32; + serial->regshift = 2; + fdt_getprop_u32(con->fdt, con->nodeoffset, "reg-shift", &serial->regshift, RT_NULL); + + return serial8250_early_fdt_setup(serial, con, options); +} +RT_FDT_EARLYCON_EXPORT(serial_pxa, "uart8250", "spacemit,pxa-uart", serial_pxa_early_setup); + +static void serial_pxa_8250_remove(struct serial8250 *serial) +{ + struct serial_pxa *pxa = rt_container_of(serial, struct serial_pxa, parent); + + if (serial->base) + { + rt_iounmap(serial->base); + } + + if (!rt_is_err_or_null(pxa->rstc)) + { + rt_reset_control_assert(pxa->rstc); + rt_reset_control_put(pxa->rstc); + } + + if (!rt_is_err_or_null(pxa->fclk)) + { + rt_clk_unprepare(pxa->fclk); + rt_clk_put(pxa->fclk); + } + + if (!rt_is_err_or_null(pxa->gclk)) + { + rt_clk_unprepare(pxa->gclk); + rt_clk_put(pxa->gclk); + } + + if (!rt_is_err_or_null(pxa->dma_tx)) + { + rt_dma_chan_release(pxa->dma_tx); + } + + if (!rt_is_err_or_null(pxa->dma_rx)) + { + rt_dma_chan_release(pxa->dma_rx); + } + + rt_free(pxa); +} + +static rt_err_t serial_pxa_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + rt_ubase_t fifo_addr_phys; + struct serial8250 *serial; + struct rt_device *dev = &pdev->parent; + struct serial_pxa *pxa = serial8250_alloc(pxa); + struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT; + + if (!pxa) + { + return -RT_ENOMEM; + } + serial = &pxa->parent; + + serial->base = rt_dm_dev_iomap(dev, 0); + if (!serial->base) + { + err = -RT_EIO; + goto _fail; + } + + serial->irq = rt_dm_dev_get_irq(dev, 0); + if (serial->irq < 0) + { + err = serial->irq; + goto _fail; + } + + pxa->gclk = rt_clk_get_by_name(dev, "gate"); + if (rt_is_err(pxa->gclk)) + { + err = rt_ptr_err(pxa->gclk); + goto _fail; + } + + pxa->fclk = rt_clk_get_by_name(dev, "func"); + if (rt_is_err(pxa->fclk)) + { + err = rt_ptr_err(pxa->fclk); + goto _fail; + } + + if ((err = rt_clk_prepare(pxa->gclk))) + { + goto _fail; + } + + if ((err = rt_clk_prepare(pxa->fclk))) + { + goto _fail; + } + + pxa->rstc = rt_reset_control_get_by_index(dev, 0); + if (rt_is_err(pxa->rstc)) + { + err = rt_ptr_err(pxa->rstc); + goto _fail; + } + rt_reset_control_deassert(pxa->rstc); + + fifo_addr_phys = (rt_ubase_t)rt_kmem_v2p(serial->base); + pxa->device_ctrl_rts = rt_dm_dev_prop_read_bool(dev, "device-control-rts"); + + pxa->dma_tx = rt_dma_chan_request(dev, "tx"); + + if (!rt_is_err_or_null(pxa->dma_tx)) + { + pxa->tx_config.dst_addr_width = RT_DMA_SLAVE_BUSWIDTH_1_BYTE; + pxa->tx_config.dst_maxburst = DMA_BURST_SIZE; + pxa->tx_config.direction = RT_DMA_MEM_TO_DEV; + pxa->tx_config.dst_addr = fifo_addr_phys; + + pxa->tx_transfer.dst_addr = pxa->tx_config.dst_addr; + } + + pxa->dma_rx = rt_dma_chan_request(dev, "rx"); + + if (!rt_is_err_or_null(pxa->dma_rx)) + { + pxa->rx_config.src_addr_width = RT_DMA_SLAVE_BUSWIDTH_1_BYTE; + pxa->rx_config.src_maxburst = DMA_BURST_SIZE; + pxa->rx_config.direction = RT_DMA_DEV_TO_MEM; + pxa->rx_config.src_addr = fifo_addr_phys; + + pxa->rx_transfer.src_addr = pxa->rx_config.src_addr; + } + + serial->clk = pxa->fclk; + serial->freq = rt_clk_get_rate(pxa->fclk); + serial->regshift = 2; + serial->iotype = PORT_MMIO32; + serial->parent.ops = &serial8250_uart_ops; + serial->parent.config = config; + serial->handle_irq = serial_pxa_isr; + serial->remove = serial_pxa_8250_remove; + if (!rt_is_err_or_null(pxa->dma_rx) && !rt_is_err_or_null(pxa->dma_tx)) + { + serial->serial_dma_enable = serial_pxa_dma_enable; + serial->serial_dma_tx = serial_pxa_dma_tx; + serial->serial_dma_rx = serial_pxa_dma_rx; + } + serial->data = dev; + + if ((err = serial8250_setup(serial))) + { + goto _fail; + } + + rt_dm_dev_bind_fwdata(&serial->parent.parent, dev->ofw_node, &serial->parent); + + dev->user_data = pxa; + + return RT_EOK; + +_fail: + pxa->parent.data = dev; + serial_pxa_8250_remove(&pxa->parent); + + return err; +} + +static rt_err_t serial_pxa_remove(struct rt_platform_device *pdev) +{ + struct rt_device *dev = &pdev->parent; + struct serial8250 *serial = dev->user_data; + + rt_dm_dev_unbind_fwdata(dev, RT_NULL); + + return serial8250_remove(serial); +} + +static const struct rt_ofw_node_id serial_pxa_ofw_ids[] = +{ + { .type = "ttyS", .compatible = "spacemit,pxa-uart" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver serial_pxa_driver = +{ + .name = "serial-pxa", + .ids = serial_pxa_ofw_ids, + + .probe = serial_pxa_probe, + .remove = serial_pxa_remove, +}; + +static int serial_pxa_drv_register(void) +{ + rt_platform_driver_register(&serial_pxa_driver); + + return 0; +} +INIT_PLATFORM_EXPORT(serial_pxa_drv_register); diff --git a/bsp/spacemit/dm/serial/Kconfig b/bsp/spacemit/dm/serial/Kconfig new file mode 100644 index 000000000000..8170f85904bc --- /dev/null +++ b/bsp/spacemit/dm/serial/Kconfig @@ -0,0 +1,7 @@ +config RT_SERIAL_PXA + bool "PXA serial" + depends on RT_USING_DMA + depends on RT_SERIAL_8250 + default n + +source "$(RTT_DIR)/libcpu/risc-v/common/serial/Kconfig" diff --git a/bsp/spacemit/dm/serial/SConscript b/bsp/spacemit/dm/serial/SConscript new file mode 100644 index 000000000000..9f7f3c91f45b --- /dev/null +++ b/bsp/spacemit/dm/serial/SConscript @@ -0,0 +1,13 @@ +from building import * + +group = [] +src = [] +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../include', cwd + '/../../../../components/drivers/serial/device/'] + +if GetDepend(['RT_SERIAL_PXA']): + src += ['8250-pxa_k1x.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/spacemit/dm/soc/Kconfig b/bsp/spacemit/dm/soc/Kconfig new file mode 100644 index 000000000000..f9608310d2d6 --- /dev/null +++ b/bsp/spacemit/dm/soc/Kconfig @@ -0,0 +1,33 @@ +config RT_SOC_SPACEMIT_K1X_RPROC + bool "Spacemit K1X remote processor" + depends on RT_USING_OFW + depends on RT_USING_DMA + depends on RT_USING_CLK + depends on RT_USING_RESET + depends on RT_USING_MBOX + depends on RT_USING_VIRTIO + depends on RT_USING_RPMSG + depends on RT_VIRTIO_RPMSG + default n + help + Load and control the K1X RCPU firmware and provide its VirtIO RPMsg + transport. The remote processor is started on demand by a client. + +config RT_SOC_CHIP_MEDIA_JPU + bool "Chip media JPU Driver" + default n + +config RT_SOC_SPACEMIT_V2D + bool "Spacemit V2D Engine Driver" + depends on RT_USING_OFW && RT_USING_DMA && RT_USING_CLK && RT_USING_RESET + default n + +config RT_SOC_SPACEMIT_K1X_TCM + bool "Spacemit k1x generic TCM alloc management Driver" + depends on RT_USING_MEMHEAP + default n + +config RT_SOC_SPACEMIT_SOCINFO + bool "Spacemit SoC information Driver" + depends on RT_USING_NVMEM + default n diff --git a/bsp/spacemit/dm/soc/SConscript b/bsp/spacemit/dm/soc/SConscript new file mode 100644 index 000000000000..b862bc53a4ef --- /dev/null +++ b/bsp/spacemit/dm/soc/SConscript @@ -0,0 +1,33 @@ +from building import * + +group = [] + +cwd = GetCurrentDir() +list = os.listdir(cwd) +CPPPATH = [cwd + '/../include'] + +src = [] + +if GetDepend(['RT_SOC_CHIP_MEDIA_JPU']): + src += ['jpu.c'] + +if GetDepend(['RT_SOC_SPACEMIT_K1X_RPROC']): + src += ['k1x-rproc.c'] + +if GetDepend(['RT_SOC_SPACEMIT_K1X_TCM']): + src += ['k1x-tcm.c'] + +if GetDepend(['ARCH_RISCV']): + src += ['sbi-ipi.c'] + +if GetDepend(['RT_SOC_SPACEMIT_SOCINFO']): + src += ['spacemit-socinfo.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [], CPPPATH = CPPPATH) + +for d in list: + path = os.path.join(cwd, d) + if os.path.isfile(os.path.join(path, 'SConscript')): + group = group + SConscript(os.path.join(d, 'SConscript')) + +Return('group') diff --git a/bsp/spacemit/dm/soc/jpu.c b/bsp/spacemit/dm/soc/jpu.c new file mode 100644 index 000000000000..812bd9549d32 --- /dev/null +++ b/bsp/spacemit/dm/soc/jpu.c @@ -0,0 +1,1760 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#include +#include +#include + +#define DBG_TAG "soc.spacemit.jpu" +#define DBG_LVL DBG_INFO +#include + +#include +#include +#include + +#ifndef NIEUPORT_BASE +#define NIEUPORT_BASE 0x0 +#endif + +#ifndef MMU_BASE +#define MMU_BASE 0x500 +#endif + +#define MJPEG_PIC_START_REG (NIEUPORT_BASE + 0x0000) +#define MJPEG_PIC_STATUS_REG (NIEUPORT_BASE + 0x0004) +#define MJPEG_PIC_ERRMB_REG (NIEUPORT_BASE + 0x0008) +#define MJPEG_PIC_SETMB_REG (NIEUPORT_BASE + 0x000C) + +#define MJPEG_PIC_CTRL_REG (NIEUPORT_BASE + 0x0010) +#define MJPEG_PIC_SIZE_REG (NIEUPORT_BASE + 0x0014) +#define MJPEG_MCU_INFO_REG (NIEUPORT_BASE + 0x0018) +#define MJPEG_ROT_INFO_REG (NIEUPORT_BASE + 0x001C) + +#define MJPEG_SCL_INFO_REG (NIEUPORT_BASE + 0x0020) +#define MJPEG_IF_INFO_REG (NIEUPORT_BASE + 0x0024) +#define MJPEG_CLP_INFO_REG (NIEUPORT_BASE + 0x0028) +#define MJPEG_OP_INFO_REG (NIEUPORT_BASE + 0x002C) + +#define MJPEG_DPB_CONFIG_REG (NIEUPORT_BASE + 0x0030) +#define MJPEG_DPB_BASE00_REG (NIEUPORT_BASE + 0x0034) +#define MJPEG_DPB_BASE01_REG (NIEUPORT_BASE + 0x0038) +#define MJPEG_DPB_BASE02_REG (NIEUPORT_BASE + 0x003C) +#define MJPEG_DPB_BASE10_REG (NIEUPORT_BASE + 0x0040) +#define MJPEG_DPB_BASE11_REG (NIEUPORT_BASE + 0x0044) +#define MJPEG_DPB_BASE12_REG (NIEUPORT_BASE + 0x0048) +#define MJPEG_DPB_BASE20_REG (NIEUPORT_BASE + 0x004C) +#define MJPEG_DPB_BASE21_REG (NIEUPORT_BASE + 0x0050) +#define MJPEG_DPB_BASE22_REG (NIEUPORT_BASE + 0x0054) +#define MJPEG_DPB_BASE30_REG (NIEUPORT_BASE + 0x0058) +#define MJPEG_DPB_BASE31_REG (NIEUPORT_BASE + 0x005C) +#define MJPEG_DPB_BASE32_REG (NIEUPORT_BASE + 0x0060) +#define MJPEG_DPB_YSTRIDE_REG (NIEUPORT_BASE + 0x0064) +#define MJPEG_DPB_CSTRIDE_REG (NIEUPORT_BASE + 0x0068) +#define MJPEG_WRESP_CHECK_REG (NIEUPORT_BASE + 0x006C) + +#define MJPEG_CLP_BASE_REG (NIEUPORT_BASE + 0x0070) +#define MJPEG_CLP_SIZE_REG (NIEUPORT_BASE + 0x0074) +#define MJPEG_HUFF_CTRL_REG (NIEUPORT_BASE + 0x0080) +#define MJPEG_HUFF_ADDR_REG (NIEUPORT_BASE + 0x0084) +#define MJPEG_HUFF_DATA_REG (NIEUPORT_BASE + 0x0088) +#define MJPEG_QMAT_CTRL_REG (NIEUPORT_BASE + 0x0090) +#define MJPEG_QMAT_ADDR_REG (NIEUPORT_BASE + 0x0094) +#define MJPEG_QMAT_DATA_REG (NIEUPORT_BASE + 0x0098) +#define MJPEG_COEF_CTRL_REG (NIEUPORT_BASE + 0x00A0) +#define MJPEG_COEF_ADDR_REG (NIEUPORT_BASE + 0x00A4) +#define MJPEG_COEF_DATA_REG (NIEUPORT_BASE + 0x00A8) +#define MJPEG_RST_INTVAL_REG (NIEUPORT_BASE + 0x00B0) +#define MJPEG_RST_INDEX_REG (NIEUPORT_BASE + 0x00B4) +#define MJPEG_RST_COUNT_REG (NIEUPORT_BASE + 0x00B8) +#define MJPEG_INTR_MASK_REG (NIEUPORT_BASE + 0x00C0) +#define MJPEG_CYCLE_INFO_REG (NIEUPORT_BASE + 0x00C8) +#define MJPEG_DPCM_DIFF_Y_REG (NIEUPORT_BASE + 0x00F0) +#define MJPEG_DPCM_DIFF_CB_REG (NIEUPORT_BASE + 0x00F4) +#define MJPEG_DPCM_DIFF_CR_REG (NIEUPORT_BASE + 0x00F8) + +/* GBU*/ +#define MJPEG_GBU_CTRL_REG (NIEUPORT_BASE + 0x0100) +#define MJPEG_GBU_PBIT_BUSY_REG (NIEUPORT_BASE + 0x0104) +#define MJPEG_GBU_BT_PTR_REG (NIEUPORT_BASE + 0x0110) +#define MJPEG_GBU_WD_PTR_REG (NIEUPORT_BASE + 0x0114) +#define MJPEG_GBU_TT_CNT_REG (NIEUPORT_BASE + 0x0118) +#define MJPEG_GBU_PBIT_08_REG (NIEUPORT_BASE + 0x0120) +#define MJPEG_GBU_PBIT_16_REG (NIEUPORT_BASE + 0x0124) +#define MJPEG_GBU_PBIT_24_REG (NIEUPORT_BASE + 0x0128) +#define MJPEG_GBU_PBIT_32_REG (NIEUPORT_BASE + 0x012C) +#define MJPEG_GBU_BBSR_REG (NIEUPORT_BASE + 0x0140) +#define MJPEG_GBU_BBER_REG (NIEUPORT_BASE + 0x0144) +#define MJPEG_GBU_BBIR_REG (NIEUPORT_BASE + 0x0148) +#define MJPEG_GBU_BBHR_REG (NIEUPORT_BASE + 0x014C) +#define MJPEG_GBU_BCNT_REG (NIEUPORT_BASE + 0x0158) +#define MJPEG_GBU_FF_RPTR_REG (NIEUPORT_BASE + 0x0160) +#define MJPEG_GBU_FF_WPTR_REG (NIEUPORT_BASE + 0x0164) + +/* BBC */ +#define MJPEG_BBC_END_ADDR_REG (NIEUPORT_BASE + 0x0208) +#define MJPEG_BBC_WR_PTR_REG (NIEUPORT_BASE + 0x020C) +#define MJPEG_BBC_RD_PTR_REG (NIEUPORT_BASE + 0x0210) +#define MJPEG_BBC_EXT_ADDR_REG (NIEUPORT_BASE + 0x0214) +#define MJPEG_BBC_INT_ADDR_REG (NIEUPORT_BASE + 0x0218) +#define MJPEG_BBC_DATA_CNT_REG (NIEUPORT_BASE + 0x021C) +#define MJPEG_BBC_COMMAND_REG (NIEUPORT_BASE + 0x0220) +#define MJPEG_BBC_BUSY_REG (NIEUPORT_BASE + 0x0224) +#define MJPEG_BBC_CTRL_REG (NIEUPORT_BASE + 0x0228) +#define MJPEG_BBC_CUR_POS_REG (NIEUPORT_BASE + 0x022C) +#define MJPEG_BBC_BAS_ADDR_REG (NIEUPORT_BASE + 0x0230) +#define MJPEG_BBC_STRM_CTRL_REG (NIEUPORT_BASE + 0x0234) +#define MJPEG_BBC_FLUSH_CMD_REG (NIEUPORT_BASE + 0x0238) + +#define JPU_MMU_TRI (NIEUPORT_BASE +0x400) + +#define TBU_NUM 32 +#define MJPEG_MMU_TTBLR_BASE (MMU_BASE + 0x40) +#define MJPEG_MMU_TTBHR_BASE (MMU_BASE + 0x44) +#define MJPEG_MMU_TCR0_BASE (MMU_BASE + 0x48) +#define MJPEG_MMU_TCR1_BASE (MMU_BASE + 0x4c) +#define MJPEG_MMU_TBU_STATUS_BASE (MMU_BASE + 0x50) +#define MJPEG_MMU_TBUx_STEP 0x20 +#define MJPEG_MMU_BVA_LO (MMU_BASE + 0x00) +#define MJPEG_MMU_BVA_HI (MMU_BASE + 0x04) +#define MJPEG_MMU_TIMEOUT_VA_ADDR_LO (MMU_BASE + 0x08) +#define MJPEG_MMU_TIMEOUT_VA_ADDR_HI (MMU_BASE + 0x0C) +#define MJPEG_MMU_IRQ_STATUS (MMU_BASE + 0x10) +#define MJPEG_MMU_IRQ_ENABLE (MMU_BASE + 0x14) +#define MJPEG_MMU_TIMEOUT_VALUE (MMU_BASE + 0x18) +#define MJPEG_MMU_ERROR_CLEAR (MMU_BASE + 0x1C) +#define MJPEG_MMU_LAST_VA_ADDR_LO (MMU_BASE + 0x20) +#define MJPEG_MMU_LAST_VA_ADDR_HI (MMU_BASE + 0x24) +#define MJPEG_MMU_LAST_PA_ADDR_LO (MMU_BASE + 0x28) +#define MJPEG_MMU_LAST_PA_ADDR_HI (MMU_BASE + 0x2C) +#define MJPEG_MMU_VERSION (MMU_BASE + 0x3C) + +#define MAX_ENTRIES_PER_TTB 8096 +#define ENTRY_SIZE 4 +#define MAX_SIZE_PER_TTB (MAX_ENTRIES_PER_TTB*ENTRY_SIZE) +#define DEFAULT_TIMEOUT_CYCS 0x80000 + +#define TBU_INSTANCES_NUM 2 + +#define TTB_ENTRY_SHIFT 12 +#define AQUIRE_TIMEOUT_MS 100 + +#define JPU_TIMEOUT_MS 5000 +#define JPU_BBC_TIMEOUT_US 10000 +#define JPU_ALIGN(value, align) (((value) + (align) - 1) & ~((align) - 1)) +#define JPU_BBC_PAGE_SIZE 256U + +#define JPU_TBU_INPUT 0 +#define JPU_TBU_OUTPUT 1 + +#define JPU_TBU_BASE_VA 0x80000000 +#define JPU_TBU_VA_STEP 0x2000000 + +#define JPU_INT_FATAL_MASK (RT_BIT(JPU_INT_ERROR) | \ + RT_BIT(JPU_INT_OVERFLOW)) + +#define JPU_DECODE_REG_NUM ((MJPEG_BBC_STRM_CTRL_REG / sizeof(rt_uint32_t)) + 1) + +enum spacemit_jpu_int_reason +{ + JPU_INT_DONE = 0, + JPU_INT_ERROR, + JPU_INT_BIT_BUF_EMPTY, + JPU_INT_OVERFLOW = 3, +}; + +struct spacemit_jpu_map +{ + rt_ubase_t stream_phys; + rt_ubase_t frame_phys; + rt_size_t stream_size; + rt_size_t frame_size; + rt_ubase_t stream_iova; + rt_ubase_t frame_iova; +}; + +struct spacemit_jpu_tbu +{ + rt_uint32_t *ttb_va; + rt_ubase_t ttb_pa; + rt_size_t ttb_size; + rt_ubase_t va_base; + rt_ubase_t va_end; +}; + +struct spacemit_jpu +{ + struct rt_device parent; + + struct rt_device *dev; + void *regs; + int irq; + + struct rt_clk *cclk; + struct rt_clk *aclk; + struct rt_clk *iclk; + + struct rt_reset_control *jpg_reset; + struct rt_reset_control *lcd_mclk_reset; + struct rt_reset_control *isp_ci_reset; + struct rt_reset_control *freset; + struct rt_reset_control *sreset; + + struct spacemit_jpu_tbu tbu[TBU_INSTANCES_NUM]; + rt_uint32_t page_size; + rt_ubase_t va_base; + rt_uint32_t time_out_cycs; + rt_bool_t mmu_enable; + + rt_uint32_t irq_reason; + rt_err_t error; + struct rt_completion completion; + struct rt_mutex lock; + struct rt_spinlock hw_lock; +}; + +#define raw_to_spacemit_jpu(raw) rt_container_of(raw, struct spacemit_jpu, parent) + +rt_inline rt_uint32_t spacemit_jpu_read(struct spacemit_jpu *jpu, int offset) +{ + return HWREG32(jpu->regs + offset); +} + +rt_inline void spacemit_jpu_write(struct spacemit_jpu *jpu, int offset, rt_uint32_t val) +{ + HWREG32(jpu->regs + offset) = val; +} + +rt_inline void spacemit_jpu_set_bits(struct spacemit_jpu *jpu, int offset, rt_uint32_t bits) +{ + spacemit_jpu_write(jpu, offset, spacemit_jpu_read(jpu, offset) | bits); +} + +rt_inline void spacemit_jpu_clear_bits(struct spacemit_jpu *jpu, int offset, rt_uint32_t bits) +{ + spacemit_jpu_write(jpu, offset, spacemit_jpu_read(jpu, offset) & ~bits); +} + +static rt_err_t spacemit_jpu_clk_enable(struct spacemit_jpu *jpu) +{ + rt_err_t err; + + if (!rt_is_err_or_null(jpu->cclk)) + { + err = rt_clk_prepare_enable(jpu->cclk); + if (err) + { + return err; + } + } + if (!rt_is_err_or_null(jpu->aclk)) + { + err = rt_clk_prepare_enable(jpu->aclk); + if (err) + { + return err; + } + } + if (!rt_is_err_or_null(jpu->iclk)) + { + err = rt_clk_prepare_enable(jpu->iclk); + if (err) + { + return err; + } + } + + return RT_EOK; +} + +static void spacemit_jpu_clk_disable(struct spacemit_jpu *jpu) +{ + if (!rt_is_err_or_null(jpu->iclk)) + { + rt_clk_disable_unprepare(jpu->iclk); + } + if (!rt_is_err_or_null(jpu->aclk)) + { + rt_clk_disable_unprepare(jpu->aclk); + } + if (!rt_is_err_or_null(jpu->cclk)) + { + rt_clk_disable_unprepare(jpu->cclk); + } +} + +static void spacemit_jpu_reset_assert_all(struct spacemit_jpu *jpu) +{ + if (!rt_is_err_or_null(jpu->jpg_reset)) + { + rt_reset_control_assert(jpu->jpg_reset); + } + if (!rt_is_err_or_null(jpu->lcd_mclk_reset)) + { + rt_reset_control_assert(jpu->lcd_mclk_reset); + } + if (!rt_is_err_or_null(jpu->isp_ci_reset)) + { + rt_reset_control_assert(jpu->isp_ci_reset); + } + if (!rt_is_err_or_null(jpu->freset)) + { + rt_reset_control_assert(jpu->freset); + } + if (!rt_is_err_or_null(jpu->sreset)) + { + rt_reset_control_assert(jpu->sreset); + } +} + +static void spacemit_jpu_reset_deassert_all(struct spacemit_jpu *jpu) +{ + if (!rt_is_err_or_null(jpu->jpg_reset)) + { + rt_reset_control_deassert(jpu->jpg_reset); + } + if (!rt_is_err_or_null(jpu->lcd_mclk_reset)) + { + rt_reset_control_deassert(jpu->lcd_mclk_reset); + } + if (!rt_is_err_or_null(jpu->isp_ci_reset)) + { + rt_reset_control_deassert(jpu->isp_ci_reset); + } + if (!rt_is_err_or_null(jpu->freset)) + { + rt_reset_control_deassert(jpu->freset); + } + if (!rt_is_err_or_null(jpu->sreset)) + { + rt_reset_control_deassert(jpu->sreset); + } +} + +static void spacemit_jpu_enable_mmu_hw(struct spacemit_jpu *jpu); +static void spacemit_jpu_disable_mmu_hw(struct spacemit_jpu *jpu); + +static void spacemit_jpu_hard_reset(struct spacemit_jpu *jpu) +{ + spacemit_jpu_clk_disable(jpu); + spacemit_jpu_reset_assert_all(jpu); + rt_hw_us_delay(5); + spacemit_jpu_reset_deassert_all(jpu); + spacemit_jpu_clk_enable(jpu); + spacemit_jpu_write(jpu, MJPEG_PIC_STATUS_REG, 0); +} + +static rt_err_t spacemit_jpu_sw_reset(struct spacemit_jpu *jpu) +{ + int timeout = JPU_BBC_TIMEOUT_US; + + spacemit_jpu_write(jpu, MJPEG_PIC_START_REG, RT_BIT(1)); + while (spacemit_jpu_read(jpu, MJPEG_PIC_START_REG) & RT_BIT(1)) + { + if (--timeout == 0) + { + LOG_E("JPU software reset timeout"); + return -RT_ETIMEOUT; + } + rt_hw_us_delay(1); + } + + return RT_EOK; +} + +static void spacemit_jpu_write_tbu_table(struct spacemit_jpu *jpu, + struct spacemit_jpu_tbu *tbu, rt_ubase_t iova, rt_ubase_t paddr, rt_size_t size) +{ + rt_uint32_t *ttb_entry; + rt_size_t pages; + rt_ubase_t mask; + rt_uint32_t val; + + mask = (jpu->page_size == 4096) ? 0xFFFFFFFFFFFFF000ULL : 0xFFFFFFFFFFFF0000ULL; + ttb_entry = tbu->ttb_va + (iova - tbu->va_base) / jpu->page_size; + + pages = RT_DIV_ROUND_UP(size, jpu->page_size); + while (pages-- != 0) + { + val = (rt_uint32_t)(((paddr & mask) >> TTB_ENTRY_SHIFT) & 0x1FFFFF); + *ttb_entry = val; + ttb_entry++; + paddr += jpu->page_size; + } +} + +static void spacemit_jpu_mmu_post(struct spacemit_jpu *jpu, int tbu_id) +{ + struct spacemit_jpu_tbu *tbu = &jpu->tbu[tbu_id]; + rt_uint32_t reg; + int index; + + if (!jpu->mmu_enable) + { + return; + } + + index = (tbu->va_base - jpu->va_base) / JPU_TBU_VA_STEP; + + if (tbu->ttb_size == 0) + { + spacemit_jpu_write(jpu, MJPEG_MMU_TCR0_BASE + index * MJPEG_MMU_TBUx_STEP, 0); + return; + } + + spacemit_jpu_write(jpu, MJPEG_MMU_TTBLR_BASE + index * MJPEG_MMU_TBUx_STEP, + (rt_uint32_t)(tbu->ttb_pa & 0xFFFFFFFF)); + spacemit_jpu_write(jpu, MJPEG_MMU_TTBHR_BASE + index * MJPEG_MMU_TBUx_STEP, + (rt_uint32_t)(tbu->ttb_pa >> 32)); + + reg = (rt_uint32_t)((tbu->ttb_size - 1) << 16); + reg |= RT_BIT(2); + if (jpu->page_size == 64 * 1024) + { + reg |= RT_BIT(1); + } + reg |= RT_BIT(0); + + spacemit_jpu_write(jpu, MJPEG_MMU_TCR0_BASE + index * MJPEG_MMU_TBUx_STEP, reg); +} + +static rt_err_t spacemit_jpu_mmu_map_one(struct spacemit_jpu *jpu, int tbu_id, + rt_ubase_t phys, rt_ubase_t iova, rt_size_t size, rt_ubase_t *mapped_iova) +{ + struct spacemit_jpu_tbu *tbu = &jpu->tbu[tbu_id]; + int index; + rt_ubase_t end; + + if (!size || !phys) + { + return -RT_EINVAL; + } + + if (!jpu->mmu_enable) + { + spacemit_jpu_enable_mmu_hw(jpu); + } + + index = (iova - jpu->va_base) / JPU_TBU_VA_STEP; + tbu->va_base = jpu->va_base + index * JPU_TBU_VA_STEP; + tbu->va_end = tbu->va_base + JPU_TBU_VA_STEP; + + if (iova < tbu->va_base || iova >= tbu->va_end) + { + return -RT_EINVAL; + } + + end = iova + size; + if (end > tbu->va_end) + { + return -RT_EINVAL; + } + + if (!is_aligned(phys, jpu->page_size)) + { + LOG_E("MMU map phys 0x%llx is not page aligned", (unsigned long long)phys); + return -RT_EINVAL; + } + + if (RT_DIV_ROUND_UP(end - tbu->va_base, jpu->page_size) > MAX_ENTRIES_PER_TTB) + { + return -RT_EINVAL; + } + + rt_spin_lock(&jpu->hw_lock); + spacemit_jpu_write_tbu_table(jpu, tbu, iova, phys, size); + + if (end > tbu->va_base + jpu->page_size * tbu->ttb_size) + { + tbu->ttb_size = RT_DIV_ROUND_UP(end - tbu->va_base, jpu->page_size); + } + + spacemit_jpu_mmu_post(jpu, tbu_id); + rt_spin_unlock(&jpu->hw_lock); + + *mapped_iova = iova; + return RT_EOK; +} + +static void spacemit_jpu_enable_mmu_hw(struct spacemit_jpu *jpu) +{ + int i; + + if (jpu->mmu_enable) + { + return; + } + + for (i = 0; i < TBU_INSTANCES_NUM; i++) + { + jpu->tbu[i].ttb_size = 0; + } + + spacemit_jpu_write(jpu, MJPEG_MMU_BVA_LO, (rt_uint32_t)(jpu->va_base & 0xFFFFFFFF)); + spacemit_jpu_write(jpu, MJPEG_MMU_BVA_HI, (rt_uint32_t)(jpu->va_base >> 32)); + spacemit_jpu_write(jpu, MJPEG_MMU_TIMEOUT_VALUE, jpu->time_out_cycs); + spacemit_jpu_set_bits(jpu, MJPEG_MMU_IRQ_ENABLE, 0); + + jpu->mmu_enable = RT_TRUE; +} + +static void spacemit_jpu_disable_mmu_hw(struct spacemit_jpu *jpu) +{ + int i; + + if (!jpu->mmu_enable) + { + return; + } + + rt_spin_lock(&jpu->hw_lock); + jpu->mmu_enable = RT_FALSE; + + for (i = 0; i < TBU_INSTANCES_NUM; i++) + { + jpu->tbu[i].ttb_size = 0; + } + + for (i = 0; i < TBU_NUM; i++) + { + spacemit_jpu_write(jpu, MJPEG_MMU_TCR0_BASE + MJPEG_MMU_TBUx_STEP * i, 0); + } + + spacemit_jpu_clear_bits(jpu, MJPEG_MMU_IRQ_ENABLE, 0x1FF); + rt_spin_unlock(&jpu->hw_lock); +} + +static rt_err_t spacemit_jpu_mmu_map(struct spacemit_jpu *jpu, + struct spacemit_jpu_map *map) +{ + rt_err_t err; + rt_ubase_t stream_iova = JPU_TBU_BASE_VA + JPU_TBU_INPUT * JPU_TBU_VA_STEP; + rt_ubase_t frame_iova = JPU_TBU_BASE_VA + JPU_TBU_OUTPUT * JPU_TBU_VA_STEP; + rt_uint64_t stream_end; + rt_uint64_t frame_end; + + if (!map) + { + return -RT_EINVAL; + } + + stream_end = (rt_uint64_t)map->stream_phys + map->stream_size; + frame_end = (rt_uint64_t)map->frame_phys + map->frame_size; + if (stream_end > map->stream_phys && frame_end > map->frame_phys && + stream_end <= (rt_uint64_t)UINT32_MAX + 1 && + frame_end <= (rt_uint64_t)UINT32_MAX + 1) + { + /* Bypasses the JPU MMU for a single contiguous DMA segment. */ + spacemit_jpu_disable_mmu_hw(jpu); + map->stream_iova = map->stream_phys; + map->frame_iova = map->frame_phys; + return RT_EOK; + } + + err = spacemit_jpu_mmu_map_one(jpu, JPU_TBU_INPUT, map->stream_phys, + stream_iova, map->stream_size, &stream_iova); + if (err != RT_EOK) + { + spacemit_jpu_disable_mmu_hw(jpu); + return err; + } + + err = spacemit_jpu_mmu_map_one(jpu, JPU_TBU_OUTPUT, map->frame_phys, + frame_iova, map->frame_size, &frame_iova); + if (err != RT_EOK) + { + spacemit_jpu_disable_mmu_hw(jpu); + return err; + } + + spacemit_jpu_write(jpu, JPU_MMU_TRI, 0x01); + + map->stream_iova = stream_iova; + map->frame_iova = frame_iova; + + return RT_EOK; +} + +static rt_err_t spacemit_jpu_buffer_alloc(struct spacemit_jpu *jpu, struct jpu_buffer *buf) +{ + rt_ubase_t phys_addr; + + if (!buf || !buf->size) + { + return -RT_EINVAL; + } + + buf->virt_addr = rt_dma_alloc_coherent(jpu->dev, buf->size, &phys_addr); + if (!buf->virt_addr) + { + return -RT_ENOMEM; + } + + buf->phys_addr = phys_addr; + + return RT_EOK; +} + +static rt_err_t spacemit_jpu_buffer_free(struct spacemit_jpu *jpu, struct jpu_buffer *buf) +{ + if (!buf || !buf->virt_addr) + { + return -RT_EINVAL; + } + + rt_dma_free_coherent(jpu->dev, buf->size, buf->virt_addr, buf->phys_addr); + buf->virt_addr = RT_NULL; + buf->phys_addr = 0; + + return RT_EOK; +} + +static rt_err_t spacemit_jpu_query_frame(struct jpu_frame_info *frame) +{ + rt_uint32_t aligned_width; + rt_uint32_t aligned_height; + rt_uint32_t y_stride; + rt_uint32_t c_stride; + rt_uint32_t c_height; + rt_uint64_t size; + + if (!frame || !frame->width || !frame->height) + { + return -RT_EINVAL; + } + + switch (frame->format) + { + case JPU_FORMAT_420: + aligned_width = JPU_ALIGN(frame->width, 16); + aligned_height = JPU_ALIGN(frame->height, 16); + y_stride = JPU_ALIGN(aligned_width, 8); + c_stride = JPU_ALIGN(y_stride / 2, 16); + c_height = JPU_ALIGN(aligned_height / 2, 8); + break; + case JPU_FORMAT_422: + aligned_width = JPU_ALIGN(frame->width, 16); + aligned_height = JPU_ALIGN(frame->height, 8); + y_stride = JPU_ALIGN(aligned_width, 8); + c_stride = JPU_ALIGN(y_stride / 2, 16); + c_height = JPU_ALIGN(aligned_height, 8); + break; + case JPU_FORMAT_440: + aligned_width = JPU_ALIGN(frame->width, 8); + aligned_height = JPU_ALIGN(frame->height, 16); + y_stride = JPU_ALIGN(aligned_width, 8); + c_stride = JPU_ALIGN(y_stride, 8); + c_height = JPU_ALIGN(aligned_height / 2, 8); + break; + case JPU_FORMAT_444: + aligned_width = JPU_ALIGN(frame->width, 8); + aligned_height = JPU_ALIGN(frame->height, 8); + y_stride = JPU_ALIGN(aligned_width, 8); + c_stride = JPU_ALIGN(y_stride, 8); + c_height = JPU_ALIGN(aligned_height, 8); + break; + case JPU_FORMAT_400: + aligned_width = JPU_ALIGN(frame->width, 8); + aligned_height = JPU_ALIGN(frame->height, 8); + y_stride = JPU_ALIGN(aligned_width, 8); + c_stride = 0; + c_height = 0; + break; + default: + return -RT_EINVAL; + } + + if (aligned_width > UINT16_MAX || aligned_height > UINT16_MAX || + y_stride > UINT16_MAX || c_stride > UINT16_MAX || c_height > UINT16_MAX) + { + return -RT_EINVAL; + } + + size = (rt_uint64_t)y_stride * aligned_height + + (rt_uint64_t)c_stride * c_height * 2; + if (!size || size > JPU_BUFFER_MAX_SIZE) + { + return -RT_ENOMEM; + } + + frame->aligned_width = aligned_width; + frame->aligned_height = aligned_height; + frame->y_stride = y_stride; + frame->c_stride = c_stride; + frame->c_height = c_height; + frame->size = size; + + return RT_EOK; +} + +static rt_err_t spacemit_jpu_validate_decode(struct jpu_decode_request *req) +{ + int component; + rt_err_t err; + + if (!req || !req->stream_phys || !req->frame_phys || + !req->stream_size || req->entropy_offset >= req->stream_size || + req->stream_capacity > JPU_BUFFER_MAX_SIZE || + req->frame_capacity > JPU_BUFFER_MAX_SIZE || + req->stream_size > req->stream_capacity || + JPU_STREAM_PADDING > req->stream_capacity - req->stream_size) + { + return -RT_EINVAL; + } + + if ((req->frame.format == JPU_FORMAT_400 && req->components != 1) || + (req->frame.format != JPU_FORMAT_400 && req->components != 3)) + { + return -RT_EINVAL; + } + + for (component = 0; component < req->components; ++component) + { + if (req->dc_selector[component] > 1 || req->ac_selector[component] > 1) + { + return -RT_EINVAL; + } + } + + if ((err = spacemit_jpu_query_frame(&req->frame)) != RT_EOK) + { + return err; + } + if (req->frame_capacity < req->frame.size) + { + return -RT_ENOMEM; + } + + return RT_EOK; +} + +static const rt_uint8_t jpu_default_huff_bits[JPU_HUFF_TABLE_NUM][JPU_HUFF_BITS_NUM] = +{ + { 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03, + 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7d }, + { 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, + 0x07, 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, 0x77 }, +}; + +static const rt_uint8_t jpu_default_huff_values[JPU_HUFF_TABLE_NUM][JPU_HUFF_VALUES_NUM] = +{ + { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, + }, + { + 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, + 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, + 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, + 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, + 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, + 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, + 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, + 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, + 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, + 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, + 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, + 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, + 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, + 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, + 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, + 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, + 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2, + 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, + 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, + 0xf9, 0xfa, + }, + { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, + }, + { + 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, + 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, + 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, + 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, + 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, + 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26, + 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38, + 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, + 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, + 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, + 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, + 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, + 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, + 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, + 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, + 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, + 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, + 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, + 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, + 0xf9, 0xfa, + }, +}; + +static rt_bool_t spacemit_jpu_uses_default_huffman(const struct jpu_decode_request *req) +{ + rt_bool_t checked[JPU_HUFF_TABLE_NUM] = { RT_FALSE }; + int component; + + for (component = 0; component < req->components; ++component) + { + int tables[2] = + { + req->dc_selector[component] * 2, + req->ac_selector[component] * 2 + 1, + }; + int type; + + for (type = 0; type < 2; ++type) + { + int index = tables[type]; + int count = 0; + int i; + + if (checked[index]) + { + continue; + } + checked[index] = RT_TRUE; + + for (i = 0; i < JPU_HUFF_BITS_NUM; ++i) + { + count += req->tables.huff_bits[index][i]; + } + + if (rt_memcmp(req->tables.huff_bits[index], + jpu_default_huff_bits[index], JPU_HUFF_BITS_NUM) || + rt_memcmp(req->tables.huff_values[index], + jpu_default_huff_values[index], count)) + { + return RT_FALSE; + } + } + } + + return RT_TRUE; +} + +static void spacemit_jpu_build_decode_regs(const struct jpu_decode_request *req, + const struct spacemit_jpu_map *map, rt_uint32_t *reg) +{ + const struct jpu_frame_info *frame = &req->frame; + rt_uint32_t y_size = frame->y_stride * frame->aligned_height; + rt_uint32_t c_size = frame->c_stride * frame->c_height; + rt_uint32_t dc = req->dc_selector[0]; + rt_uint32_t ac = req->ac_selector[0]; + rt_uint32_t mcu_width; + rt_uint32_t mcu_height; + rt_uint32_t mcu_blocks; + rt_uint32_t bus_requests; + rt_uint32_t comp0; + rt_uint32_t stream_end = (rt_uint32_t)map->stream_iova + req->stream_size; + + switch (frame->format) + { + case JPU_FORMAT_420: + mcu_width = 16; + mcu_height = 16; + mcu_blocks = 6; + bus_requests = 2; + break; + case JPU_FORMAT_422: + mcu_width = 16; + mcu_height = 8; + mcu_blocks = 4; + bus_requests = 3; + break; + case JPU_FORMAT_440: + mcu_width = 8; + mcu_height = 16; + mcu_blocks = 4; + bus_requests = 8; + break; + case JPU_FORMAT_444: + mcu_width = 8; + mcu_height = 8; + mcu_blocks = 3; + bus_requests = 4; + break; + default: + mcu_width = 8; + mcu_height = 8; + mcu_blocks = 1; + bus_requests = 4; + break; + } + + if (req->components == 3) + { + dc = (dc << 1) | req->dc_selector[1]; + dc = (dc << 1) | req->dc_selector[2]; + ac = (ac << 1) | req->ac_selector[1]; + ac = (ac << 1) | req->ac_selector[2]; + } + else + { + dc <<= 2; + ac <<= 2; + } + + comp0 = ((mcu_width >> 3) << 2) | (mcu_height >> 3); + reg[MJPEG_PIC_START_REG / 4] = 1; + reg[MJPEG_PIC_CTRL_REG / 4] = (ac << 10) | (dc << 7); + if (!spacemit_jpu_uses_default_huffman(req)) + { + reg[MJPEG_PIC_CTRL_REG / 4] |= RT_BIT(6); + } + reg[MJPEG_PIC_SIZE_REG / 4] = ((rt_uint32_t)frame->aligned_width << 16) | + frame->aligned_height; + reg[MJPEG_MCU_INFO_REG / 4] = (mcu_blocks << 16) | + ((rt_uint32_t)req->components << 12) | (comp0 << 8) | + ((req->components == 3 ? 5U : 0U) << 4) | + (req->components == 3 ? 5U : 0U); + reg[MJPEG_OP_INFO_REG / 4] = bus_requests; + reg[MJPEG_DPB_BASE00_REG / 4] = (rt_uint32_t)map->frame_iova; + reg[MJPEG_DPB_BASE01_REG / 4] = (rt_uint32_t)map->frame_iova + y_size; + reg[MJPEG_DPB_BASE02_REG / 4] = (rt_uint32_t)map->frame_iova + y_size + c_size; + reg[MJPEG_DPB_YSTRIDE_REG / 4] = frame->y_stride; + reg[MJPEG_DPB_CSTRIDE_REG / 4] = frame->c_stride; + reg[MJPEG_RST_INTVAL_REG / 4] = req->restart_interval; + reg[MJPEG_INTR_MASK_REG / 4] = + (~(RT_BIT(JPU_INT_DONE) | RT_BIT(JPU_INT_ERROR) | + RT_BIT(JPU_INT_BIT_BUF_EMPTY))) & 0x3ff; + reg[MJPEG_BBC_WR_PTR_REG / 4] = stream_end; + reg[MJPEG_BBC_END_ADDR_REG / 4] = JPU_ALIGN(stream_end, JPU_BBC_PAGE_SIZE); + reg[MJPEG_BBC_RD_PTR_REG / 4] = (rt_uint32_t)map->stream_iova; + reg[MJPEG_BBC_BAS_ADDR_REG / 4] = (rt_uint32_t)map->stream_iova; + reg[MJPEG_BBC_STRM_CTRL_REG / 4] = RT_BIT(31) | + RT_DIV_ROUND_UP(req->stream_size, JPU_BBC_PAGE_SIZE); +} + +static void spacemit_jpu_make_huffman_table(const struct jpu_dec_tables *tables, + rt_uint16_t min[JPU_HUFF_TABLE_NUM][JPU_HUFF_BITS_NUM], + rt_uint16_t max[JPU_HUFF_TABLE_NUM][JPU_HUFF_BITS_NUM], + rt_uint8_t ptr[JPU_HUFF_TABLE_NUM][JPU_HUFF_BITS_NUM]) +{ + int table, length; + + for (table = 0; table < JPU_HUFF_TABLE_NUM; ++table) + { + rt_uint32_t code = 0; + rt_uint32_t value_index = 0; + rt_bool_t have_code = RT_FALSE; + + for (length = 0; length < JPU_HUFF_BITS_NUM; ++length) + { + rt_uint32_t count = tables->huff_bits[table][length]; + + if (count) + { + ptr[table][length] = value_index; + min[table][length] = code; + max[table][length] = code + count - 1; + value_index += count; + code = (max[table][length] + 1) << 1; + have_code = RT_TRUE; + } + else + { + ptr[table][length] = 0xff; + min[table][length] = 0xffff; + max[table][length] = 0xffff; + if (have_code) + { + code <<= 1; + } + } + } + } +} + +static rt_err_t spacemit_jpu_load_huffman(struct spacemit_jpu *jpu, + const struct jpu_dec_tables *tables) +{ + static const rt_uint8_t order[JPU_HUFF_TABLE_NUM] = { 0, 2, 1, 3 }; + rt_uint16_t min[JPU_HUFF_TABLE_NUM][JPU_HUFF_BITS_NUM]; + rt_uint16_t max[JPU_HUFF_TABLE_NUM][JPU_HUFF_BITS_NUM]; + rt_uint8_t ptr[JPU_HUFF_TABLE_NUM][JPU_HUFF_BITS_NUM]; + int count[JPU_HUFF_TABLE_NUM] = { 0 }; + int table, i; + + for (table = 0; table < JPU_HUFF_TABLE_NUM; ++table) + { + for (i = 0; i < JPU_HUFF_BITS_NUM; ++i) + { + count[table] += tables->huff_bits[table][i]; + } + + if (count[table] <= 0 || + count[table] > ((table & 1) ? JPU_HUFF_VALUES_NUM : 12)) + { + return -RT_EINVAL; + } + } + + spacemit_jpu_make_huffman_table(tables, min, max, ptr); + + spacemit_jpu_write(jpu, MJPEG_HUFF_CTRL_REG, 0x003); + for (table = 0; table < JPU_HUFF_TABLE_NUM; ++table) + { + int index = order[table]; + + for (i = 0; i < JPU_HUFF_BITS_NUM; ++i) + { + spacemit_jpu_write(jpu, MJPEG_HUFF_DATA_REG, + (rt_uint32_t)(rt_int32_t)(rt_int16_t)min[index][i]); + } + } + + spacemit_jpu_write(jpu, MJPEG_HUFF_CTRL_REG, 0x403); + spacemit_jpu_write(jpu, MJPEG_HUFF_ADDR_REG, 0x440); + for (table = 0; table < JPU_HUFF_TABLE_NUM; ++table) + { + int index = order[table]; + + for (i = 0; i < JPU_HUFF_BITS_NUM; ++i) + { + spacemit_jpu_write(jpu, MJPEG_HUFF_DATA_REG, + (rt_uint32_t)(rt_int32_t)(rt_int16_t)max[index][i]); + } + } + + spacemit_jpu_write(jpu, MJPEG_HUFF_CTRL_REG, 0x803); + spacemit_jpu_write(jpu, MJPEG_HUFF_ADDR_REG, 0x880); + for (table = 0; table < JPU_HUFF_TABLE_NUM; ++table) + { + int index = order[table]; + + for (i = 0; i < JPU_HUFF_BITS_NUM; ++i) + { + spacemit_jpu_write(jpu, MJPEG_HUFF_DATA_REG, + (rt_uint32_t)(rt_int32_t)(rt_int8_t)ptr[index][i]); + } + } + + spacemit_jpu_write(jpu, MJPEG_HUFF_CTRL_REG, 0xc03); + for (table = 0; table < JPU_HUFF_TABLE_NUM; ++table) + { + int index = order[table]; + int slots = (index & 1) ? JPU_HUFF_VALUES_NUM : 12; + + for (i = 0; i < count[index]; ++i) + { + spacemit_jpu_write(jpu, MJPEG_HUFF_DATA_REG, + (rt_uint32_t)(rt_int32_t)(rt_int8_t)tables->huff_values[index][i]); + } + for (; i < slots; ++i) + { + spacemit_jpu_write(jpu, MJPEG_HUFF_DATA_REG, 0xffffffff); + } + } + spacemit_jpu_write(jpu, MJPEG_HUFF_CTRL_REG, 0); + + return RT_EOK; +} + +static void spacemit_jpu_load_quant(struct spacemit_jpu *jpu, + const struct jpu_dec_tables *tables) +{ + static const rt_uint32_t control[JPU_QUANT_COMPONENT_NUM] = { 0x03, 0x43, 0x83 }; + int component, i; + + for (component = 0; component < JPU_QUANT_COMPONENT_NUM; ++component) + { + spacemit_jpu_write(jpu, MJPEG_QMAT_CTRL_REG, control[component]); + for (i = 0; i < JPU_QUANT_VALUES_NUM; ++i) + { + spacemit_jpu_write(jpu, MJPEG_QMAT_DATA_REG, + tables->quant[component][i]); + } + spacemit_jpu_write(jpu, MJPEG_QMAT_CTRL_REG, 0); + } +} + +static rt_err_t spacemit_jpu_wait_bbc(struct spacemit_jpu *jpu) +{ + int timeout = JPU_BBC_TIMEOUT_US; + + while (spacemit_jpu_read(jpu, MJPEG_BBC_BUSY_REG) & 1) + { + if (--timeout == 0) + { + LOG_E("JPU BBC preload timeout"); + return -RT_ETIMEOUT; + } + rt_hw_us_delay(1); + } + + return RT_EOK; +} + +static rt_err_t spacemit_jpu_prepare_stream(struct spacemit_jpu *jpu, + rt_uint32_t stream_base, rt_uint32_t entropy_offset) +{ + rt_uint32_t page = entropy_offset >> 8; + rt_uint32_t word = (entropy_offset & 0xf0) >> 2; + rt_uint32_t bit = (entropy_offset & 0xf) << 3; + int i; + + if (page & 1) + { + word += 64; + } + if (word & 1) + { + --word; + } + + for (i = 0; i < 2; ++i) + { + rt_uint32_t current = page + i; + + spacemit_jpu_write(jpu, MJPEG_BBC_CUR_POS_REG, current); + spacemit_jpu_write(jpu, MJPEG_BBC_EXT_ADDR_REG, stream_base + (current << 8)); + spacemit_jpu_write(jpu, MJPEG_BBC_INT_ADDR_REG, (current & 1) << 6); + spacemit_jpu_write(jpu, MJPEG_BBC_DATA_CNT_REG, 64); + spacemit_jpu_write(jpu, MJPEG_BBC_COMMAND_REG, 0); + if (spacemit_jpu_wait_bbc(jpu) != RT_EOK) + { + return -RT_ETIMEOUT; + } + } + + spacemit_jpu_write(jpu, MJPEG_BBC_CUR_POS_REG, page + 2); + spacemit_jpu_write(jpu, MJPEG_BBC_CTRL_REG, 1); + spacemit_jpu_write(jpu, MJPEG_GBU_WD_PTR_REG, word); + spacemit_jpu_write(jpu, MJPEG_GBU_BBSR_REG, 0); + spacemit_jpu_write(jpu, MJPEG_GBU_BBER_REG, 127); + spacemit_jpu_write(jpu, MJPEG_GBU_BBIR_REG, (page & 1) ? 0 : 64); + spacemit_jpu_write(jpu, MJPEG_GBU_BBHR_REG, (page & 1) ? 0 : 64); + spacemit_jpu_write(jpu, MJPEG_GBU_CTRL_REG, 4); + spacemit_jpu_write(jpu, MJPEG_GBU_FF_RPTR_REG, bit); + + return RT_EOK; +} + +static void spacemit_jpu_dump_timeout(struct spacemit_jpu *jpu) +{ + LOG_E("core: start=%08x status=%08x errmb=%08x cycle=%08x", + spacemit_jpu_read(jpu, MJPEG_PIC_START_REG), + spacemit_jpu_read(jpu, MJPEG_PIC_STATUS_REG), + spacemit_jpu_read(jpu, MJPEG_PIC_ERRMB_REG), + spacemit_jpu_read(jpu, MJPEG_CYCLE_INFO_REG)); + LOG_E("BBC: busy=%08x pos=%08x rd=%08x wr=%08x end=%08x ctrl=%08x", + spacemit_jpu_read(jpu, MJPEG_BBC_BUSY_REG), + spacemit_jpu_read(jpu, MJPEG_BBC_CUR_POS_REG), + spacemit_jpu_read(jpu, MJPEG_BBC_RD_PTR_REG), + spacemit_jpu_read(jpu, MJPEG_BBC_WR_PTR_REG), + spacemit_jpu_read(jpu, MJPEG_BBC_END_ADDR_REG), + spacemit_jpu_read(jpu, MJPEG_BBC_STRM_CTRL_REG)); + LOG_E("GBU: ctrl=%08x word=%08x bit=%08x count=%08x MMU=%08x/%08x/%08x", + spacemit_jpu_read(jpu, MJPEG_GBU_CTRL_REG), + spacemit_jpu_read(jpu, MJPEG_GBU_WD_PTR_REG), + spacemit_jpu_read(jpu, MJPEG_GBU_FF_RPTR_REG), + spacemit_jpu_read(jpu, MJPEG_GBU_TT_CNT_REG), + spacemit_jpu_read(jpu, MJPEG_MMU_IRQ_STATUS), + spacemit_jpu_read(jpu, MJPEG_MMU_TBU_STATUS_BASE), + spacemit_jpu_read(jpu, MJPEG_MMU_TBU_STATUS_BASE + MJPEG_MMU_TBUx_STEP)); +} + +#if DBG_LVL >= DBG_LOG +static void spacemit_jpu_dump_config(struct spacemit_jpu *jpu, + const struct spacemit_jpu_map *map) +{ + LOG_D("DMA: stream=%08x->%08x/%u frame=%08x->%08x/%u MMU=%u", + (rt_uint32_t)map->stream_phys, (rt_uint32_t)map->stream_iova, + (unsigned int)map->stream_size, (rt_uint32_t)map->frame_phys, + (rt_uint32_t)map->frame_iova, (unsigned int)map->frame_size, + (unsigned int)jpu->mmu_enable); + LOG_D("core: mask=%08x ctrl=%08x pic=%08x mcu=%08x op=%08x dpbcfg=%08x", + spacemit_jpu_read(jpu, MJPEG_INTR_MASK_REG), + spacemit_jpu_read(jpu, MJPEG_PIC_CTRL_REG), + spacemit_jpu_read(jpu, MJPEG_PIC_SIZE_REG), + spacemit_jpu_read(jpu, MJPEG_MCU_INFO_REG), + spacemit_jpu_read(jpu, MJPEG_OP_INFO_REG), + spacemit_jpu_read(jpu, MJPEG_DPB_CONFIG_REG)); + LOG_D("DPB: y=%08x cb=%08x cr=%08x stride=%08x/%08x", + spacemit_jpu_read(jpu, MJPEG_DPB_BASE00_REG), + spacemit_jpu_read(jpu, MJPEG_DPB_BASE01_REG), + spacemit_jpu_read(jpu, MJPEG_DPB_BASE02_REG), + spacemit_jpu_read(jpu, MJPEG_DPB_YSTRIDE_REG), + spacemit_jpu_read(jpu, MJPEG_DPB_CSTRIDE_REG)); + LOG_D("BBC: base=%08x rd=%08x wr=%08x end=%08x pos=%08x ctrl=%08x", + spacemit_jpu_read(jpu, MJPEG_BBC_BAS_ADDR_REG), + spacemit_jpu_read(jpu, MJPEG_BBC_RD_PTR_REG), + spacemit_jpu_read(jpu, MJPEG_BBC_WR_PTR_REG), + spacemit_jpu_read(jpu, MJPEG_BBC_END_ADDR_REG), + spacemit_jpu_read(jpu, MJPEG_BBC_CUR_POS_REG), + spacemit_jpu_read(jpu, MJPEG_BBC_STRM_CTRL_REG)); + LOG_D("GBU: word=%08x bit=%08x range=%08x/%08x/%08x/%08x ctrl=%08x", + spacemit_jpu_read(jpu, MJPEG_GBU_WD_PTR_REG), + spacemit_jpu_read(jpu, MJPEG_GBU_FF_RPTR_REG), + spacemit_jpu_read(jpu, MJPEG_GBU_BBSR_REG), + spacemit_jpu_read(jpu, MJPEG_GBU_BBER_REG), + spacemit_jpu_read(jpu, MJPEG_GBU_BBIR_REG), + spacemit_jpu_read(jpu, MJPEG_GBU_BBHR_REG), + spacemit_jpu_read(jpu, MJPEG_GBU_CTRL_REG)); +} +#endif + +static rt_err_t spacemit_jpu_submit(struct spacemit_jpu *jpu, + struct jpu_decode_request *req) +{ + struct spacemit_jpu_map map; + rt_uint32_t reg[JPU_DECODE_REG_NUM] = { 0 }; + rt_err_t err; + + if ((err = spacemit_jpu_validate_decode(req)) != RT_EOK) + { + return err; + } + + if (spacemit_jpu_read(jpu, MJPEG_PIC_START_REG) != 0) + { + LOG_E("JPU busy"); + return -RT_EBUSY; + } + + req->irq_status = 0; + req->picture_status = 0; + req->error_mcu = 0; + req->cycles = 0; + + if ((err = spacemit_jpu_sw_reset(jpu)) != RT_EOK) + { + return err; + } + rt_completion_init(&jpu->completion); + jpu->error = RT_EOK; + jpu->irq_reason = 0; + + map.stream_phys = req->stream_phys; + map.stream_size = req->stream_capacity; + map.frame_phys = req->frame_phys; + map.frame_size = req->frame_capacity; + if ((err = spacemit_jpu_mmu_map(jpu, &map)) != RT_EOK) + { + LOG_E("failed to map decode buffers: %d", err); + goto _fail; + } + + spacemit_jpu_build_decode_regs(req, &map, reg); + + LOG_D("config: pic=%08x mcu=%08x ctrl=%08x entropy=%u stream=%u", + reg[MJPEG_PIC_SIZE_REG / sizeof(rt_uint32_t)], + reg[MJPEG_MCU_INFO_REG / sizeof(rt_uint32_t)], + reg[MJPEG_PIC_CTRL_REG / sizeof(rt_uint32_t)], + req->entropy_offset, req->stream_size); + + /* Keep this sequence aligned with JPU_DecSetRdPtrEx() and + * JPU_DecStartOneFrame() from the vendor library. */ + spacemit_jpu_write(jpu, MJPEG_BBC_RD_PTR_REG, + reg[MJPEG_BBC_RD_PTR_REG / sizeof(rt_uint32_t)]); + spacemit_jpu_write(jpu, MJPEG_INTR_MASK_REG, + reg[MJPEG_INTR_MASK_REG / sizeof(rt_uint32_t)]); + spacemit_jpu_write(jpu, MJPEG_BBC_WR_PTR_REG, + reg[MJPEG_BBC_WR_PTR_REG / sizeof(rt_uint32_t)]); + spacemit_jpu_write(jpu, MJPEG_BBC_END_ADDR_REG, + reg[MJPEG_BBC_END_ADDR_REG / sizeof(rt_uint32_t)]); + spacemit_jpu_write(jpu, MJPEG_BBC_BAS_ADDR_REG, + reg[MJPEG_BBC_BAS_ADDR_REG / sizeof(rt_uint32_t)]); + spacemit_jpu_write(jpu, MJPEG_GBU_TT_CNT_REG, 0); + spacemit_jpu_write(jpu, MJPEG_GBU_TT_CNT_REG + sizeof(rt_uint32_t), 0); + spacemit_jpu_write(jpu, MJPEG_PIC_ERRMB_REG, 0); + spacemit_jpu_write(jpu, MJPEG_PIC_CTRL_REG, + reg[MJPEG_PIC_CTRL_REG / sizeof(rt_uint32_t)]); + spacemit_jpu_write(jpu, MJPEG_PIC_SIZE_REG, + reg[MJPEG_PIC_SIZE_REG / sizeof(rt_uint32_t)]); + spacemit_jpu_write(jpu, MJPEG_OP_INFO_REG, + reg[MJPEG_OP_INFO_REG / sizeof(rt_uint32_t)]); + spacemit_jpu_write(jpu, MJPEG_MCU_INFO_REG, + reg[MJPEG_MCU_INFO_REG / sizeof(rt_uint32_t)]); + spacemit_jpu_write(jpu, MJPEG_DPB_CONFIG_REG, 0); + spacemit_jpu_write(jpu, MJPEG_RST_INTVAL_REG, + reg[MJPEG_RST_INTVAL_REG / sizeof(rt_uint32_t)]); + spacemit_jpu_write(jpu, MJPEG_SCL_INFO_REG, 0); + + if ((reg[MJPEG_PIC_CTRL_REG / sizeof(rt_uint32_t)] & RT_BIT(6)) && + (err = spacemit_jpu_load_huffman(jpu, &req->tables)) != RT_EOK) + { + LOG_E("invalid Huffman tables"); + goto _fail; + } + + spacemit_jpu_load_quant(jpu, &req->tables); + if ((err = spacemit_jpu_prepare_stream(jpu, + map.stream_iova, req->entropy_offset)) != RT_EOK) + { + goto _fail; + } + if (jpu->error != RT_EOK) + { + err = jpu->error; + goto _fail; + } + + spacemit_jpu_write(jpu, MJPEG_BBC_STRM_CTRL_REG, + reg[MJPEG_BBC_STRM_CTRL_REG / sizeof(rt_uint32_t)]); + spacemit_jpu_write(jpu, MJPEG_RST_INDEX_REG, 0); + spacemit_jpu_write(jpu, MJPEG_RST_COUNT_REG, 0); + spacemit_jpu_write(jpu, MJPEG_DPCM_DIFF_Y_REG, 0); + spacemit_jpu_write(jpu, MJPEG_DPCM_DIFF_CB_REG, 0); + spacemit_jpu_write(jpu, MJPEG_DPCM_DIFF_CR_REG, 0); + spacemit_jpu_write(jpu, MJPEG_GBU_FF_RPTR_REG, + (req->entropy_offset & 0xf) << 3); + spacemit_jpu_write(jpu, MJPEG_GBU_CTRL_REG, 3); + + spacemit_jpu_write(jpu, MJPEG_ROT_INFO_REG, 0); + spacemit_jpu_write(jpu, MJPEG_DPB_BASE00_REG, + reg[MJPEG_DPB_BASE00_REG / sizeof(rt_uint32_t)]); + spacemit_jpu_write(jpu, MJPEG_DPB_BASE01_REG, + reg[MJPEG_DPB_BASE01_REG / sizeof(rt_uint32_t)]); + spacemit_jpu_write(jpu, MJPEG_DPB_BASE02_REG, + reg[MJPEG_DPB_BASE02_REG / sizeof(rt_uint32_t)]); + spacemit_jpu_write(jpu, MJPEG_DPB_YSTRIDE_REG, + reg[MJPEG_DPB_YSTRIDE_REG / sizeof(rt_uint32_t)]); + spacemit_jpu_write(jpu, MJPEG_DPB_CSTRIDE_REG, + reg[MJPEG_DPB_CSTRIDE_REG / sizeof(rt_uint32_t)]); + spacemit_jpu_write(jpu, MJPEG_CLP_INFO_REG, 0); + + rt_hw_dsb(); +#if DBG_LVL >= DBG_LOG + spacemit_jpu_dump_config(jpu, &map); +#endif + + spacemit_jpu_write(jpu, MJPEG_PIC_START_REG, reg[MJPEG_PIC_START_REG / 4]); + + if (rt_completion_wait(&jpu->completion, + rt_tick_from_millisecond(JPU_TIMEOUT_MS)) != RT_EOK) + { + LOG_E("JPU timeout"); + spacemit_jpu_dump_timeout(jpu); + err = -RT_ETIMEOUT; + goto _fail; + } + + req->irq_status = jpu->irq_reason; + req->picture_status = spacemit_jpu_read(jpu, MJPEG_PIC_STATUS_REG); + req->error_mcu = spacemit_jpu_read(jpu, MJPEG_PIC_ERRMB_REG); + req->cycles = spacemit_jpu_read(jpu, MJPEG_CYCLE_INFO_REG); + + spacemit_jpu_disable_mmu_hw(jpu); + + if (jpu->error != RT_EOK) + { + spacemit_jpu_hard_reset(jpu); + } + + return jpu->error; + +_fail: + req->irq_status = jpu->irq_reason; + req->picture_status = spacemit_jpu_read(jpu, MJPEG_PIC_STATUS_REG); + req->error_mcu = spacemit_jpu_read(jpu, MJPEG_PIC_ERRMB_REG); + req->cycles = spacemit_jpu_read(jpu, MJPEG_CYCLE_INFO_REG); + spacemit_jpu_hard_reset(jpu); + spacemit_jpu_disable_mmu_hw(jpu); + return err; +} + +static rt_err_t spacemit_jpu_control(rt_device_t dev, int cmd, void *args) +{ + rt_err_t err = RT_EOK; + struct spacemit_jpu *jpu = raw_to_spacemit_jpu(dev); + + rt_mutex_take(&jpu->lock, RT_WAITING_FOREVER); + + switch (cmd) + { + case JPU_DECODE: + { + struct jpu_decode_request *req = args; + + if (!req) + { + err = -RT_EINVAL; + break; + } + + err = spacemit_jpu_submit(jpu, req); + break; + } + case JPU_QUERY_FRAME: + { + struct jpu_frame_info *frame = args; + + if (!frame) + { + err = -RT_EINVAL; + break; + } + + err = spacemit_jpu_query_frame(frame); + break; + } + case JPU_ALLOC_BUFFER: + { + struct jpu_buffer *buf = args; + + if (!buf) + { + err = -RT_EINVAL; + break; + } + + err = spacemit_jpu_buffer_alloc(jpu, buf); + break; + } + case JPU_FREE_BUFFER: + { + struct jpu_buffer *buf = args; + + if (!buf) + { + err = -RT_EINVAL; + break; + } + + err = spacemit_jpu_buffer_free(jpu, buf); + break; + } + case JPU_RESET: + spacemit_jpu_hard_reset(jpu); + spacemit_jpu_disable_mmu_hw(jpu); + break; + case JPU_GET_MMU_VERSION: + { + rt_uint32_t *version = args; + + if (!version) + { + err = -RT_EINVAL; + break; + } + + *version = spacemit_jpu_read(jpu, MJPEG_MMU_VERSION); + break; + } + default: + err = -RT_ENOSYS; + break; + } + + rt_mutex_release(&jpu->lock); + + return err; +} + +#ifdef RT_USING_DEVICE_OPS +static const struct rt_device_ops spacemit_jpu_ops = +{ + .control = spacemit_jpu_control, +}; +#endif + +static void spacemit_jpu_isr(int irqno, void *param) +{ + rt_uint32_t int_reason; + rt_uint32_t mmu_irq_status; + rt_bool_t completed = RT_FALSE; + struct spacemit_jpu *jpu = param; + + int_reason = spacemit_jpu_read(jpu, MJPEG_PIC_STATUS_REG); + if (int_reason != 0) + { + if (int_reason & RT_BIT(JPU_INT_DONE)) + { + spacemit_jpu_write(jpu, MJPEG_BBC_FLUSH_CMD_REG, 0); + } + + spacemit_jpu_write(jpu, MJPEG_PIC_STATUS_REG, int_reason); + } + + mmu_irq_status = spacemit_jpu_read(jpu, MJPEG_MMU_IRQ_STATUS); + if (mmu_irq_status != 0) + { + LOG_E("JPU MMU fault: status 0x%08x", mmu_irq_status); + + if (mmu_irq_status & 0xFF) + { + spacemit_jpu_set_bits(jpu, MJPEG_MMU_ERROR_CLEAR, RT_BIT(1)); + } + + spacemit_jpu_write(jpu, MJPEG_MMU_IRQ_STATUS, mmu_irq_status); + jpu->error = -RT_EIO; + completed = RT_TRUE; + } + + if (int_reason != 0) + { + jpu->irq_reason |= int_reason; + + if (int_reason & JPU_INT_FATAL_MASK) + { + LOG_E("JPU error, status = 0x%08x", int_reason); + jpu->error = -RT_EIO; + } + + if (int_reason & (RT_BIT(JPU_INT_DONE) | JPU_INT_FATAL_MASK)) + { + completed = RT_TRUE; + } + } + + if (completed) + { + rt_completion_done(&jpu->completion); + } +} + +static struct rt_reset_control *spacemit_jpu_get_reset(struct rt_device *dev, const char *name) +{ + struct rt_reset_control *rstc = rt_reset_control_get_by_name(dev, name); + + if (rt_is_err(rstc)) + { + LOG_W("no %s reset, err = %d", name, rt_ptr_err(rstc)); + return RT_NULL; + } + + return rstc; +} + +static void spacemit_jpu_free(struct spacemit_jpu *jpu) +{ + void *ttb_va = RT_NULL; + rt_ubase_t ttb_pa = 0; + + if (jpu->tbu[0].ttb_va) + { + ttb_va = jpu->tbu[0].ttb_va; + ttb_pa = jpu->tbu[0].ttb_pa; + } + + if (ttb_va && jpu->dev) + { + rt_dma_free_coherent(jpu->dev, MAX_SIZE_PER_TTB * TBU_INSTANCES_NUM, + ttb_va, ttb_pa); + } + + if (jpu->regs) + { + rt_iounmap(jpu->regs); + } + + spacemit_jpu_clk_disable(jpu); + + if (!rt_is_err_or_null(jpu->cclk)) + { + rt_clk_put(jpu->cclk); + } + if (!rt_is_err_or_null(jpu->aclk)) + { + rt_clk_put(jpu->aclk); + } + if (!rt_is_err_or_null(jpu->iclk)) + { + rt_clk_put(jpu->iclk); + } + + if (!rt_is_err_or_null(jpu->jpg_reset)) + { + rt_reset_control_put(jpu->jpg_reset); + } + if (!rt_is_err_or_null(jpu->lcd_mclk_reset)) + { + rt_reset_control_put(jpu->lcd_mclk_reset); + } + if (!rt_is_err_or_null(jpu->isp_ci_reset)) + { + rt_reset_control_put(jpu->isp_ci_reset); + } + if (!rt_is_err_or_null(jpu->freset)) + { + rt_reset_control_put(jpu->freset); + } + if (!rt_is_err_or_null(jpu->sreset)) + { + rt_reset_control_put(jpu->sreset); + } + + rt_free(jpu); +} + +static rt_err_t spacemit_jpu_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + rt_uint32_t chip_id = 0; + const char *dev_name; + struct rt_device *dev = &pdev->parent; + struct spacemit_jpu *jpu = rt_calloc(1, sizeof(*jpu)); + void *ttb_va = RT_NULL; + rt_ubase_t ttb_pa = 0; + int i; + + if (!jpu) + { + return -RT_ENOMEM; + } + + jpu->dev = dev; + + jpu->regs = rt_dm_dev_iomap(dev, 0); + if (!jpu->regs) + { + err = -RT_EIO; + goto _fail; + } + + if (!rt_dm_dev_prop_read_u32(dev, "page-size", &jpu->page_size)) + { + jpu->page_size *= 1024; + } + else + { + jpu->page_size = 4096; + } + + jpu->cclk = rt_clk_get_by_name(dev, "cclk"); + if (rt_is_err(jpu->cclk)) + { + err = rt_ptr_err(jpu->cclk); + goto _fail; + } + + jpu->aclk = rt_clk_get_by_name(dev, "aclk"); + if (rt_is_err(jpu->aclk)) + { + err = rt_ptr_err(jpu->aclk); + goto _fail; + } + + jpu->iclk = rt_clk_get_by_name(dev, "iclk"); + if (rt_is_err(jpu->iclk)) + { + err = rt_ptr_err(jpu->iclk); + goto _fail; + } + + if ((err = spacemit_jpu_clk_enable(jpu)) != RT_EOK) + { + goto _fail; + } + + jpu->jpg_reset = spacemit_jpu_get_reset(dev, "jpg_reset"); + jpu->lcd_mclk_reset = spacemit_jpu_get_reset(dev, "lcd_mclk_reset"); + jpu->isp_ci_reset = spacemit_jpu_get_reset(dev, "isp_ci_reset"); + jpu->freset = spacemit_jpu_get_reset(dev, "freset"); + jpu->sreset = spacemit_jpu_get_reset(dev, "sreset"); + spacemit_jpu_reset_deassert_all(jpu); + + jpu->irq = rt_dm_dev_get_irq(dev, 0); + if (jpu->irq < 0) + { + err = jpu->irq; + goto _fail; + } + + ttb_va = rt_dma_alloc_coherent(dev, MAX_SIZE_PER_TTB * TBU_INSTANCES_NUM, &ttb_pa); + if (!ttb_va) + { + LOG_E("No memory for TBU page tables"); + err = -RT_ENOMEM; + goto _fail; + } + rt_memset(ttb_va, 0, MAX_SIZE_PER_TTB * TBU_INSTANCES_NUM); + + for (i = 0; i < TBU_INSTANCES_NUM; i++) + { + jpu->tbu[i].ttb_va = (rt_uint32_t *)((rt_uint8_t *)ttb_va + i * MAX_SIZE_PER_TTB); + jpu->tbu[i].ttb_pa = ttb_pa + i * MAX_SIZE_PER_TTB; + } + + jpu->va_base = JPU_TBU_BASE_VA; + jpu->time_out_cycs = DEFAULT_TIMEOUT_CYCS; + rt_spin_lock_init(&jpu->hw_lock); + + if (!rt_dm_dev_prop_read_u32(dev, "jpu,chip-id", &chip_id)) + { + rt_dm_dev_set_name(&jpu->parent, "jpu%u", chip_id); + } + else + { + rt_dm_dev_set_name_auto(&jpu->parent, "jpu"); + } + dev_name = rt_dm_dev_get_name(&jpu->parent); + + dev->user_data = jpu; + + jpu->parent.type = RT_Device_Class_Char; +#ifdef RT_USING_DEVICE_OPS + jpu->parent.ops = &spacemit_jpu_ops; +#else + jpu->parent.control = spacemit_jpu_control; +#endif + + if ((err = rt_device_register(&jpu->parent, dev_name, RT_DEVICE_FLAG_DEACTIVATE))) + { + goto _fail; + } + + rt_mutex_init(&jpu->lock, dev_name, RT_IPC_FLAG_PRIO); + rt_completion_init(&jpu->completion); + + rt_hw_interrupt_install(jpu->irq, spacemit_jpu_isr, jpu, "jpu"); + rt_hw_interrupt_umask(jpu->irq); + + LOG_I("Chip Media JPU probed, MMU version 0x%08x", + spacemit_jpu_read(jpu, MJPEG_MMU_VERSION)); + + return RT_EOK; + +_fail: + spacemit_jpu_free(jpu); + + return err; +} + +static rt_err_t spacemit_jpu_remove(struct rt_platform_device *pdev) +{ + struct spacemit_jpu *jpu = pdev->parent.user_data; + + rt_hw_interrupt_mask(jpu->irq); + rt_pic_detach_irq(jpu->irq, jpu); + + rt_device_unregister(&jpu->parent); + + spacemit_jpu_free(jpu); + + return RT_EOK; +} + +static const struct rt_ofw_node_id spacemit_jpu_ofw_ids[] = +{ + { .compatible = "chip-media, jpu" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver spacemit_jpu_driver = +{ + .name = "spacemit-jpu", + .ids = spacemit_jpu_ofw_ids, + + .probe = spacemit_jpu_probe, + .remove = spacemit_jpu_remove, +}; +RT_PLATFORM_DRIVER_EXPORT(spacemit_jpu_driver); diff --git a/bsp/spacemit/dm/soc/k1x-rproc.c b/bsp/spacemit/dm/soc/k1x-rproc.c new file mode 100644 index 000000000000..bdf60330c7a9 --- /dev/null +++ b/bsp/spacemit/dm/soc/k1x-rproc.c @@ -0,0 +1,1557 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#define DBG_TAG "soc.k1x-rproc" +#define DBG_LVL DBG_INFO +#include + +#include +#include + +#define K1X_MBOX_VQ0_ID 0 +#define K1X_MBOX_VQ1_ID 1 + +#define K1X_RPMSG_VRING0_REGION 2 +#define K1X_RPMSG_VRING1_REGION 3 +#define K1X_RPMSG_BUFFER_REGION 4 +#define K1X_RPMSG_RSC_REGION 5 + +#define K1X_RPMSG_VRING0_NAME "vdev0vring0" +#define K1X_RPMSG_VRING1_NAME "vdev0vring1" +#define K1X_RPMSG_BUFFER_NAME "vdev0buffer" +#define K1X_RPMSG_RSC_NAME "rsc_table" + +#define K1X_RPMSG_QUEUE_NUM 256 +#define K1X_RPMSG_BUFFER_SIZE 512 +#define K1X_RPMSG_MAX_MEMORY_REGIONS 16 +#define K1X_RPMSG_VRING0_NOTIFY_ID 0 +#define K1X_RPMSG_VRING1_NOTIFY_ID 1 +#define K1X_RPMSG_VIRTIO_VENDOR 0x53504d54U + +#define K1X_RSC_VDEV 3 +#define K1X_VIRTIO_ID_RPMSG 7 +#define K1X_VIRTIO_RPMSG_F_NS RT_BIT(0) + +#define FW_BOOT_ENTRY_REG_OFFSET 0x88 +#define FW_BOOTUP_REG_OFFSET 0x30 +#define FW_AON_PER_CLK_RST_CTL_REG 0x2c + +#define FW_DDR_REGMAP_BASE_REG_OFFSET 0xc0 + +static char *const mb_name[] = +{ + [K1X_MBOX_VQ0_ID] = "vq0", + [K1X_MBOX_VQ1_ID] = "vq1", +}; + +struct spacemit_rproc; + +struct spacemit_rproc_mbox +{ + struct rt_mbox_client parent; + + struct rt_mbox_chan *chan; + + int vq_id; + struct spacemit_rproc *rproc; +}; + +struct spacemit_rpmsg_region +{ + void *va; + rt_uint64_t pa; + rt_uint64_t size; + rt_uint32_t da; +}; + +struct spacemit_fw_rsc_vdev_vring +{ + rt_uint32_t da; + rt_uint32_t align; + rt_uint32_t num; + rt_uint32_t notifyid; + rt_uint32_t reserved; +}; + +struct spacemit_fw_rsc_vdev +{ + rt_uint32_t type; + rt_uint32_t id; + rt_uint32_t notifyid; + rt_uint32_t dfeatures; + rt_uint32_t gfeatures; + rt_uint32_t config_len; + rt_uint8_t status; + rt_uint8_t num_of_vrings; + rt_uint8_t reserved[2]; + struct spacemit_fw_rsc_vdev_vring vring[2]; +}; + +struct spacemit_resource_table +{ + rt_uint32_t version; + rt_uint32_t num; + rt_uint32_t reserved[2]; + rt_uint32_t offset[1]; +}; + +struct spacemit_rproc +{ + struct rt_device *dev; + + void *bootc_mem_base; + void *sysctrl_mem_base; + + struct rt_clk *core_clk; + struct rt_clk *apb_clk; + struct rt_reset_control *core_rstc; + + rt_uint32_t apb_clk_rate; + rt_uint32_t ddr_remap_base; + rt_uint32_t fw_entry_point; + char fw_name[32]; + struct spacemit_rproc_mbox mb[RT_ARRAY_SIZE(mb_name)]; + + struct spacemit_rpmsg_region vring_region[2]; + struct spacemit_rpmsg_region buffer_region; + struct spacemit_rpmsg_region rsc_region; + struct rt_virtio_device vdev; + struct rt_virtqueue *vqs[2]; + rt_uint8_t virtio_status; + rt_uint64_t virtio_features; + rt_uint32_t vring_notify[2]; + rt_uint32_t vring_align[2]; + rt_uint16_t vring_num[2]; + rt_bool_t virtio_registered; + struct rt_spinlock dma_lock; + rt_uint8_t *dma_slots; + rt_size_t dma_slot_count; + rt_uint32_t rsc_vdev_offset; + rt_bool_t rpmsg_ready; + rt_bool_t firmware_started; + rt_bool_t boot_requested; + rt_bool_t clocks_enabled; + rt_bool_t worker_stop; + rt_bool_t worker_started; + rt_bool_t rpmsg_sem_inited; + rt_bool_t rpmsg_mutex_inited; + struct rt_semaphore rpmsg_sem; + struct rt_mutex rpmsg_mutex; + rt_thread_t rpmsg_thread; + rt_uint32_t notify_count[RT_ARRAY_SIZE(mb_name)]; + rt_uint32_t mbox_count[RT_ARRAY_SIZE(mb_name)]; +}; + +static struct spacemit_rproc *spacemit_rproc_global; +static RT_DEFINE_SPINLOCK(spacemit_rpmsg_lock); + +static rt_err_t spacemit_rproc_boot(struct spacemit_rproc *rproc); +static rt_err_t spacemit_rproc_stop(struct spacemit_rproc *rproc); +static void spacemit_rpmsg_notify(struct spacemit_rproc *rproc, int vq_id); + +static struct spacemit_rproc *spacemit_virtio_to_rproc( + struct rt_virtio_device *vdev) +{ + return rt_container_of(vdev, struct spacemit_rproc, vdev); +} + +static struct spacemit_fw_rsc_vdev *spacemit_rproc_rsc_vdev( + struct spacemit_rproc *rproc) +{ + struct spacemit_resource_table *table; + + if (!rproc || !rproc->rsc_region.va || + rproc->rsc_vdev_offset + sizeof(struct spacemit_fw_rsc_vdev) > + rproc->rsc_region.size) + { + return RT_NULL; + } + + table = rproc->rsc_region.va; + + return (void *)((char *)table + rproc->rsc_vdev_offset); +} + +static rt_err_t spacemit_rproc_dma_sync_out_data(struct rt_device *dev, + void *data, rt_size_t size, rt_ubase_t *dma_handle, + rt_ubase_t flags) +{ + rt_ubase_t level; + rt_size_t slot = 0; + rt_bool_t found = RT_FALSE; + struct rt_virtio_device *vdev = + rt_container_of(dev, struct rt_virtio_device, parent); + struct spacemit_rproc *rproc = spacemit_virtio_to_rproc(vdev); + + if (!data || !dma_handle || !rproc->dma_slots || + !rproc->dma_slot_count || size > K1X_RPMSG_BUFFER_SIZE) + { + return -RT_EINVAL; + } + + level = rt_spin_lock_irqsave(&rproc->dma_lock); + for (slot = 0; slot < rproc->dma_slot_count; ++slot) + { + if (!rproc->dma_slots[slot]) + { + rproc->dma_slots[slot] = 1; + found = RT_TRUE; + break; + } + } + rt_spin_unlock_irqrestore(&rproc->dma_lock, level); + + if (!found) + { + return -RT_EFULL; + } + + rt_memset((char *)rproc->buffer_region.va + + slot * K1X_RPMSG_BUFFER_SIZE, 0, K1X_RPMSG_BUFFER_SIZE); + rt_memcpy((char *)rproc->buffer_region.va + + slot * K1X_RPMSG_BUFFER_SIZE, data, size); + rt_hw_wmb(); + + *dma_handle = rproc->buffer_region.da + + slot * K1X_RPMSG_BUFFER_SIZE; + + return RT_EOK; +} + +static rt_err_t spacemit_rproc_dma_sync_in_data(struct rt_device *dev, + void *out_data, rt_size_t size, rt_ubase_t dma_handle, + rt_ubase_t flags) +{ + rt_ubase_t level; + rt_uint64_t offset; + rt_size_t slot; + struct rt_virtio_device *vdev = + rt_container_of(dev, struct rt_virtio_device, parent); + struct spacemit_rproc *rproc = spacemit_virtio_to_rproc(vdev); + + if (!out_data || !rproc->dma_slots || + dma_handle < rproc->buffer_region.da) + { + return -RT_EINVAL; + } + + offset = dma_handle - rproc->buffer_region.da; + if (offset >= rproc->buffer_region.size || + offset % K1X_RPMSG_BUFFER_SIZE) + { + return -RT_EINVAL; + } + + slot = offset / K1X_RPMSG_BUFFER_SIZE; + if (slot >= rproc->dma_slot_count) + { + return -RT_EINVAL; + } + + rt_hw_rmb(); + rt_memcpy(out_data, (char *)rproc->buffer_region.va + offset, + rt_min_t(rt_size_t, size, K1X_RPMSG_BUFFER_SIZE)); + + level = rt_spin_lock_irqsave(&rproc->dma_lock); + rproc->dma_slots[slot] = 0; + rt_spin_unlock_irqrestore(&rproc->dma_lock, level); + + return RT_EOK; +} + +static const struct rt_dma_map_ops spacemit_rproc_dma_ops = +{ + .sync_out_data = spacemit_rproc_dma_sync_out_data, + .sync_in_data = spacemit_rproc_dma_sync_in_data, +}; + +static rt_err_t spacemit_rproc_virtio_get_status( + struct rt_virtio_device *vdev, rt_uint8_t *out_status) +{ + struct spacemit_rproc *rproc = spacemit_virtio_to_rproc(vdev); + + *out_status = rproc->virtio_status; + + return RT_EOK; +} + +static rt_err_t spacemit_rproc_virtio_set_status( + struct rt_virtio_device *vdev, rt_uint8_t status) +{ + struct spacemit_fw_rsc_vdev *rsc_vdev; + struct spacemit_rproc *rproc = spacemit_virtio_to_rproc(vdev); + + rproc->virtio_status = status; + rsc_vdev = spacemit_rproc_rsc_vdev(rproc); + if (rsc_vdev) + { + rsc_vdev->status = status; + rt_hw_wmb(); + } + + return RT_EOK; +} + +static rt_err_t spacemit_rproc_virtio_get_features( + struct rt_virtio_device *vdev, rt_uint64_t *out_features) +{ + struct spacemit_rproc *rproc = spacemit_virtio_to_rproc(vdev); + + *out_features = rproc->virtio_features; + + return RT_EOK; +} + +static rt_err_t spacemit_rproc_virtio_set_features( + struct rt_virtio_device *vdev) +{ + struct spacemit_fw_rsc_vdev *rsc_vdev; + struct spacemit_rproc *rproc = spacemit_virtio_to_rproc(vdev); + + rsc_vdev = spacemit_rproc_rsc_vdev(rproc); + if (rsc_vdev) + { + rsc_vdev->gfeatures = rt_cpu_to_le32( + (rt_uint32_t)vdev->features); + rt_hw_wmb(); + } + + return RT_EOK; +} + +static rt_err_t spacemit_rproc_virtio_get_config( + struct rt_virtio_device *vdev, rt_uint32_t offset, void *dst, + int length) +{ + rt_memset(dst, 0, length); + + return RT_EOK; +} + +static rt_err_t spacemit_rproc_virtio_set_config( + struct rt_virtio_device *vdev, rt_uint32_t offset, + const void *src, int length) +{ + return RT_EOK; +} + +static rt_bool_t spacemit_rproc_virtio_notify(struct rt_virtqueue *vq) +{ + static const char kick[] = "kick"; + rt_ubase_t level; + struct spacemit_rproc *rproc = spacemit_virtio_to_rproc(vq->vdev); + + if (!rproc->firmware_started) + { + level = rt_spin_lock_irqsave(&spacemit_rpmsg_lock); + rproc->boot_requested = RT_TRUE; + rt_spin_unlock_irqrestore(&spacemit_rpmsg_lock, level); + + if (rproc->rpmsg_sem_inited) + { + rt_sem_release(&rproc->rpmsg_sem); + } + + LOG_D("RCPU firmware boot requested by RPMsg vq%d", vq->index); + + return RT_TRUE; + } + + if (rproc->rpmsg_ready && rproc->firmware_started && + vq->index < RT_ARRAY_SIZE(rproc->mb)) + { + ++rproc->notify_count[vq->index]; + rt_mbox_send(rproc->mb[vq->index].chan, kick, + RT_WAITING_FOREVER); + } + + return RT_TRUE; +} + +static rt_err_t spacemit_rproc_virtio_install_vqs( + struct rt_virtio_device *vdev, int vqs_nr, + struct rt_virtqueue *vqs[], const char *names[], + rt_virtqueue_callback cbs[]) +{ + struct spacemit_rproc *rproc = spacemit_virtio_to_rproc(vdev); + + if (vqs_nr != RT_ARRAY_SIZE(rproc->vqs)) + { + return -RT_EINVAL; + } + + for (int i = 0; i < vqs_nr; ++i) + { + rt_uint32_t align = rproc->vring_align[i] ? : + ARCH_PAGE_SIZE; + rt_uint16_t num = rproc->vring_num[i] ? : + K1X_RPMSG_QUEUE_NUM; + struct rt_virtqueue_formula formula = + { + .page = rproc->vring_region[i].va, + }; + + if (!names[i]) + { + vqs[i] = RT_NULL; + continue; + } + + if (rproc->vring_region[i].size < + virtq_size(RT_NULL, num, align)) + { + rt_virtio_virtqueue_release(vdev); + return -RT_EINVAL; + } + + vqs[i] = rt_virtqueue_create(vdev, names[i], i, num, align, + spacemit_rproc_virtio_notify, cbs[i], &formula); + if (!vqs[i]) + { + rt_virtio_virtqueue_release(vdev); + return -RT_ENOMEM; + } + + rproc->vqs[i] = vqs[i]; + } + + return RT_EOK; +} + +static rt_err_t spacemit_rproc_virtio_release_vqs( + struct rt_virtio_device *vdev) +{ + struct rt_virtqueue *vq, *next; + struct spacemit_rproc *rproc = spacemit_virtio_to_rproc(vdev); + + rt_list_for_each_entry_safe(vq, next, &vdev->vq_node, list) + { + if (vq->index < RT_ARRAY_SIZE(rproc->vqs)) + { + rproc->vqs[vq->index] = RT_NULL; + } + rt_virtqueue_delete(vdev, vq); + } + + return RT_EOK; +} + +static rt_err_t spacemit_rproc_virtio_control_vqs( + struct rt_virtio_device *vdev, rt_uint32_t cfg, void *data) +{ + return -RT_ENOSYS; +} + +static rt_err_t spacemit_rproc_virtio_generation( + struct rt_virtio_device *vdev, rt_uint32_t *out_counter) +{ + *out_counter = 0; + + return RT_EOK; +} + +static rt_err_t spacemit_rproc_virtio_reset( + struct rt_virtio_device *vdev) +{ + struct spacemit_rproc *rproc = spacemit_virtio_to_rproc(vdev); + + rproc->virtio_status = 0; + if (rproc->dma_slots) + { + rt_memset(rproc->dma_slots, 0, + rproc->dma_slot_count * sizeof(rproc->dma_slots[0])); + } + spacemit_rproc_virtio_set_status(vdev, 0); + + return RT_EOK; +} + +static const struct rt_virtio_transport spacemit_rproc_virtio_transport = +{ + .get_status = spacemit_rproc_virtio_get_status, + .set_status = spacemit_rproc_virtio_set_status, + .get_features = spacemit_rproc_virtio_get_features, + .set_features = spacemit_rproc_virtio_set_features, + .get_config = spacemit_rproc_virtio_get_config, + .set_config = spacemit_rproc_virtio_set_config, + .install_vqs = spacemit_rproc_virtio_install_vqs, + .release_vqs = spacemit_rproc_virtio_release_vqs, + .control_vqs = spacemit_rproc_virtio_control_vqs, + .generation = spacemit_rproc_virtio_generation, + .reset = spacemit_rproc_virtio_reset, +}; + +static void spacemit_rpmsg_notify(struct spacemit_rproc *rproc, int vq_id) +{ + static const char kick[] = "kick"; + + if (rproc->rpmsg_ready && rproc->firmware_started && + vq_id < RT_ARRAY_SIZE(rproc->mb)) + { + ++rproc->notify_count[vq_id]; + rt_mbox_send(rproc->mb[vq_id].chan, kick, RT_WAITING_FOREVER); + } +} + +static rt_err_t spacemit_rpmsg_worker_start(struct spacemit_rproc *rproc) +{ + rt_err_t err; + rt_ubase_t level; + + if (!rproc || !rproc->rpmsg_thread) + { + return -RT_EINVAL; + } + + level = rt_spin_lock_irqsave(&spacemit_rpmsg_lock); + if (rproc != spacemit_rproc_global || rproc->worker_started) + { + rt_spin_unlock_irqrestore(&spacemit_rpmsg_lock, level); + return RT_EOK; + } + rt_spin_unlock_irqrestore(&spacemit_rpmsg_lock, level); + + err = rt_thread_startup(rproc->rpmsg_thread); + if (err == RT_EOK) + { + level = rt_spin_lock_irqsave(&spacemit_rpmsg_lock); + if (rproc == spacemit_rproc_global) + { + rproc->worker_started = RT_TRUE; + } + rt_spin_unlock_irqrestore(&spacemit_rpmsg_lock, level); + + rt_sem_release(&rproc->rpmsg_sem); + LOG_D("RPMsg worker started"); + } + + return err; +} + +static void spacemit_rpmsg_pump(struct spacemit_rproc *rproc) +{ + if (!rproc || !rproc->rpmsg_ready || !rproc->firmware_started || + !rproc->rpmsg_mutex_inited) + { + return; + } + + if (rt_mutex_take(&rproc->rpmsg_mutex, RT_WAITING_NO) != RT_EOK) + { + return; + } + + for (int i = 0; i < RT_ARRAY_SIZE(rproc->vqs); ++i) + { + if (rproc->vqs[i]) + { + rt_virtqueue_isr(i, rproc->vqs[i]); + } + } + + rt_mutex_release(&rproc->rpmsg_mutex); +} + +static void spacemit_rpmsg_worker(void *parameter) +{ + struct spacemit_rproc *rproc = parameter; + + while (!rproc->worker_stop) + { + rt_bool_t boot_requested; + + rt_sem_take(&rproc->rpmsg_sem, rt_tick_from_millisecond(10)); + + boot_requested = rproc->boot_requested; + if (boot_requested && !rproc->firmware_started) + { + rt_err_t err; + rt_ubase_t level; + + level = rt_spin_lock_irqsave(&spacemit_rpmsg_lock); + rproc->boot_requested = RT_FALSE; + rt_spin_unlock_irqrestore(&spacemit_rpmsg_lock, level); + + err = spacemit_rproc_boot(rproc); + if (err) + { + LOG_E("Boot RCPU firmware failed: %s", + rt_strerror(err)); + } + else + { + spacemit_rpmsg_notify(rproc, K1X_MBOX_VQ0_ID); + spacemit_rpmsg_notify(rproc, K1X_MBOX_VQ1_ID); + } + } + + spacemit_rpmsg_pump(rproc); + } +} + +static void spacemit_rpmsg_worker_destroy(struct spacemit_rproc *rproc) +{ + rt_thread_t thread = rproc->rpmsg_thread; + + if (!thread) + { + return; + } + + rproc->worker_stop = RT_TRUE; + if (rproc->worker_started) + { + rt_sem_release(&rproc->rpmsg_sem); + rt_thread_delete(thread); + } + else + { + rt_timer_detach(&thread->thread_timer); +#ifdef RT_USING_HW_STACK_GUARD + RT_KERNEL_FREE(thread->stack_buf); +#else + RT_KERNEL_FREE(thread->stack_addr); +#endif + rt_object_delete((rt_object_t)thread); + } + + rproc->rpmsg_thread = RT_NULL; + rproc->worker_started = RT_FALSE; +} + +static rt_err_t spacemit_rpmsg_map_region_node(struct rt_ofw_node *np, + const char *label, int index, struct spacemit_rpmsg_region *region) +{ + rt_err_t err; + + if (!np) + { + return -RT_EINVAL; + } + + err = rt_ofw_get_address(np, 0, ®ion->pa, ®ion->size); + if (!err && rt_ofw_prop_read_u32(np, "da_base", ®ion->da)) + { + region->da = (rt_uint32_t)region->pa; + } + if (err) + { + rt_ofw_node_put(np); + return err; + } + + region->va = rt_ioremap_nocache((void *)(rt_ubase_t)region->pa, + region->size); + if (!region->va) + { + rt_ofw_node_put(np); + return -RT_ENOMEM; + } + + LOG_D("RPMsg %s region: %s idx=%d pa=%p da=0x%08x size=%p va=%p", + label, rt_ofw_node_full_name(np), index, + (void *)(rt_ubase_t)region->pa, region->da, + (void *)(rt_ubase_t)region->size, region->va); + + rt_ofw_node_put(np); + + return RT_EOK; +} + +static rt_err_t spacemit_rpmsg_map_region(struct spacemit_rproc *rproc, + const char *tag, int fallback_index, + struct spacemit_rpmsg_region *region) +{ + struct rt_ofw_node *np; + + for (int i = 0; i < K1X_RPMSG_MAX_MEMORY_REGIONS; ++i) + { + np = rt_ofw_parse_phandle(rproc->dev->ofw_node, + "memory-region", i); + if (!np) + { + break; + } + + if (rt_ofw_node_tag_equ(np, tag)) + { + return spacemit_rpmsg_map_region_node(np, tag, i, region); + } + + rt_ofw_node_put(np); + } + + np = rt_ofw_parse_phandle(rproc->dev->ofw_node, + "memory-region", fallback_index); + if (!np) + { + return -RT_EINVAL; + } + + LOG_W("RPMsg %s reserved memory not found by name, fallback to memory-region[%d]", + tag, fallback_index); + + return spacemit_rpmsg_map_region_node(np, tag, fallback_index, region); +} + +static rt_err_t spacemit_rpmsg_load_resource(const char *fw_name, + struct spacemit_rpmsg_region *region) +{ + rt_ubase_t base; + rt_size_t size; + Elf32_Ehdr *ehdr; + Elf32_Phdr *phdr; + + if (!spacemit_firmware_find(fw_name, &base, &size)) + { + return -RT_EEMPTY; + } + + ehdr = (Elf32_Ehdr *)base; + if (size < sizeof(*ehdr) || + rt_memcmp(ehdr->e_ident, ELFMAG, SELFMAG) || + ehdr->e_ident[EI_CLASS] != ELFCLASS32 || + ehdr->e_phoff + ehdr->e_phnum * sizeof(*phdr) > size) + { + return -RT_EINVAL; + } + + phdr = (Elf32_Phdr *)(base + ehdr->e_phoff); + for (int i = 0; i < ehdr->e_phnum; ++i) + { + rt_ubase_t offset; + rt_size_t copy; + + if (phdr[i].p_type != PT_LOAD || region->da < phdr[i].p_paddr || + region->da >= phdr[i].p_paddr + phdr[i].p_memsz) + { + continue; + } + + offset = region->da - phdr[i].p_paddr; + if (offset >= phdr[i].p_filesz || + phdr[i].p_offset + phdr[i].p_filesz > size) + { + return -RT_EINVAL; + } + + copy = rt_min_t(rt_size_t, phdr[i].p_filesz - offset, + region->size); + rt_memset(region->va, 0, region->size); + rt_memcpy(region->va, (void *)(base + phdr[i].p_offset + offset), + copy); + return RT_EOK; + } + + return -RT_EEMPTY; +} + +static rt_err_t spacemit_rproc_da_to_pa(struct spacemit_rproc *rproc, + rt_uint32_t da, rt_uint64_t *out_pa) +{ + struct rt_ofw_node *np; + + for (int i = 0; i < K1X_RPMSG_MAX_MEMORY_REGIONS; ++i) + { + rt_uint32_t da_base; + rt_uint64_t pa, size, offset; + + np = rt_ofw_parse_phandle(rproc->dev->ofw_node, + "memory-region", i); + if (!np) + { + break; + } + + if (rt_ofw_get_address(np, 0, &pa, &size)) + { + rt_ofw_node_put(np); + continue; + } + + if (rt_ofw_prop_read_u32(np, "da_base", &da_base)) + { + da_base = (rt_uint32_t)pa; + } + + if (da >= da_base) + { + offset = da - da_base; + if (offset < size) + { + *out_pa = pa + offset; + LOG_D("RCPU DA 0x%08x -> PA %p by %s idx=%d", + da, (void *)(rt_ubase_t)*out_pa, + rt_ofw_node_full_name(np), i); + rt_ofw_node_put(np); + + return RT_EOK; + } + } + + rt_ofw_node_put(np); + } + + return -RT_EINVAL; +} + +static rt_err_t spacemit_rproc_clear_carveouts(struct spacemit_rproc *rproc) +{ + struct rt_ofw_node *np; + + for (int i = 0; i < K1X_RPMSG_MAX_MEMORY_REGIONS; ++i) + { + void *va; + rt_uint64_t pa, size; + + np = rt_ofw_parse_phandle(rproc->dev->ofw_node, + "memory-region", i); + if (!np) + { + break; + } + + if (rt_ofw_get_address(np, 0, &pa, &size)) + { + rt_ofw_node_put(np); + continue; + } + + va = rt_ioremap_nocache((void *)(rt_ubase_t)pa, size); + if (!va) + { + LOG_E("Map RCPU carveout %s failed", + rt_ofw_node_full_name(np)); + rt_ofw_node_put(np); + return -RT_ENOMEM; + } + + LOG_D("Clear RCPU carveout %s pa=%p size=%p", + rt_ofw_node_full_name(np), (void *)(rt_ubase_t)pa, + (void *)(rt_ubase_t)size); + rt_memset(va, 0, size); + rt_hw_wmb(); + rt_iounmap(va); + rt_ofw_node_put(np); + } + + return RT_EOK; +} + +static rt_err_t spacemit_rpmsg_reset_transport(struct spacemit_rproc *rproc, + const char *fw_name) +{ + rt_err_t err; + struct spacemit_resource_table *table; + struct spacemit_fw_rsc_vdev *vdev; + + if (rproc->vring_region[0].size < + virtq_size(RT_NULL, K1X_RPMSG_QUEUE_NUM, ARCH_PAGE_SIZE) || + rproc->vring_region[1].size < + virtq_size(RT_NULL, K1X_RPMSG_QUEUE_NUM, ARCH_PAGE_SIZE) || + rproc->buffer_region.size < + K1X_RPMSG_QUEUE_NUM * K1X_RPMSG_BUFFER_SIZE * 2) + { + return -RT_EINVAL; + } + + if ((err = spacemit_rpmsg_load_resource(fw_name, + &rproc->rsc_region))) + { + return err; + } + + table = rproc->rsc_region.va; + if (rt_le32_to_cpu(table->num) != 1 || + rt_le32_to_cpu(table->offset[0]) + sizeof(*vdev) > + rproc->rsc_region.size) + { + return -RT_EINVAL; + } + rproc->rsc_vdev_offset = rt_le32_to_cpu(table->offset[0]); + vdev = (void *)((char *)table + rproc->rsc_vdev_offset); + if (rt_le32_to_cpu(vdev->type) != K1X_RSC_VDEV || + rt_le32_to_cpu(vdev->id) != K1X_VIRTIO_ID_RPMSG || + vdev->num_of_vrings != 2) + { + return -RT_EINVAL; + } + + rt_memset(rproc->vring_region[0].va, 0, + rproc->vring_region[0].size); + rt_memset(rproc->vring_region[1].va, 0, + rproc->vring_region[1].size); + rt_memset(rproc->buffer_region.va, 0, rproc->buffer_region.size); + + for (int i = 0; i < RT_ARRAY_SIZE(rproc->vring_region); ++i) + { + rproc->vring_num[i] = rt_le32_to_cpu(vdev->vring[i].num) ? : + K1X_RPMSG_QUEUE_NUM; + rproc->vring_align[i] = rt_le32_to_cpu(vdev->vring[i].align) ? : + ARCH_PAGE_SIZE; + rproc->vring_notify[i] = rt_le32_to_cpu(vdev->vring[i].notifyid); + } + rproc->vring_notify[0] = K1X_RPMSG_VRING0_NOTIFY_ID; + rproc->vring_notify[1] = K1X_RPMSG_VRING1_NOTIFY_ID; + + vdev->vring[0].da = rt_cpu_to_le32(rproc->vring_region[0].da); + vdev->vring[1].da = rt_cpu_to_le32(rproc->vring_region[1].da); + vdev->vring[0].align = rt_cpu_to_le32(rproc->vring_align[0]); + vdev->vring[1].align = rt_cpu_to_le32(rproc->vring_align[1]); + vdev->vring[0].num = rt_cpu_to_le32(rproc->vring_num[0]); + vdev->vring[1].num = rt_cpu_to_le32(rproc->vring_num[1]); + vdev->vring[0].notifyid = rt_cpu_to_le32(rproc->vring_notify[0]); + vdev->vring[1].notifyid = rt_cpu_to_le32(rproc->vring_notify[1]); + rproc->virtio_features = rt_le32_to_cpu(vdev->dfeatures) | + K1X_VIRTIO_RPMSG_F_NS; + vdev->dfeatures = rt_cpu_to_le32( + (rt_uint32_t)rproc->virtio_features); + vdev->gfeatures = 0; + vdev->status = 0; + rt_hw_wmb(); + + LOG_D("RPMsg resource ready: status=0x%02x notify=%u/%u vring0=0x%08x vring1=0x%08x buffer=0x%08x", + vdev->status, rproc->vring_notify[0], + rproc->vring_notify[1], + rproc->vring_region[0].da, + rproc->vring_region[1].da, rproc->buffer_region.da); + + return RT_EOK; +} + +static rt_err_t spacemit_rpmsg_prepare(struct spacemit_rproc *rproc, + const char *fw_name) +{ + rt_err_t err; + + if ((err = spacemit_rpmsg_map_region(rproc, K1X_RPMSG_VRING0_NAME, + K1X_RPMSG_VRING0_REGION, + &rproc->vring_region[0])) || + (err = spacemit_rpmsg_map_region(rproc, K1X_RPMSG_VRING1_NAME, + K1X_RPMSG_VRING1_REGION, + &rproc->vring_region[1])) || + (err = spacemit_rpmsg_map_region(rproc, K1X_RPMSG_BUFFER_NAME, + K1X_RPMSG_BUFFER_REGION, + &rproc->buffer_region)) || + (err = spacemit_rpmsg_map_region(rproc, K1X_RPMSG_RSC_NAME, + K1X_RPMSG_RSC_REGION, + &rproc->rsc_region))) + { + return err; + } + + rproc->dma_slot_count = rproc->buffer_region.size / + K1X_RPMSG_BUFFER_SIZE; + if (!rproc->dma_slot_count) + { + return -RT_EINVAL; + } + + rproc->dma_slots = rt_calloc(rproc->dma_slot_count, + sizeof(rproc->dma_slots[0])); + if (!rproc->dma_slots) + { + return -RT_ENOMEM; + } + rt_spin_lock_init(&rproc->dma_lock); + + return spacemit_rpmsg_reset_transport(rproc, fw_name); +} + +static rt_err_t spacemit_rproc_prepare(struct spacemit_rproc *rproc) +{ + rt_err_t err; + + /* Keep the RCPU held until a client explicitly needs RPMsg. */ + HWREG32(rproc->bootc_mem_base + FW_BOOTUP_REG_OFFSET) = 0; + rt_hw_wmb(); + + /* De-assert the clk */ + rt_reset_control_assert(rproc->core_rstc); + rt_reset_control_deassert(rproc->core_rstc); + HWREG32(rproc->bootc_mem_base + FW_BOOTUP_REG_OFFSET) = 0; + rt_hw_wmb(); + + /* Enable clocks explicitly (RT-Thread may keep them gated by default) */ + if ((err = rt_clk_prepare_enable(rproc->core_clk))) + { + return err; + } + + if ((err = rt_clk_prepare_enable(rproc->apb_clk))) + { + rt_clk_disable_unprepare(rproc->core_clk); + return err; + } + rproc->clocks_enabled = RT_TRUE; + + /* Set apb clk rate */ + if ((err = rt_clk_set_rate(rproc->apb_clk, rproc->apb_clk_rate))) + { + rt_clk_disable_unprepare(rproc->apb_clk); + rt_clk_disable_unprepare(rproc->core_clk); + rproc->clocks_enabled = RT_FALSE; + return err; + } + + return RT_EOK; +} + +static rt_err_t spacemit_rproc_start(struct spacemit_rproc *rproc) +{ + /* Enable ipc2ap clk & reset--> rcpu side */ + HWREG32(rproc->bootc_mem_base + FW_AON_PER_CLK_RST_CTL_REG) = 0xff; + + /* Set the boot-entry */ + HWREG32(rproc->sysctrl_mem_base + FW_BOOT_ENTRY_REG_OFFSET) = rproc->fw_entry_point; + + /* Set ddr map */ + HWREG32(rproc->sysctrl_mem_base + FW_DDR_REGMAP_BASE_REG_OFFSET) = rproc->ddr_remap_base; + + rt_hw_wmb(); + + /* Lanching up firmware */ + HWREG32(rproc->bootc_mem_base + FW_BOOTUP_REG_OFFSET) = 1; + rt_hw_wmb(); + + return RT_EOK; +} + +static rt_err_t spacemit_rproc_boot(struct spacemit_rproc *rproc) +{ + rt_err_t err; + rt_ubase_t level; + rt_bool_t started; + + if (!rproc || !rproc->rpmsg_ready || !rproc->rpmsg_mutex_inited) + { + return -RT_EINVAL; + } + + err = rt_mutex_take(&rproc->rpmsg_mutex, RT_WAITING_FOREVER); + if (err) + { + return err; + } + + level = rt_spin_lock_irqsave(&spacemit_rpmsg_lock); + if (rproc != spacemit_rproc_global) + { + rt_spin_unlock_irqrestore(&spacemit_rpmsg_lock, level); + rt_mutex_release(&rproc->rpmsg_mutex); + return -RT_EINVAL; + } + started = rproc->firmware_started; + rt_spin_unlock_irqrestore(&spacemit_rpmsg_lock, level); + + if (!started) + { + if (rproc->clocks_enabled == RT_FALSE) + { + err = spacemit_rproc_prepare(rproc); + if (err) + { + rt_mutex_release(&rproc->rpmsg_mutex); + return err; + } + } + + err = spacemit_rproc_start(rproc); + if (!err) + { + rt_hw_wmb(); + level = rt_spin_lock_irqsave(&spacemit_rpmsg_lock); + if (rproc == spacemit_rproc_global) + { + rproc->firmware_started = RT_TRUE; + rproc->boot_requested = RT_FALSE; + } + else + { + err = -RT_EINVAL; + } + rt_spin_unlock_irqrestore(&spacemit_rpmsg_lock, level); + } + } + + rt_mutex_release(&rproc->rpmsg_mutex); + if (err) + { + return err; + } + + err = spacemit_rpmsg_worker_start(rproc); + if (err) + { + return err; + } + + spacemit_rpmsg_notify(rproc, K1X_MBOX_VQ0_ID); + spacemit_rpmsg_notify(rproc, K1X_MBOX_VQ1_ID); + LOG_D("RCPU firmware booted on demand, entry=0x%08x remap=0x%08x", + rproc->fw_entry_point, rproc->ddr_remap_base); + + return RT_EOK; +} + +rt_err_t spacemit_k1x_rproc_boot(const char *fw_name) +{ + rt_err_t err; + rt_ubase_t level; + struct spacemit_rproc *rproc; + + level = rt_spin_lock_irqsave(&spacemit_rpmsg_lock); + rproc = spacemit_rproc_global; + rt_spin_unlock_irqrestore(&spacemit_rpmsg_lock, level); + + if (!rproc) + { + return -RT_ENOENT; + } + + if (fw_name && fw_name[0] && rt_strcmp(fw_name, rproc->fw_name)) + { + return -RT_ENOENT; + } + + err = spacemit_rproc_boot(rproc); + if (err) + { + LOG_E("Boot RCPU firmware %s failed: %s", + rproc->fw_name, rt_strerror(err)); + return err; + } + + return RT_EOK; +} + +void spacemit_k1x_rproc_dump_status(void) +{ + rt_ubase_t level; + struct spacemit_fw_rsc_vdev *rsc_vdev; + struct spacemit_rproc *rproc; + + level = rt_spin_lock_irqsave(&spacemit_rpmsg_lock); + rproc = spacemit_rproc_global; + rt_spin_unlock_irqrestore(&spacemit_rpmsg_lock, level); + if (!rproc) + { + LOG_W("RCPU state unavailable"); + return; + } + + LOG_W("RCPU state: started=%u worker=%u boot=%08x entry=%08x remap=%08x aon=%08x", + rproc->firmware_started, rproc->worker_started, + HWREG32((char *)rproc->bootc_mem_base + FW_BOOTUP_REG_OFFSET), + HWREG32((char *)rproc->sysctrl_mem_base + + FW_BOOT_ENTRY_REG_OFFSET), + HWREG32((char *)rproc->sysctrl_mem_base + + FW_DDR_REGMAP_BASE_REG_OFFSET), + HWREG32((char *)rproc->bootc_mem_base + + FW_AON_PER_CLK_RST_CTL_REG)); + + rsc_vdev = spacemit_rproc_rsc_vdev(rproc); + if (rsc_vdev) + { + rt_hw_rmb(); + LOG_W("RPMsg resource: status=%02x dfeatures=%08x gfeatures=%08x", + rsc_vdev->status, + rt_le32_to_cpu(rsc_vdev->dfeatures), + rt_le32_to_cpu(rsc_vdev->gfeatures)); + } + + for (int i = 0; i < RT_ARRAY_SIZE(rproc->vqs); ++i) + { + struct virtq ring; + struct rt_virtqueue *vq = rproc->vqs[i]; + + if (!vq || !rproc->vring_region[i].va) + { + continue; + } + + virtq_init(&ring, rproc->vring_num[i], + rproc->vring_region[i].va, + rproc->vring_align[i]); + rt_hw_rmb(); + LOG_W("RPMsg vq%d: avail=%u used=%u last=%u notify=%u mailbox=%u", + i, rt_le16_to_cpu(ring.avail->idx), + rt_le16_to_cpu(ring.used->idx), vq->last_used_idx, + rproc->notify_count[i], rproc->mbox_count[i]); + } +} + +static rt_err_t spacemit_rproc_stop(struct spacemit_rproc *rproc) +{ + rt_ubase_t level; + + /* Hold the rcpu */ + HWREG32(rproc->bootc_mem_base + FW_BOOTUP_REG_OFFSET) = 0; + rt_hw_wmb(); + + level = rt_spin_lock_irqsave(&spacemit_rpmsg_lock); + rproc->firmware_started = RT_FALSE; + rt_spin_unlock_irqrestore(&spacemit_rpmsg_lock, level); + + rt_reset_control_assert(rproc->core_rstc); + + if (rproc->clocks_enabled) + { + /* Gate clocks after reset asserted */ + rt_clk_disable_unprepare(rproc->apb_clk); + rt_clk_disable_unprepare(rproc->core_clk); + rproc->clocks_enabled = RT_FALSE; + } + + return RT_EOK; +} + +static void spacemit_rproc_mbox_rx_callback(struct rt_mbox_client *client, void *data) +{ + struct spacemit_rproc_mbox *mb = rt_container_of(client, struct spacemit_rproc_mbox, parent); + struct spacemit_rproc *rproc = mb->rproc; + + if (mb->vq_id < RT_ARRAY_SIZE(rproc->mbox_count)) + { + ++rproc->mbox_count[mb->vq_id]; + } + + if (rproc->rpmsg_sem_inited) + { + rt_sem_release(&rproc->rpmsg_sem); + } +} + +static rt_err_t spacemit_rproc_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + rt_uint64_t fw_entry_pa; + const char *fw_name, *name; + struct rt_device *dev = &pdev->parent; + struct spacemit_rproc *rproc = rt_calloc(1, sizeof(*rproc)); + + if (!rproc) + { + return -RT_ENOMEM; + } + rproc->dev = dev; + + rproc->bootc_mem_base = rt_dm_dev_iomap(dev, 0); + if (!rproc->bootc_mem_base) + { + err = -RT_EIO; + goto _fail; + } + + rproc->sysctrl_mem_base = rt_dm_dev_iomap(dev, 1); + if (!rproc->sysctrl_mem_base) + { + err = -RT_EIO; + goto _fail; + } + + rproc->core_rstc = rt_reset_control_get_by_index(dev, 0); + if (rt_is_err(rproc->core_rstc)) + { + err = rt_ptr_err(rproc->core_rstc); + goto _fail; + } + + rproc->core_clk = rt_clk_get_by_name(dev, "core"); + if (rt_is_err(rproc->core_clk)) + { + err = rt_ptr_err(rproc->core_clk); + goto _fail; + } + + rproc->apb_clk = rt_clk_get_by_name(dev, "apb"); + if (rt_is_err(rproc->apb_clk)) + { + err = rt_ptr_err(rproc->apb_clk); + goto _fail; + } + + if ((err = rt_dm_dev_prop_read_u32(dev, "apb-clk-rate", &rproc->apb_clk_rate))) + { + goto _fail; + } + + if ((err = rt_dm_dev_prop_read_u32(dev, "ddr-remap-base", &rproc->ddr_remap_base))) + { + goto _fail; + } + + if ((err = rt_dm_dev_prop_read_string(dev, "firmware-name", &fw_name))) + { + goto _fail; + } + rt_strncpy(rproc->fw_name, fw_name, sizeof(rproc->fw_name) - 1); + + if (!(name = rt_dm_dev_get_prop_fuzzy_name(dev, "-entry-point$"))) + { + err = -RT_EINVAL; + goto _fail; + } + + if ((err = rt_dm_dev_prop_read_u32(dev, name, &rproc->fw_entry_point))) + { + goto _fail; + } + + for (int i = 0; i < RT_ARRAY_SIZE(rproc->mb); ++i) + { + struct spacemit_rproc_mbox *mb = &rproc->mb[i]; + + mb->vq_id = i; + mb->rproc = rproc; + + mb->parent.dev = dev; + mb->parent.rx_callback = spacemit_rproc_mbox_rx_callback; + + mb->chan = rt_mbox_request_by_name(&mb->parent, mb_name[i]); + + if (rt_is_err_or_null(mb->chan)) + { + err = -RT_EINVAL; + LOG_E("Request mailbox fail"); + goto _fail; + } + } + + if ((err = spacemit_rproc_prepare(rproc))) + { + LOG_E("Prepare RCPU hardware failed: %s", rt_strerror(err)); + goto _fail; + } + + if ((err = spacemit_rproc_clear_carveouts(rproc))) + { + goto _fail; + } + + if ((err = spacemit_rproc_da_to_pa(rproc, rproc->fw_entry_point, + &fw_entry_pa))) + { + LOG_E("Translate RCPU firmware entry 0x%08x failed: %s", + rproc->fw_entry_point, rt_strerror(err)); + goto _fail; + } + if ((err = spacemit_firmware_load_elf(fw_name, fw_entry_pa))) + { + LOG_E("Run firmware %s fail", fw_name); + goto _fail; + } + + if ((err = spacemit_rpmsg_prepare(rproc, fw_name))) + { + LOG_E("Prepare RPMsg transport failed: %s", rt_strerror(err)); + goto _fail; + } + + if ((err = rt_sem_init(&rproc->rpmsg_sem, "k1-rpmsg", 0, + RT_IPC_FLAG_FIFO))) + { + goto _fail; + } + rproc->rpmsg_sem_inited = RT_TRUE; + if ((err = rt_mutex_init(&rproc->rpmsg_mutex, "k1-rpmsg", + RT_IPC_FLAG_FIFO))) + { + goto _fail; + } + rproc->rpmsg_mutex_inited = RT_TRUE; + rproc->rpmsg_thread = rt_thread_create("k1-rpmsg", spacemit_rpmsg_worker, + rproc, 4096, RT_THREAD_PRIORITY_MAX / 2, 10); + if (!rproc->rpmsg_thread) + { + err = -RT_ENOMEM; + goto _fail; + } + + rproc->rpmsg_ready = RT_TRUE; + rt_spin_lock(&spacemit_rpmsg_lock); + spacemit_rproc_global = rproc; + rt_spin_unlock(&spacemit_rpmsg_lock); + + rproc->vdev.parent.ofw_node = dev->ofw_node; + rproc->vdev.id.device = VIRTIO_DEVICE_ID_RPMSG; + rproc->vdev.id.vendor = K1X_RPMSG_VIRTIO_VENDOR; + rproc->vdev.trans = &spacemit_rproc_virtio_transport; + rproc->vdev.dma_dispatch = RT_TRUE; + rt_dma_device_set_ops(&rproc->vdev.parent, &spacemit_rproc_dma_ops); + if ((err = rt_virtio_device_register(&rproc->vdev))) + { + LOG_E("Register RCPU virtio-rpmsg failed: %s", + rt_strerror(err)); + goto _fail; + } + rproc->virtio_registered = RT_TRUE; + + LOG_D("RCPU firmware %s loaded, entry=0x%08x remap=0x%08x, boot deferred", + fw_name, rproc->fw_entry_point, rproc->ddr_remap_base); + + dev->user_data = rproc; + + return RT_EOK; + +_fail: + rproc->rpmsg_ready = RT_FALSE; + rt_spin_lock(&spacemit_rpmsg_lock); + if (spacemit_rproc_global == rproc) + { + spacemit_rproc_global = RT_NULL; + } + rt_spin_unlock(&spacemit_rpmsg_lock); + if (rproc->firmware_started) + { + spacemit_rproc_stop(rproc); + } + else if (rproc->clocks_enabled) + { + spacemit_rproc_stop(rproc); + } + if (rproc->virtio_registered) + { + rt_bus_remove_device(&rproc->vdev.parent); + rproc->virtio_registered = RT_FALSE; + } + if (rproc->rpmsg_thread) + { + spacemit_rpmsg_worker_destroy(rproc); + } + if (rproc->rpmsg_sem_inited) + { + rt_sem_detach(&rproc->rpmsg_sem); + } + if (rproc->rpmsg_mutex_inited) + { + rt_mutex_detach(&rproc->rpmsg_mutex); + } + for (int i = 0; i < RT_ARRAY_SIZE(rproc->vring_region); ++i) + { + if (rproc->vring_region[i].va) + { + rt_iounmap(rproc->vring_region[i].va); + } + } + if (rproc->buffer_region.va) + { + rt_iounmap(rproc->buffer_region.va); + } + if (rproc->rsc_region.va) + { + rt_iounmap(rproc->rsc_region.va); + } + if (rproc->dma_slots) + { + rt_free(rproc->dma_slots); + } + if (rproc->bootc_mem_base) + { + rt_iounmap(rproc->bootc_mem_base); + } + if (rproc->sysctrl_mem_base) + { + rt_iounmap(rproc->sysctrl_mem_base); + } + + if (!rt_is_err_or_null(rproc->core_rstc)) + { + rt_reset_control_put(rproc->core_rstc); + } + if (!rt_is_err_or_null(rproc->core_clk)) + { + rt_clk_put(rproc->core_clk); + } + if (!rt_is_err_or_null(rproc->apb_clk)) + { + rt_clk_put(rproc->apb_clk); + } + + for (int i = 0; i < RT_ARRAY_SIZE(rproc->mb); ++i) + { + struct spacemit_rproc_mbox *mb = &rproc->mb[i]; + + if (!rt_is_err_or_null(mb->chan)) + { + rt_mbox_release(mb->chan); + } + } + + rt_free(rproc); + + return err; +} + +static rt_err_t spacemit_rproc_shutdown(struct rt_platform_device *pdev) +{ + struct spacemit_rproc *rproc = pdev->parent.user_data; + + rproc->rpmsg_ready = RT_FALSE; + spacemit_rpmsg_worker_destroy(rproc); + if (rproc->rpmsg_mutex_inited) + { + rt_mutex_detach(&rproc->rpmsg_mutex); + rproc->rpmsg_mutex_inited = RT_FALSE; + } + if (rproc->rpmsg_sem_inited) + { + rt_sem_detach(&rproc->rpmsg_sem); + rproc->rpmsg_sem_inited = RT_FALSE; + } + rt_spin_lock(&spacemit_rpmsg_lock); + if (spacemit_rproc_global == rproc) + { + spacemit_rproc_global = RT_NULL; + } + rt_spin_unlock(&spacemit_rpmsg_lock); + if (rproc->virtio_registered) + { + rt_bus_remove_device(&rproc->vdev.parent); + rproc->virtio_registered = RT_FALSE; + } + spacemit_rproc_stop(rproc); + + return RT_EOK; +} + +static const struct rt_ofw_node_id spacemit_rproc_ofw_ids[] = +{ + { .compatible = "spacemit,k1-x-rproc" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver spacemit_rproc_driver = +{ + .name = "spacemit-rproc", + .ids = spacemit_rproc_ofw_ids, + + .probe = spacemit_rproc_probe, + .shutdown = spacemit_rproc_shutdown, +}; + +static int spacemit_rproc_drv_register(void) +{ + rt_platform_driver_register(&spacemit_rproc_driver); + + return 0; +} +INIT_SUBSYS_EXPORT(spacemit_rproc_drv_register); diff --git a/bsp/spacemit/dm/soc/k1x-tcm.c b/bsp/spacemit/dm/soc/k1x-tcm.c new file mode 100644 index 000000000000..df1d97cac362 --- /dev/null +++ b/bsp/spacemit/dm/soc/k1x-tcm.c @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#include +#include + +#define DBG_TAG "soc.k1x-tcm" +#define DBG_LVL DBG_INFO +#include + +#include +#include + +static struct rt_memheap *tcm_heap[RT_CPUS_NR]; + +void *tcm_alloc_cpu(int cpuid, rt_size_t size) +{ + if (cpuid < RT_ARRAY_SIZE(tcm_heap) && tcm_heap[cpuid]) + { + return rt_memheap_alloc(tcm_heap[cpuid], size); + } + + return RT_NULL; +} + +void tcm_free_cpu(int cpuid, void *ptr) +{ + if (cpuid < RT_ARRAY_SIZE(tcm_heap) && tcm_heap[cpuid]) + { + rt_memheap_free(ptr); + } +} + +static rt_err_t spacemit_tcm_probe(struct rt_platform_device *pdev) +{ + struct rt_ofw_node *np = pdev->parent.ofw_node, *tcm_np; + + csr_write(CSR_TCMCFG, TCM_EN); + + rt_ofw_foreach_child_node(np, tcm_np) + { + int cpuid = 0; + void *tcm_base; + rt_uint64_t addr, size; + const char *string, *node_name; + + if (rt_ofw_get_address(tcm_np, 0, &addr, &size)) + { + continue; + } + + string = node_name = rt_fdt_node_name(tcm_np->full_name); + string += sizeof("core") - 1; + + while (*string >= '0' && *string <= '9') + { + cpuid *= 10; + cpuid += *string - '0'; + + ++string; + } + + tcm_heap[cpuid] = rt_calloc(1, sizeof(struct rt_memheap)); + + if (!tcm_heap[cpuid]) + { + return -RT_ENOMEM; + } + + if (!(tcm_base = rt_ioremap_cached((void *)addr, size))) + { + rt_free(tcm_heap[cpuid]); + return -RT_EIO; + } + + if (rt_memheap_init(tcm_heap[cpuid], node_name, tcm_base, size)) + { + rt_free(tcm_heap[cpuid]); + tcm_heap[cpuid] = RT_NULL; + } + } + + return RT_EOK; +} + +static rt_err_t spacemit_tcm_shutdown(struct rt_platform_device *pdev) +{ + csr_clear(CSR_TCMCFG, TCM_EN); + + return RT_EOK; +} + +static const struct rt_ofw_node_id spacemit_tcm_ofw_ids[] = +{ + { .compatible = "spacemit,k1-x-tcm" }, + { .compatible = "spacemit,k1-pro-tcm" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver spacemit_tcm_driver = +{ + .name = "spacemit-tcm", + .ids = spacemit_tcm_ofw_ids, + + .probe = spacemit_tcm_probe, + .shutdown = spacemit_tcm_shutdown, +}; + +static int spacemit_tcm_drv_register(void) +{ + rt_platform_driver_register(&spacemit_tcm_driver); + + return 0; +} +INIT_SUBSYS_EXPORT(spacemit_tcm_drv_register); diff --git a/bsp/spacemit/dm/soc/sbi-ipi.c b/bsp/spacemit/dm/soc/sbi-ipi.c new file mode 100644 index 000000000000..3880c3522106 --- /dev/null +++ b/bsp/spacemit/dm/soc/sbi-ipi.c @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#include + +#include + +static int spacemit_sbi_ipi_init(void) +{ + csr_set(CSR_IE, IE_SIE); + + return 0; +} +INIT_BOARD_EXPORT(spacemit_sbi_ipi_init); + +static int spacemit_sbi_ipi_secondary_cpu_init(void) +{ + return spacemit_sbi_ipi_init(); +} +INIT_SECONDARY_CPU_EXPORT(spacemit_sbi_ipi_secondary_cpu_init); diff --git a/bsp/spacemit/dm/soc/spacemit-socinfo.c b/bsp/spacemit/dm/soc/spacemit-socinfo.c new file mode 100644 index 000000000000..df4fdc9bbce9 --- /dev/null +++ b/bsp/spacemit/dm/soc/spacemit-socinfo.c @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#include +#include + +#define DBG_TAG "soc.info" +#define DBG_LVL DBG_INFO +#include + +struct spacemit_soc_info +{ + rt_uint32_t die_id; /* Die/wafer id */ + rt_uint32_t ver_id; /* Die/wafer version */ + rt_uint32_t pack_id; /* Package id */ + rt_uint32_t svtdro; /* Dro vaule */ + rt_uint64_t chipid; /* Chip serial number */ + rt_uint32_t soc_id; /* SoC id */ + char *name; /* Chip name */ +}; + +struct spacemit_soc_id +{ + const char *name; + rt_uint32_t id; +}; + +static const struct spacemit_soc_id soc_ids[] = +{ + { "unknown", 0x00000000 }, + /* k1 serial soc */ + { "M1-8571", 0x36070000 }, + { "K1-6370", 0x36070009 }, + { "K1-6350", 0x36070012 }, + { "K1-6371", 0x36070040 }, + { "M103-6370", 0x36070109 }, + { "M103-6371", 0x36070140 }, +}; + +static const char *soc_id_to_chip_name(rt_uint32_t die_id, rt_uint32_t ver_id, rt_uint32_t pack_id) +{ + rt_uint32_t soc_id = (die_id << 16) | (pack_id); + + for (int i = 0; i < RT_ARRAY_SIZE(soc_ids); ++i) + { + if (soc_id == soc_ids[i].id) + { + return soc_ids[i].name; + } + } + + /* The soc id is unknown */ + return soc_ids[0].name; +} + +static rt_ssize_t socinfo_get_nvparam(struct rt_device *dev, char *cell_name, void *val, rt_size_t size) +{ + rt_ssize_t res; + struct rt_nvmem_cell *cell; + + cell = rt_nvmem_get_cell_by_name(dev, cell_name); + if (rt_is_err(cell)) + { + LOG_E("NVMEM cell get %s failed", cell_name); + return rt_ptr_err(cell); + } + + res = rt_nvmem_cell_read(cell, val, rt_min_t(rt_size_t, cell->bytes, size)); + if (res < 0) + { + LOG_E("NVMEM cell read %s failed", cell_name); + goto _end; + } + +_end: + rt_nvmem_put_cell(cell); + + return res; +} + +static rt_err_t spacemit_socinfo_probe(struct rt_platform_device *pdev) +{ + rt_ssize_t res; + struct rt_device *dev = &pdev->parent; + struct spacemit_soc_info socinfo; + + rt_memset(&socinfo, 0, sizeof(socinfo)); + + if ((res = socinfo_get_nvparam(dev, "soc_die_id", + &socinfo.die_id, sizeof(socinfo.die_id))) <= 0) + { + LOG_E("Try to get soc_%s from efuse failed", "die_id"); + } + + if ((res = socinfo_get_nvparam(dev, "soc_ver_id", + &socinfo.ver_id, sizeof(socinfo.ver_id))) <= 0) + { + LOG_E("Try to get soc_%s from efuse failed", "ver_id"); + } + + if ((res = socinfo_get_nvparam(dev, "soc_pack_id", + &socinfo.pack_id, sizeof(socinfo.pack_id))) <= 0) + { + LOG_E("Try to get soc_%s from efuse failed", "pack_id"); + } + + if ((res = socinfo_get_nvparam(dev, "soc_svt_dro", + &socinfo.svtdro, sizeof(socinfo.svtdro))) <= 0) + { + LOG_E("Try to get soc_%s from efuse failed", "svt_dro"); + } + + if ((res = socinfo_get_nvparam(dev, "soc_chip_id", + &socinfo.chipid, sizeof(socinfo.chipid))) <= 0) + { + LOG_E("Try to get soc_%s from efuse failed", "chip_id"); + } + + socinfo.soc_id = (socinfo.die_id << 16) | socinfo.pack_id; + + LOG_I("Revision : %c", (socinfo.ver_id + 'A') & 0xff); + LOG_I("ID : %s", soc_id_to_chip_name(socinfo.die_id, socinfo.ver_id, socinfo.pack_id)); + LOG_I("Serial No: %016lx", socinfo.chipid); + + return RT_EOK; +} + +static const struct rt_ofw_node_id spacemit_socinfo_ofw_ids[] = +{ + { .compatible = "spacemit,socinfo-k1x" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver spacemit_socinfo_driver = +{ + .name = "spacemit-socinfo", + .ids = spacemit_socinfo_ofw_ids, + + .probe = spacemit_socinfo_probe, +}; +RT_PLATFORM_DRIVER_EXPORT(spacemit_socinfo_driver); diff --git a/bsp/spacemit/dm/soc/v2d/SConscript b/bsp/spacemit/dm/soc/v2d/SConscript new file mode 100644 index 000000000000..d5a33a71dd12 --- /dev/null +++ b/bsp/spacemit/dm/soc/v2d/SConscript @@ -0,0 +1,9 @@ +from building import * + +cwd = GetCurrentDir() +src = ['v2d_drv.c', 'v2d_hw.c'] +CPPPATH = [cwd, cwd + '/../../include'] + +group = DefineGroup('DeviceDrivers', src, depend = ['RT_SOC_SPACEMIT_V2D'], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/spacemit/dm/soc/v2d/v2d_drv.c b/bsp/spacemit/dm/soc/v2d/v2d_drv.c new file mode 100644 index 000000000000..38825126c8bd --- /dev/null +++ b/bsp/spacemit/dm/soc/v2d/v2d_drv.c @@ -0,0 +1,740 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#include "v2d_internal.h" +#include "v2d_reg.h" + +#include + +#define V2D_TIMEOUT_MS 2500 +#define V2D_CORE_RATE 409600000UL +#define V2D_ADDRESS_MASK 0x3ffffffffULL + +struct spacemit_v2d_buffer +{ + rt_list_t list; + V2D_BUFFER_S buffer; +}; + +struct spacemit_v2d +{ + struct rt_device parent; + struct rt_device *dev; + void *regs; + int irq; + + struct rt_clk *clk_core; + struct rt_clk *clk_io; + struct rt_reset_control *reset; + + struct rt_mutex lock; + struct rt_completion completion; + rt_list_t buffers; + + rt_bool_t clocks_enabled; + rt_bool_t reset_deasserted; + rt_bool_t lock_initialized; + rt_bool_t device_registered; + + rt_uint32_t irq_status; + rt_uint32_t error_status; + rt_err_t error; +}; + +rt_inline struct spacemit_v2d *raw_to_spacemit_v2d(struct rt_device *dev) +{ + return rt_container_of(dev, struct spacemit_v2d, parent); +} + +static rt_uint64_t v2d_surface_y_address(const V2D_SURFACE_S *surface) +{ + return (rt_uint64_t)surface->phyaddr_y_l | + ((rt_uint64_t)surface->phyaddr_y_h << 32); +} + +static rt_uint64_t v2d_surface_uv_address(const V2D_SURFACE_S *surface) +{ + return (rt_uint64_t)surface->phyaddr_uv_l | + ((rt_uint64_t)surface->phyaddr_uv_h << 32); +} + +static int v2d_format_bpp(V2D_COLOR_FORMAT_E format) +{ + switch (format) + { + case V2D_COLOR_FORMAT_NV12: + case V2D_COLOR_FORMAT_NV21: + case V2D_COLOR_FORMAT_A8: + case V2D_COLOR_FORMAT_Y8: + case V2D_COLOR_FORMAT_L8_RGBA8888: + case V2D_COLOR_FORMAT_L8_RGB888: + case V2D_COLOR_FORMAT_L8_RGB565: + case V2D_COLOR_FORMAT_L8_BGRA8888: + case V2D_COLOR_FORMAT_L8_BGR888: + case V2D_COLOR_FORMAT_L8_BGR565: + return 1; + case V2D_COLOR_FORMAT_RGB565: + case V2D_COLOR_FORMAT_BGR565: + return 2; + case V2D_COLOR_FORMAT_RGB888: + case V2D_COLOR_FORMAT_BGR888: + case V2D_COLOR_FORMAT_RGBA5658: + case V2D_COLOR_FORMAT_ARGB8565: + case V2D_COLOR_FORMAT_BGRA5658: + case V2D_COLOR_FORMAT_ABGR8565: + return 3; + case V2D_COLOR_FORMAT_RGBX8888: + case V2D_COLOR_FORMAT_RGBA8888: + case V2D_COLOR_FORMAT_ARGB8888: + case V2D_COLOR_FORMAT_BGRX8888: + case V2D_COLOR_FORMAT_BGRA8888: + case V2D_COLOR_FORMAT_ABGR8888: + return 4; + default: + return 0; + } +} + +static rt_bool_t v2d_range_is_allocated(struct spacemit_v2d *v2d, + rt_uint64_t address, rt_uint64_t size) +{ + struct spacemit_v2d_buffer *entry; + + if (!address || !size || address > V2D_ADDRESS_MASK || + size - 1 > V2D_ADDRESS_MASK - address) + { + return RT_FALSE; + } + + rt_list_for_each_entry(entry, &v2d->buffers, list) + { + rt_uint64_t start = entry->buffer.phys_addr; + rt_uint64_t end = start + entry->buffer.size; + + if (address >= start && address + size <= end) + { + return RT_TRUE; + } + } + + return RT_FALSE; +} + +static rt_err_t v2d_validate_rect(const V2D_AREA_S *rect, + rt_uint16_t width, rt_uint16_t height) +{ + if (!rect->w || !rect->h || rect->x >= width || rect->y >= height || + rect->w > width - rect->x || rect->h > height - rect->y) + { + return -RT_EINVAL; + } + + return RT_EOK; +} + +static rt_err_t v2d_validate_surface(struct spacemit_v2d *v2d, + const V2D_SURFACE_S *surface, const V2D_AREA_S *rect) +{ + rt_uint64_t y_size; + rt_uint64_t min_stride; + rt_uint64_t address; + int bpp; + + if (surface->fbc_enable) + { + return -RT_ENOSYS; + } + if (!surface->w || !surface->h || !surface->stride || + !(bpp = v2d_format_bpp(surface->format))) + { + return -RT_EINVAL; + } + if (v2d_validate_rect(rect, surface->w, surface->h) != RT_EOK) + { + return -RT_EINVAL; + } + + min_stride = (rt_uint64_t)surface->w * bpp; + if (surface->stride < min_stride) + { + return -RT_EINVAL; + } + + address = v2d_surface_y_address(surface); + y_size = (rt_uint64_t)(surface->h - 1) * surface->stride + min_stride; + if (!v2d_range_is_allocated(v2d, address, y_size)) + { + return -RT_EINVAL; + } + + if (surface->format == V2D_COLOR_FORMAT_NV12 || + surface->format == V2D_COLOR_FORMAT_NV21) + { + rt_uint64_t uv_address = v2d_surface_uv_address(surface); + rt_uint64_t uv_size = (rt_uint64_t)surface->stride * + RT_DIV_ROUND_UP(surface->h, 2); + + if (!v2d_range_is_allocated(v2d, uv_address, uv_size)) + { + return -RT_EINVAL; + } + } + + return RT_EOK; +} + +static rt_bool_t v2d_layer_enabled(const V2D_SURFACE_S *surface) +{ + return surface->solidcolor.enable || surface->fbc_enable || + v2d_surface_y_address(surface) != 0; +} + +static rt_bool_t v2d_blend_layer_valid(const V2D_BLEND_LAYER_CONF_S *blend, + V2D_BLENDCMD_E command) +{ + if ((unsigned int)blend->blend_alpha_source >= + V2D_BLENDALPHA_SOURCE_BUTT || + (unsigned int)blend->blend_pre_alpha_func >= + V2D_BLEND_PRE_ALPHA_FUNC_BUTT) + { + return RT_FALSE; + } + + if (command == V2D_BLENDCMD_ALPHA) + { + return (unsigned int)blend->stBlendFactor.srcColorFactor < + V2D_BLEND_BUTT && + (unsigned int)blend->stBlendFactor.dstColorFactor < + V2D_BLEND_BUTT && + (unsigned int)blend->stBlendFactor.srcAlphaFactor < + V2D_BLEND_BUTT && + (unsigned int)blend->stBlendFactor.dstAlphaFactor < + V2D_BLEND_BUTT; + } + + return (unsigned int)blend->stRop2Code.colorRop2Code < V2D_ROP2_BUTT && + (unsigned int)blend->stRop2Code.alphaRop2Code < V2D_ROP2_BUTT; +} + +static rt_err_t v2d_validate_layer(struct spacemit_v2d *v2d, + const V2D_SURFACE_S *surface, const V2D_AREA_S *source, + const V2D_BLEND_LAYER_CONF_S *blend, const V2D_SURFACE_S *dst) +{ + if (!v2d_layer_enabled(surface)) + { + return RT_EOK; + } + if (!blend->blend_area.w || !blend->blend_area.h || + blend->blend_area.x >= dst->w || blend->blend_area.y >= dst->h || + blend->blend_area.w > dst->w - blend->blend_area.x || + blend->blend_area.h > dst->h - blend->blend_area.y) + { + return -RT_EINVAL; + } + if (surface->solidcolor.enable) + { + return surface->solidcolor.fillcolor.format < V2D_COLOR_FORMAT_BUTT ? + RT_EOK : -RT_EINVAL; + } + + return v2d_validate_surface(v2d, surface, source); +} + +static rt_err_t v2d_validate_task(struct spacemit_v2d *v2d, + V2D_SUBMIT_TASK_S *task) +{ + V2D_PARAM_S *param; + rt_err_t err; + + if (!task) + { + return -RT_EINVAL; + } + param = &task->param; + + if (task->acquireFencefd != -1 || + param->dst.fbc_enable || param->mask.fbc_enable || + (unsigned int)param->l0_rt > V2D_ROT_FLIP || + (unsigned int)param->l1_rt > V2D_ROT_FLIP || + (unsigned int)param->l0_csc > V2D_CSC_MODE_BUTT || + (unsigned int)param->l1_csc > V2D_CSC_MODE_BUTT || + (unsigned int)param->dither > V2D_DITHER_8X8 || + (unsigned int)param->blendconf.blend_cmd >= V2D_BLENDCMD_BUTT || + (unsigned int)param->blendconf.mask_cmd >= V2D_MASKCMD_BUTT || + param->palette.len < 0 || + param->palette.len > (int)sizeof(param->palette.palVal) || + !v2d_blend_layer_valid(¶m->blendconf.blendlayer[0], + param->blendconf.blend_cmd) || + !v2d_blend_layer_valid(¶m->blendconf.blendlayer[1], + param->blendconf.blend_cmd)) + { + return -RT_EINVAL; + } + if ((err = v2d_validate_surface(v2d, ¶m->dst, + ¶m->dst_rect)) != RT_EOK) + { + return err; + } + if ((err = v2d_validate_layer(v2d, ¶m->layer0, ¶m->l0_rect, + ¶m->blendconf.blendlayer[0], ¶m->dst)) != RT_EOK) + { + return err; + } + if ((err = v2d_validate_layer(v2d, ¶m->layer1, ¶m->l1_rect, + ¶m->blendconf.blendlayer[1], ¶m->dst)) != RT_EOK) + { + return err; + } + if (!v2d_layer_enabled(¶m->layer0) && + !v2d_layer_enabled(¶m->layer1) && + !param->blendconf.bgcolor.enable) + { + return -RT_EINVAL; + } + if (v2d_surface_y_address(¶m->mask)) + { + if ((err = v2d_validate_surface(v2d, ¶m->mask, + ¶m->mask_rect)) != RT_EOK) + { + return err; + } + } + + return RT_EOK; +} + +static rt_err_t v2d_buffer_alloc(struct spacemit_v2d *v2d, + V2D_BUFFER_S *buffer) +{ + struct spacemit_v2d_buffer *entry; + rt_ubase_t phys_addr; + + if (!buffer || !buffer->size || buffer->size > V2D_BUFFER_MAX_SIZE) + { + return -RT_EINVAL; + } + + entry = rt_calloc(1, sizeof(*entry)); + if (!entry) + { + return -RT_ENOMEM; + } + + buffer->virt_addr = rt_dma_alloc_coherent(v2d->dev, buffer->size, + &phys_addr); + if (!buffer->virt_addr) + { + rt_free(entry); + return -RT_ENOMEM; + } + buffer->phys_addr = phys_addr; + entry->buffer = *buffer; + rt_list_insert_before(&v2d->buffers, &entry->list); + + return RT_EOK; +} + +static rt_err_t v2d_buffer_free(struct spacemit_v2d *v2d, + V2D_BUFFER_S *buffer) +{ + struct spacemit_v2d_buffer *entry; + + if (!buffer || !buffer->virt_addr || !buffer->size) + { + return -RT_EINVAL; + } + + rt_list_for_each_entry(entry, &v2d->buffers, list) + { + if (entry->buffer.virt_addr == buffer->virt_addr && + entry->buffer.phys_addr == buffer->phys_addr && + entry->buffer.size == buffer->size) + { + rt_list_remove(&entry->list); + rt_dma_free_coherent(v2d->dev, entry->buffer.size, + entry->buffer.virt_addr, entry->buffer.phys_addr); + rt_free(entry); + buffer->virt_addr = RT_NULL; + buffer->phys_addr = 0; + return RT_EOK; + } + } + + return -RT_EINVAL; +} + +static rt_err_t v2d_hard_reset(struct spacemit_v2d *v2d) +{ + rt_err_t err; + + v2d_irq_disable(); + if (!rt_is_err_or_null(v2d->reset)) + { + if ((err = rt_reset_control_assert(v2d->reset)) != RT_EOK) + { + return err; + } + v2d->reset_deasserted = RT_FALSE; + rt_hw_us_delay(5); + if ((err = rt_reset_control_deassert(v2d->reset)) != RT_EOK) + { + return err; + } + v2d->reset_deasserted = RT_TRUE; + } + + return v2d_global_reset(); +} + +static rt_err_t v2d_submit(struct spacemit_v2d *v2d, + V2D_SUBMIT_TASK_S *task) +{ + rt_uint32_t status; + rt_err_t err; + + if ((err = v2d_validate_task(v2d, task)) != RT_EOK) + { + return err; + } + task->completeFencefd = -1; + + status = v2d_irq_status(); + if (status) + { + v2d_irq_clear(status); + } + status = v2d_irqerr_status(); + if (status) + { + v2d_irqerr_clear(status); + } + + rt_completion_init(&v2d->completion); + v2d->irq_status = 0; + v2d->error_status = 0; + v2d->error = RT_EOK; + + v2d_irq_enable(); + config_v2d_hw(task); + + if (rt_completion_wait(&v2d->completion, + rt_tick_from_millisecond(V2D_TIMEOUT_MS)) != RT_EOK) + { + LOG_E("job timeout"); + v2d_dump_irqraw_status(); + v2d_hard_reset(v2d); + return -RT_ETIMEOUT; + } + + v2d_irq_disable(); + if (v2d->error != RT_EOK) + { + LOG_E("job failed: irq=%08x error=%08x", + v2d->irq_status, v2d->error_status); + v2d_dump_irqraw_status(); + v2d_hard_reset(v2d); + } + + return v2d->error; +} + +static rt_err_t spacemit_v2d_control(rt_device_t dev, int cmd, void *args) +{ + rt_err_t err; + struct spacemit_v2d *v2d = raw_to_spacemit_v2d(dev); + + rt_mutex_take(&v2d->lock, RT_WAITING_FOREVER); + + switch (cmd) + { + case V2D_SUBMIT: + err = v2d_submit(v2d, args); + break; + case V2D_ALLOC_BUFFER: + err = v2d_buffer_alloc(v2d, args); + break; + case V2D_FREE_BUFFER: + err = v2d_buffer_free(v2d, args); + break; + case V2D_RESET: + err = v2d_hard_reset(v2d); + break; + default: + err = -RT_ENOSYS; + break; + } + + rt_mutex_release(&v2d->lock); + + return err; +} + +#ifdef RT_USING_DEVICE_OPS +static const struct rt_device_ops spacemit_v2d_ops = +{ + .control = spacemit_v2d_control, +}; +#endif + +static void spacemit_v2d_isr(int irqno, void *param) +{ + rt_uint32_t irq_status; + rt_uint32_t error_status; + struct spacemit_v2d *v2d = param; + + RT_UNUSED(irqno); + + irq_status = v2d_irq_status(); + error_status = v2d_irqerr_status(); + + if (error_status) + { + v2d_irqerr_clear(error_status); + v2d->error_status |= error_status; + v2d->error = -RT_EIO; + } + if (irq_status) + { + v2d_irq_clear(irq_status); + v2d->irq_status |= irq_status; + } + + if (error_status || (irq_status & + (V2D_EOF_IRQ_STATUS | V2D_FBCENC_IRQ_STATUS))) + { + rt_completion_done(&v2d->completion); + } +} + +static rt_err_t v2d_clocks_enable(struct spacemit_v2d *v2d) +{ + rt_err_t err; + + if ((err = rt_clk_prepare_enable(v2d->clk_core)) != RT_EOK) + { + return err; + } + if ((err = rt_clk_prepare_enable(v2d->clk_io)) != RT_EOK) + { + rt_clk_disable_unprepare(v2d->clk_core); + return err; + } + + v2d->clocks_enabled = RT_TRUE; + + return RT_EOK; +} + +static void v2d_clocks_disable(struct spacemit_v2d *v2d) +{ + if (!v2d->clocks_enabled) + { + return; + } + + if (!rt_is_err_or_null(v2d->clk_io)) + { + rt_clk_disable_unprepare(v2d->clk_io); + } + if (!rt_is_err_or_null(v2d->clk_core)) + { + rt_clk_disable_unprepare(v2d->clk_core); + } + v2d->clocks_enabled = RT_FALSE; +} + +static void spacemit_v2d_free(struct spacemit_v2d *v2d) +{ + struct spacemit_v2d_buffer *entry, *next; + + if (v2d->dev && v2d->dev->user_data == v2d) + { + v2d->dev->user_data = RT_NULL; + } + + rt_list_for_each_entry_safe(entry, next, &v2d->buffers, list) + { + rt_list_remove(&entry->list); + rt_dma_free_coherent(v2d->dev, entry->buffer.size, + entry->buffer.virt_addr, entry->buffer.phys_addr); + rt_free(entry); + } + + if (v2d->device_registered) + { + rt_device_unregister(&v2d->parent); + v2d->device_registered = RT_FALSE; + } + if (v2d->lock_initialized) + { + rt_mutex_detach(&v2d->lock); + v2d->lock_initialized = RT_FALSE; + } + + if (v2d->reset_deasserted && !rt_is_err_or_null(v2d->reset)) + { + rt_reset_control_assert(v2d->reset); + v2d->reset_deasserted = RT_FALSE; + } + + v2d_clocks_disable(v2d); + + if (!rt_is_err_or_null(v2d->clk_io)) + { + rt_clk_put(v2d->clk_io); + } + if (!rt_is_err_or_null(v2d->clk_core)) + { + rt_clk_put(v2d->clk_core); + } + if (!rt_is_err_or_null(v2d->reset)) + { + rt_reset_control_put(v2d->reset); + } + if (v2d->regs) + { + v2d_hw_set_base(RT_NULL); + rt_iounmap(v2d->regs); + } + + rt_free(v2d); +} + +static rt_err_t spacemit_v2d_probe(struct rt_platform_device *pdev) +{ + const char *dev_name; + rt_err_t err; + struct rt_device *dev = &pdev->parent; + struct spacemit_v2d *v2d = rt_calloc(1, sizeof(*v2d)); + + if (!v2d) + { + return -RT_ENOMEM; + } + v2d->dev = dev; + rt_list_init(&v2d->buffers); + + v2d->regs = rt_dm_dev_iomap(dev, 0); + if (!v2d->regs) + { + err = -RT_EIO; + goto _fail; + } + v2d_hw_set_base(v2d->regs); + + v2d->clk_core = rt_clk_get_by_name(dev, "v2d-core"); + if (rt_is_err(v2d->clk_core)) + { + err = rt_ptr_err(v2d->clk_core); + goto _fail; + } + v2d->clk_io = rt_clk_get_by_name(dev, "v2d-io"); + if (rt_is_err(v2d->clk_io)) + { + err = rt_ptr_err(v2d->clk_io); + goto _fail; + } + if ((err = v2d_clocks_enable(v2d)) != RT_EOK) + { + goto _fail; + } + if ((err = rt_clk_set_rate(v2d->clk_core, V2D_CORE_RATE)) != RT_EOK) + { + goto _fail; + } + + v2d->reset = rt_reset_control_get_by_name(dev, "v2d_reset"); + if (rt_is_err(v2d->reset)) + { + err = rt_ptr_err(v2d->reset); + goto _fail; + } + if ((err = rt_reset_control_deassert(v2d->reset)) != RT_EOK) + { + goto _fail; + } + v2d->reset_deasserted = RT_TRUE; + if ((err = v2d_global_reset()) != RT_EOK) + { + goto _fail; + } + + v2d->irq = rt_dm_dev_get_irq(dev, 0); + if (v2d->irq < 0) + { + err = v2d->irq; + goto _fail; + } + + if ((err = rt_dm_dev_set_name_auto(&v2d->parent, "v2d")) < 0) + { + goto _fail; + } + dev_name = rt_dm_dev_get_name(&v2d->parent); + v2d->parent.type = RT_Device_Class_Char; +#ifdef RT_USING_DEVICE_OPS + v2d->parent.ops = &spacemit_v2d_ops; +#else + v2d->parent.control = spacemit_v2d_control; +#endif + dev->user_data = v2d; + + if ((err = rt_mutex_init(&v2d->lock, dev_name, + RT_IPC_FLAG_PRIO)) != RT_EOK) + { + goto _fail; + } + v2d->lock_initialized = RT_TRUE; + rt_completion_init(&v2d->completion); + + if ((err = rt_device_register(&v2d->parent, dev_name, + RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_STANDALONE)) != RT_EOK) + { + goto _fail; + } + v2d->device_registered = RT_TRUE; + + v2d_irq_disable(); + + rt_hw_interrupt_install(v2d->irq, spacemit_v2d_isr, v2d, "v2d"); + rt_hw_interrupt_umask(v2d->irq); + + return RT_EOK; + +_fail: + spacemit_v2d_free(v2d); + return err; +} + +static rt_err_t spacemit_v2d_remove(struct rt_platform_device *pdev) +{ + struct spacemit_v2d *v2d = pdev->parent.user_data; + + rt_hw_interrupt_mask(v2d->irq); + rt_pic_detach_irq(v2d->irq, v2d); + spacemit_v2d_free(v2d); + + return RT_EOK; +} + +static const struct rt_ofw_node_id spacemit_v2d_ofw_ids[] = +{ + { .compatible = "spacemit,v2d" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver spacemit_v2d_driver = +{ + .name = "spacemit-v2d", + .ids = spacemit_v2d_ofw_ids, + .probe = spacemit_v2d_probe, + .remove = spacemit_v2d_remove, +}; +RT_PLATFORM_DRIVER_EXPORT(spacemit_v2d_driver); diff --git a/bsp/spacemit/dm/soc/v2d/v2d_hw.c b/bsp/spacemit/dm/soc/v2d/v2d_hw.c new file mode 100644 index 000000000000..603774626dbd --- /dev/null +++ b/bsp/spacemit/dm/soc/v2d/v2d_hw.c @@ -0,0 +1,1092 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#include "v2d_internal.h" +#include "v2d_reg.h" + +static const int cscmatrix[V2D_CSC_MODE_BUTT][3][4] = +{ + /* RGB2BT601Wide */ + {{ 306, 601, 117, 0 }, + { -173, -339, 512, 128 }, + { 512, -429, -83, 128 }}, + + /* BT601Wide2RGB */ + {{ 1024, 0, 1436, -179 }, + { 1024, -352, -731, 135 }, + { 1024, 1815, 0, -227 }}, + + /* RGB2BT601Narrow */ + {{ 263, 516, 100, 16 }, + { -152, -298, 450, 128 }, + { 450, -377, -73, 128 }}, + + /* BT601Narrow2RGB */ + {{ 1192, 0, 1634, -223 }, + { 1192, -401, -832, 136 }, + { 1192, 2066, 0, -277 }}, + + /* RGB2BT709Wide */ + {{ 218, 732, 74, 0 }, + { -117, -395, 512, 128 }, + { 512, -465, -47, 128 }}, + + /* BT709Wide2RGB */ + {{ 1024, 0, 1613, -202 }, + { 1024, -192, -479, 84 }, + { 1024, 1900, 0, -238 }}, + + /* RGB2BT709Narrow */ + {{ 187, 629, 63, 16 }, + { -103, -347, 450, 128}, + { 450, -409, -41, 128}}, + + /* BT709Narrow2RGB */ + {{ 1192, 0, 1836, -248 }, + { 1192, -218, -546, 77 }, + { 1192, 2163, 0, -289 }}, + + /* BT601Wide2BT709Wide */ + {{ 1024, -121, -218, 42 }, + { 0, 1043, 117, -17 }, + { 0, 77, 1050, -13 }}, + + /* BT601Wide2BT709Narrow */ + {{ 879, -104, -187, 52 }, + { 0, 916, 103, 1 }, + { 0, 68, 922, 4 }}, + + /* BT601Wide2BT601Narrow */ + {{ 879, 0, 0, 16 }, + { 0, 900, 0, 16 }, + { 0, 0, 900, 16 }}, + + /* BT601Narrow2BT709Wide */ + {{ 1192, -138, -248, 30 }, + { 0, 1187, 134, -37 }, + { 0, 88, 1195, -32 }}, + + /* BT601Narrow2BT709Narrow */ + {{ 1024, -118, -213, 41 }, + { 0, 1043, 117, -17 }, + { 0, 77, 1050, -13 }}, + + /* BT601Narrow2BT601Wide */ + {{ 1192, 0, 0, -19 }, + { 0, 1166, 0, -18 }, + { 0, 0, 1166, -18 }}, + + /* BT709Wide2BT601Wide */ + {{ 1024, 104, 201, -38 }, + { 0, 1014, -113, 15 }, + { 0, -74, 1007, 11 }}, + + /* BT709Wide2BT601Narrow */ + {{ 879, 89, 172, -17 }, + { 0, 890, -100, 29 }, + { 0, -65, 885, 26 }}, + + /* BT709Wide2BT709Narrow */ + {{ 879, 0, 0, 16 }, + { 0, 900, 0, 16 }, + { 0, 0, 900, 16 }}, + + /* BT709Narrow2BT601Wide */ + {{ 1192, 118, 229, -62 }, + { 0, 1154, -129, 0 }, + { 0, -85, 1146, -5 }}, + + /* BT709Narrow2BT601Narrow */ + {{ 1024, 102, 196, -37 }, + { 0, 1014, -113, 15 }, + { 0, -74, 1007, 11 }}, + + /* BT709Narrow2BT709Wide */ + {{ 1192, 0, 0, -19 }, + { 0, 1166, 0, -18 }, + { 0, 0, 1166, -18 }}, + + /* RGB2Grey */ + {{ 218, 732, 74, 0 }, + { -117, -395, 512, 128 }, + { 512, -465, -47, 128 }}, + + /* RGB2RGB */ + {{ 1024, 0, 0, 0 }, + { 0, 1024, 0, 0 }, + { 0, 0, 1024, 0 }} +}; + +enum +{ + R = 0, + G, + B, + A +}; + +static const int32_t bicubic_coef[16][3] = +{ + { 246, 507, 246 }, + { 222, 505, 270 }, + { 199, 501, 294 }, + { 177, 494, 318 }, + { 155, 486, 342 }, + { 136, 474, 365 }, + { 117, 461, 387 }, + { 100, 445, 408 }, + { 85, 427, 427 }, + { 71, 408, 445 }, + { 59, 387, 461 }, + { 49, 365, 474 }, + { 41, 343, 485 }, + { 35, 318, 494 }, + { 30, 294, 501 }, + { 27, 270, 505 } +}; + +static void *v2d_reg_base; + +void v2d_hw_set_base(void *base) +{ + v2d_reg_base = base; +} + +rt_inline void v2d_write(uint32_t reg, uint32_t val) +{ + HWREG32((rt_uint8_t *)v2d_reg_base + reg) = val; +} + +rt_inline uint32_t v2d_read(uint32_t reg) +{ + return HWREG32((rt_uint8_t *)v2d_reg_base + reg); +} + +rt_inline void v2d_set_bits(uint32_t reg, uint32_t bits) +{ + v2d_write(reg, v2d_read(reg) | bits); +} + +rt_inline void v2d_clear_bits(uint32_t reg, uint32_t bits) +{ + v2d_write(reg, v2d_read(reg) & ~bits); +} + +static void v2d_write_bits(uint32_t reg, uint32_t value, uint32_t mask, uint32_t shifts) +{ + uint32_t reg_val; + + reg_val = v2d_read(reg); + reg_val &= ~(mask << shifts); + reg_val |= (value << shifts); + v2d_write(reg, reg_val); +} + +int v2d_global_reset(void) +{ + int timeout = 10000; + + v2d_set_bits(V2D_AUTO_CLK_REG, V2D_GLOBAL_RESET); + while ((v2d_read(V2D_AUTO_CLK_REG) & V2D_GLOBAL_RESET) && --timeout) + { + rt_hw_us_delay(1); + } + + if (!timeout) + { + LOG_E("global reset timeout"); + return -RT_ETIMEOUT; + } + + return RT_EOK; +} + +uint32_t v2d_irq_status(void) +{ + return v2d_read(V2D_IRQ_STATUS); +} + +void v2d_dump_irqraw_status(void) +{ + uint32_t irqerr_raw, encirq, dec0_irqraw, dec1_irqraw; + irqerr_raw = v2d_read(V2D_ERR_IRQ_RAW); + dec0_irqraw = v2d_read(V2D_L0_DEC_REG8); + dec1_irqraw = v2d_read(V2D_L1_DEC_REG8); + encirq = v2d_read(V2D_ENC_REG18); + LOG_E("raw status: core=%08x dec0=%08x dec1=%08x enc=%08x", + irqerr_raw, dec0_irqraw, dec1_irqraw, encirq); +} + +uint32_t v2d_irqerr_status(void) +{ + return v2d_read(V2D_ERR_IRQ_STATUS); +} + +void v2d_irqerr_clear(uint32_t irqerr) +{ + v2d_write(V2D_ERR_IRQ_STATUS, irqerr); +} + +void v2d_irq_clear(uint32_t irqstaus) +{ + v2d_write(V2D_ENC_REG18, 0x3ffff); + v2d_write(V2D_IRQ_STATUS, irqstaus); +} + +void v2d_irq_enable(void) +{ + v2d_write(V2D_IRQ_MASK, V2D_EOF_IRQ_MASK|V2D_FBCENC_IRQ_MASK); + v2d_write(V2D_ERR_IRQ_MASK, 0xE07); + v2d_write_bits(V2D_DEBUG_REG0, 0x1, 0x1, 0); +} + +void v2d_irq_disable(void) +{ + v2d_write(V2D_IRQ_MASK, 0x00); + v2d_write(V2D_ERR_IRQ_MASK, 0x00); +} + +static void ConfigAxiBus(void) +{ + v2d_axi_bus_ctrl_reg_t ctrl; + + ctrl.overlay = 0; + ctrl.field.arqos_m = 2; + ctrl.field.awqos_m = 2; + ctrl.field.shadow_mode = 1; + v2d_write(V2D_AXI_BUS_CTRL, ctrl.overlay); +} + +int getBytePerPixel(V2D_COLOR_FORMAT_E enFormat) +{ + int Bpp=0; + + switch (enFormat) + { + case V2D_COLOR_FORMAT_NV12: + case V2D_COLOR_FORMAT_NV21: + Bpp = 1; + break; + case V2D_COLOR_FORMAT_RGB888: + case V2D_COLOR_FORMAT_BGR888: + Bpp = 3; + break; + case V2D_COLOR_FORMAT_RGBX8888: + case V2D_COLOR_FORMAT_RGBA8888: + case V2D_COLOR_FORMAT_ARGB8888: + case V2D_COLOR_FORMAT_BGRX8888: + case V2D_COLOR_FORMAT_BGRA8888: + case V2D_COLOR_FORMAT_ABGR8888: + Bpp = 4; + break; + case V2D_COLOR_FORMAT_RGB565: + case V2D_COLOR_FORMAT_BGR565: + Bpp = 2; + break; + case V2D_COLOR_FORMAT_RGBA5658: + case V2D_COLOR_FORMAT_ARGB8565: + case V2D_COLOR_FORMAT_BGRA5658: + case V2D_COLOR_FORMAT_ABGR8565: + Bpp = 3; + break; + case V2D_COLOR_FORMAT_A8: + case V2D_COLOR_FORMAT_Y8: + Bpp = 1; + break; + default: + LOG_E("err format: %d not supported",enFormat); + } + return Bpp; +} + +static void v2d_scaler_coef_init(void) +{ + const int32_t *pCoef; + v2d_scaler_coef_reg_t scaler_coef; + + scaler_coef.overlay = 0; + pCoef = &bicubic_coef[0][0]; + for (int i=0; i> 8) & 0xFF; + b = (fillcolor >> 16) & 0xFF; + a = 0xFF; + break; + case V2D_COLOR_FORMAT_NV21: + r = fillcolor & 0xFF; + b = (fillcolor >> 8) & 0xFF; + g = (fillcolor >> 16) & 0xFF; + a = 0xFF; + break; + case V2D_COLOR_FORMAT_RGB888: + case V2D_COLOR_FORMAT_RGBX8888: + r = fillcolor & 0xFF; + g = (fillcolor >> 8) & 0xFF; + b = (fillcolor >> 16) & 0xFF; + a = 0xFF; + break; + case V2D_COLOR_FORMAT_RGBA8888: + r = fillcolor & 0xFF; + g = (fillcolor >> 8) & 0xFF; + b = (fillcolor >> 16) & 0xFF; + a = (fillcolor >> 24) & 0xFF; + break; + case V2D_COLOR_FORMAT_ARGB8888: + a = fillcolor & 0xFF; + r = (fillcolor >> 8) & 0xFF; + g = (fillcolor >> 16) & 0xFF; + b = (fillcolor >> 24) & 0xFF; + break; + case V2D_COLOR_FORMAT_RGB565: + a = 0xFF; + r = fillcolor & 0x1F; + g = (fillcolor >> 5) & 0x3F; + b = (fillcolor >> 11) & 0x1F; + break; + case V2D_COLOR_FORMAT_RGBA5658: + r = fillcolor & 0x1F; + g = (fillcolor >> 5) & 0x3F; + b = (fillcolor >> 11) & 0x1F; + a = (fillcolor >> 16) & 0xFF; + break; + case V2D_COLOR_FORMAT_ARGB8565: + a = fillcolor & 0xFF; + r = (fillcolor >> 8) & 0x1F; + g = (fillcolor >> 13) & 0x3F; + b = (fillcolor >> 19) & 0x1F; + break; + case V2D_COLOR_FORMAT_BGR888: + case V2D_COLOR_FORMAT_BGRX8888: + b = fillcolor & 0xFF; + g = (fillcolor >> 8) & 0xFF; + r = (fillcolor >> 16) & 0xFF; + a = 0xFF; + break; + case V2D_COLOR_FORMAT_BGRA8888: + b = fillcolor & 0xFF; + g = (fillcolor >> 8) & 0xFF; + r = (fillcolor >> 16) & 0xFF; + a = (fillcolor >> 24) & 0xFF; + break; + case V2D_COLOR_FORMAT_ABGR8888: + a = fillcolor & 0xFF; + b = (fillcolor >> 8) & 0xFF; + g = (fillcolor >> 16) & 0xFF; + r = (fillcolor >> 24) & 0xFF; + break; + case V2D_COLOR_FORMAT_BGR565: + a = 0xFF; + b = fillcolor & 0x1F; + g = (fillcolor >> 5) & 0x3F; + r = (fillcolor >> 11) & 0x1F; + break; + case V2D_COLOR_FORMAT_BGRA5658: + b = fillcolor & 0x1F; + g = (fillcolor >> 5) & 0x3F; + r = (fillcolor >> 11) & 0x1F; + a = (fillcolor >> 16) & 0xFF; + break; + case V2D_COLOR_FORMAT_ABGR8565: + a = fillcolor & 0xFF; + b = (fillcolor >> 8) & 0x1F; + g = (fillcolor >> 13) & 0x3F; + r = (fillcolor >> 19) & 0x1F; + break; + default: + r = 0xFF; + g = 0xFF; + b = 0xFF; + a = 0xFF; + break; + } + pChl[R] = r; + pChl[G] = g; + pChl[B] = b; + pChl[A] = a; +} + +static bool do_swap(V2D_COLOR_FORMAT_E enFormatIn) +{ + switch (enFormatIn) + { + case V2D_COLOR_FORMAT_BGR888: + case V2D_COLOR_FORMAT_BGRX8888: + case V2D_COLOR_FORMAT_BGRA8888: + case V2D_COLOR_FORMAT_ABGR8888: + case V2D_COLOR_FORMAT_BGR565: + case V2D_COLOR_FORMAT_BGRA5658: + case V2D_COLOR_FORMAT_ABGR8565: + case V2D_COLOR_FORMAT_NV21: + case V2D_COLOR_FORMAT_L8_BGR565: + case V2D_COLOR_FORMAT_L8_BGR888: + case V2D_COLOR_FORMAT_L8_BGRA8888: + return RT_TRUE; + default: + return RT_FALSE; + } +} + +static bool do_narrow(V2D_CSC_MODE_E enForeCSCMode, V2D_CSC_MODE_E enBackCSCMode) +{ + int ret = RT_FALSE; + + switch (enForeCSCMode) + { + case V2D_CSC_MODE_RGB_2_BT601NARROW: + case V2D_CSC_MODE_RGB_2_BT709NARROW: + case V2D_CSC_MODE_BT601WIDE_2_BT709NARROW: + case V2D_CSC_MODE_BT601WIDE_2_BT601NARROW: + case V2D_CSC_MODE_BT601NARROW_2_BT709NARROW: + case V2D_CSC_MODE_BT709WIDE_2_BT601NARROW: + case V2D_CSC_MODE_BT709WIDE_2_BT709NARROW: + case V2D_CSC_MODE_BT709NARROW_2_BT601NARROW: + ret = RT_TRUE; + break; + default: + break; + } + switch (enBackCSCMode) + { + case V2D_CSC_MODE_RGB_2_BT601NARROW: + case V2D_CSC_MODE_RGB_2_BT709NARROW: + case V2D_CSC_MODE_BT601WIDE_2_BT709NARROW: + case V2D_CSC_MODE_BT601WIDE_2_BT601NARROW: + case V2D_CSC_MODE_BT601NARROW_2_BT709NARROW: + case V2D_CSC_MODE_BT709WIDE_2_BT601NARROW: + case V2D_CSC_MODE_BT709WIDE_2_BT709NARROW: + case V2D_CSC_MODE_BT709NARROW_2_BT601NARROW: + ret = RT_TRUE; + break; + default: + break; + } + return ret; +} + +static V2D_COLOR_FORMAT_E fmt_convert(V2D_COLOR_FORMAT_E enFormatIn) +{ + V2D_COLOR_FORMAT_E enFormatOut = 0; + + switch (enFormatIn) + { + case V2D_COLOR_FORMAT_RGB888: + case V2D_COLOR_FORMAT_RGBX8888: + case V2D_COLOR_FORMAT_RGBA8888: + case V2D_COLOR_FORMAT_ARGB8888: + case V2D_COLOR_FORMAT_RGB565: + case V2D_COLOR_FORMAT_NV12: + case V2D_COLOR_FORMAT_RGBA5658: + case V2D_COLOR_FORMAT_ARGB8565: + case V2D_COLOR_FORMAT_A8: + case V2D_COLOR_FORMAT_Y8: + enFormatOut = enFormatIn; + break; + case V2D_COLOR_FORMAT_BGR888: + case V2D_COLOR_FORMAT_BGRX8888: + case V2D_COLOR_FORMAT_BGRA8888: + case V2D_COLOR_FORMAT_ABGR8888: + case V2D_COLOR_FORMAT_BGR565: + case V2D_COLOR_FORMAT_NV21: + case V2D_COLOR_FORMAT_BGRA5658: + case V2D_COLOR_FORMAT_ABGR8565: + enFormatOut = enFormatIn - V2D_COLOR_FORMAT_BGR888; + break; + case V2D_COLOR_FORMAT_L8_RGBA8888: + case V2D_COLOR_FORMAT_L8_RGB888: + case V2D_COLOR_FORMAT_L8_RGB565: + case V2D_COLOR_FORMAT_L8_BGRA8888: + case V2D_COLOR_FORMAT_L8_BGR888: + case V2D_COLOR_FORMAT_L8_BGR565: + enFormatOut = V2D_COLOR_FORMAT_L8_RGBA8888; + break; + default: + break; + } + return enFormatOut; +} + +static int Get_L8_Palette_bytePerPixel(V2D_SURFACE_S *pstBackGround, V2D_SURFACE_S *pstForeGround) +{ + int bpp = 4; + + if (pstBackGround) + { + if (pstBackGround->format == V2D_COLOR_FORMAT_L8_RGBA8888 || pstBackGround->format == V2D_COLOR_FORMAT_L8_BGRA8888) + { + bpp = 4; + } + else if (pstBackGround->format == V2D_COLOR_FORMAT_L8_RGB888 || pstBackGround->format == V2D_COLOR_FORMAT_L8_BGR888) + { + bpp = 3; + } + else if (pstBackGround->format == V2D_COLOR_FORMAT_L8_RGB565 || pstBackGround->format == V2D_COLOR_FORMAT_L8_BGR565) + { + bpp = 2; + } + } + if (pstForeGround) + { + if (pstForeGround->format == V2D_COLOR_FORMAT_L8_RGBA8888 || pstForeGround->format == V2D_COLOR_FORMAT_L8_BGRA8888) + { + bpp = 4; + } + else if (pstForeGround->format == V2D_COLOR_FORMAT_L8_RGB888 || pstForeGround->format == V2D_COLOR_FORMAT_L8_BGR888) + { + bpp = 3; + } + else if (pstForeGround->format == V2D_COLOR_FORMAT_L8_RGB565 || pstForeGround->format == V2D_COLOR_FORMAT_L8_BGR565) + { + bpp = 2; + } + } + return bpp; +} + +static void ConfigV2dFbcDecoder(V2D_SURFACE_S *pstV2DSurface, V2D_INPUT_LAYER_E enInputLayer) +{ + v2d_fbc_decoder_bbox_reg_t bbox_x = { 0 }, bbox_y = { 0 }; + v2d_fbc_decoder_imgae_size_reg_t img_size = { 0 }; + v2d_fbc_decoder_mode_reg_t dec_mode = { 0 }; + v2d_fbc_decoder_dma_ctrl_reg_t dmac = { 0 }; + v2d_fbc_decoder_irq_ctrl_reg_t irqmask = { 0 }; + FBC_DECODER_S *pDecInfo = &pstV2DSurface->fbcDecInfo; + + LOG_D("config %s fbc decoder", (enInputLayer > 0 ? "layer1" : "layer0")); + bbox_x.field.bbox_start = pDecInfo->bboxLeft; + bbox_x.field.bbox_end = pDecInfo->bboxRight; + bbox_y.field.bbox_start = pDecInfo->bboxTop; + bbox_y.field.bbox_end = pDecInfo->bboxBottom; + img_size.field.width = pstV2DSurface->w; + img_size.field.height = pstV2DSurface->h; + dec_mode.field.mode = pDecInfo->enFbcdecMode; + dec_mode.field.format = pDecInfo->enFbcdecFmt; + dec_mode.field.is_split = pDecInfo->is_split; + dec_mode.field.rgb_pack_en = pDecInfo->rgb_pack_en; + dmac.overlay = 0xffff1a02; + irqmask.overlay = 0x00000017; + + v2d_write(V2D_LAYER_DEC_REG0_L(enInputLayer), pDecInfo->headerAddr_l); + v2d_write(V2D_LAYER_DEC_REG1_L(enInputLayer), pDecInfo->headerAddr_h); + v2d_write(V2D_LAYER_DEC_REG2_L(enInputLayer), bbox_x.overlay); + v2d_write(V2D_LAYER_DEC_REG3_L(enInputLayer), bbox_y.overlay); + v2d_write(V2D_LAYER_DEC_REG4_L(enInputLayer), img_size.overlay); + v2d_write(V2D_LAYER_DEC_REG5_L(enInputLayer), dec_mode.overlay); + v2d_write(V2D_LAYER_DEC_REG6_L(enInputLayer), dmac.overlay); + v2d_write(V2D_LAYER_DEC_REG7_L(enInputLayer), irqmask.overlay); +} + +static void ConfigV2dFbcEncoder(V2D_SURFACE_S *pstV2DSurface) +{ + v2d_fbc_encoder_bbox_reg_t bbox_x = { 0 }, bbox_y = { 0 }; + v2d_fbc_encoder_buf_size_reg_t y_buf_size = { 0 }, uv_buf_size = { 0 }; + v2d_fbc_encoder_irq_reg_t irqmask = { 0 }; + v2d_fbc_encoder_mode_reg_t enc_mode = { 0 }; + v2d_fbc_encoder_dmac_burst_reg_t dmac_burst = { 0 }; + FBC_ENCODER_S *pEncInfo = &pstV2DSurface->fbcEncInfo; + + LOG_D("config fbc encoder"); + bbox_x.field.bbox_start = pEncInfo->bboxLeft; + bbox_x.field.bbox_end = pEncInfo->bboxRight; + bbox_y.field.bbox_start = pEncInfo->bboxTop; + bbox_y.field.bbox_end = pEncInfo->bboxBottom; + y_buf_size.field.x_size = pstV2DSurface->w; + y_buf_size.field.y_size = pstV2DSurface->h; + uv_buf_size.field.x_size = pstV2DSurface->w >> 1; + uv_buf_size.field.y_size = pstV2DSurface->w >> 1; + irqmask.overlay = 0x0001ffff; + enc_mode.field.encode_enable = 1; + enc_mode.field.split_mode_en = pEncInfo->is_split; + enc_mode.field.img_pix_format = pEncInfo->enFbcencFmt; + dmac_burst.field.burst_length = 0x10; + + v2d_write(V2D_ENC_REG0, pEncInfo->headerAddr_l); + v2d_write(V2D_ENC_REG1, pEncInfo->headerAddr_h); + v2d_write(V2D_ENC_REG2, pEncInfo->payloadAddr_l); + v2d_write(V2D_ENC_REG3, pEncInfo->payloadAddr_h); + v2d_write(V2D_ENC_REG4, bbox_x.overlay); + v2d_write(V2D_ENC_REG5, bbox_y.overlay); + v2d_write(V2D_ENC_REG10, y_buf_size.overlay); + v2d_write(V2D_ENC_REG11, uv_buf_size.overlay); + v2d_write(V2D_ENC_REG13, irqmask.overlay); + v2d_write(V2D_ENC_REG15, 0x9e00ffff); + v2d_write(V2D_ENC_REG16, enc_mode.overlay); + v2d_write(V2D_ENC_REG17, dmac_burst.overlay); +} + +static void ConfigV2dInputLayer(V2D_SURFACE_S *pstV2DSurface, + V2D_AREA_S *pstV2DArea, + V2D_BLEND_CONF_S *pstBlendConf, + V2D_ROTATE_ANGLE_E enRotateAngle, + V2D_CSC_MODE_E enCSCMode, + V2D_INPUT_LAYER_E enInputLayer) +{ + const int *pCscMatrix; + V2D_SCALER_MODE_E enScaleMode = V2D_NO_SCALE; + uint32_t width = 0, height = 0; + V2D_FILLCOLOR_S *pFillColor; uint8_t chl[4]; + V2D_BLEND_LAYER_CONF_S *pBlendLayerConf; + v2d_blend_layer_ctrl0_reg_t bld_layer_ctrl0 = { 0 }; + v2d_blend_layer_ctrl1_reg_t bld_layer_ctrl1 = { 0 }; + v2d_blend_layer_ctrl2_reg_t bld_layer_ctrl2 = { 0 }; + v2d_blend_layer_ctrl3_reg_t bld_layer_ctrl3 = { 0 }; + v2d_blend_layer_factor_reg_t bld_layer_factor = { 0 }; + v2d_solid_color_ctrl0_reg_t solidcolor_ctrl0 = { 0 }; + v2d_solid_color_ctrl1_reg_t solidcolor_ctrl1 = { 0 }; + v2d_input_layer_width_height_reg_t layer_in_ori_w_h = { 0 }; + v2d_input_layer_ctrl_reg_t layer_in_ctrl = { 0 }; + v2d_input_layer_crop0_reg_t layer_in_crop0 = { 0 }; + v2d_input_layer_crop1_reg_t layer_in_crop1 = { 0 }; + v2d_input_layer_csc_ctrl0_reg_t layer_in_csc_ctrl0 = { 0 }; + v2d_input_layer_csc_ctrl1_reg_t layer_in_csc_ctrl1 = { 0 }; + v2d_input_layer_csc_ctrl2_reg_t layer_in_csc_ctrl2 = { 0 }; + v2d_input_layer_scale_mode_reg_t layer_scale_mode = { 0 }; + v2d_input_layer_scale_delta_x_reg_t layer_scale_delta_x = { 0 }; + v2d_input_layer_scale_delta_y_reg_t layer_scale_delta_y = { 0 }; + + bld_layer_ctrl1.overlay = 0; + bld_layer_ctrl3.overlay = 0; + bld_layer_factor.overlay = 0; + solidcolor_ctrl0.overlay = 0; + solidcolor_ctrl1.overlay = 0; + layer_in_ctrl.overlay = 0; + layer_in_csc_ctrl0.overlay = 0; + layer_in_csc_ctrl1.overlay = 0; + layer_in_csc_ctrl2.overlay = 0; + layer_scale_mode.overlay = 0; + layer_scale_delta_x.overlay = 0; + layer_scale_delta_y.overlay = 0; + + if ((!pstV2DSurface->solidcolor.enable) && + (pstV2DSurface->phyaddr_y_l == 0) && + (pstV2DSurface->phyaddr_y_h == 0) && + (!pstV2DSurface->fbc_enable)) + { + LOG_D("%s disable", (enInputLayer > 0 ? "layer1" : "layer0")); + bld_layer_ctrl1.field.blend_en = V2D_FUNC_DISABLE; + v2d_write(V2D_LAYER_BLD_CTRL1_LAYER(enInputLayer), bld_layer_ctrl1.overlay); + } + else + { + LOG_D("config %s rot: %d, csc: %d", (enInputLayer > 0 ? "layer1" : "layer0"), enRotateAngle, enCSCMode); + /* blendlayer */ + pBlendLayerConf = &pstBlendConf->blendlayer[enInputLayer]; + bld_layer_ctrl0.field.bld_alpha_source = pBlendLayerConf->blend_alpha_source; + bld_layer_ctrl0.field.bld_pre_alp_func = pBlendLayerConf->blend_pre_alpha_func; + bld_layer_ctrl0.field.bld_glb_alp = pBlendLayerConf->global_alpha; + bld_layer_ctrl0.field.scl_delta_y = 0; + bld_layer_ctrl1.field.blend_en = V2D_FUNC_ENABLE; + bld_layer_ctrl1.field.bld_rect_ltop_x = pBlendLayerConf->blend_area.x; + bld_layer_ctrl2.field.bld_rect_ltop_y = pBlendLayerConf->blend_area.y; + bld_layer_ctrl2.field.bld_rect_width = pBlendLayerConf->blend_area.w; + bld_layer_ctrl3.field.bld_rect_height = pBlendLayerConf->blend_area.h; + LOG_D("bld alpha_src: %d,pre_func: %d,glb_alpha: %d", pBlendLayerConf->blend_alpha_source, pBlendLayerConf->blend_pre_alpha_func, pBlendLayerConf->global_alpha); + LOG_D("bld_rect:(%d,%d,%d,%d)", pBlendLayerConf->blend_area.x, pBlendLayerConf->blend_area.y, pBlendLayerConf->blend_area.w, pBlendLayerConf->blend_area.h); + v2d_write(V2D_LAYER_BLD_CTRL0_LAYER(enInputLayer), bld_layer_ctrl0.overlay); + v2d_write(V2D_LAYER_BLD_CTRL1_LAYER(enInputLayer), bld_layer_ctrl1.overlay); + v2d_write(V2D_LAYER_BLD_CTRL2_LAYER(enInputLayer), bld_layer_ctrl2.overlay); + v2d_write(V2D_LAYER_BLD_CTRL3_LAYER(enInputLayer), bld_layer_ctrl3.overlay); + + bld_layer_factor.field.in_addr_uv_33_32 = pstV2DSurface->phyaddr_uv_h & V2D_H_ADDR_MASK; + if (pstBlendConf->blend_cmd) + { + bld_layer_factor.field.bld_color_rop2_code = pBlendLayerConf->stRop2Code.colorRop2Code; + bld_layer_factor.field.bld_alpha_rop2_code = pBlendLayerConf->stRop2Code.alphaRop2Code; + } + else + { + bld_layer_factor.field.bld_src_color_factor = pBlendLayerConf->stBlendFactor.srcColorFactor; + bld_layer_factor.field.bld_src_alpha_factor = pBlendLayerConf->stBlendFactor.srcAlphaFactor; + bld_layer_factor.field.bld_dst_color_factor = pBlendLayerConf->stBlendFactor.dstColorFactor; + bld_layer_factor.field.bld_dst_alpha_factor = pBlendLayerConf->stBlendFactor.dstAlphaFactor; + } + LOG_D("bld factor:src_c=%d,src_a=%d,dst_c=%d,dst_a=%d", pBlendLayerConf->stBlendFactor.srcColorFactor, pBlendLayerConf->stBlendFactor.srcAlphaFactor, + pBlendLayerConf->stBlendFactor.dstColorFactor, pBlendLayerConf->stBlendFactor.dstAlphaFactor); + v2d_write(V2D_LAYER_BLD_FACTOR_LAYER(enInputLayer), bld_layer_factor.overlay); + + if (pstV2DSurface->solidcolor.enable) + { + /* solid color */ + pFillColor = &pstV2DSurface->solidcolor.fillcolor; + split_fillcolor(pFillColor->colorvalue, pFillColor->format, chl); + solidcolor_ctrl0.field.solid_en = V2D_FUNC_ENABLE; + solidcolor_ctrl0.field.solid_R = chl[R]; + solidcolor_ctrl0.field.solid_G = chl[G]; + solidcolor_ctrl0.field.solid_B = chl[B]; + solidcolor_ctrl1.field.solid_A = chl[A]; + solidcolor_ctrl1.field.csc_en = V2D_FUNC_DISABLE; + v2d_write(V2D_LAYER_SOLIDCOLOR_CTRL0_LAYER(enInputLayer), solidcolor_ctrl0.overlay); + v2d_write(V2D_LAYER_SOLIDCOLOR_CTRL1_LAYER(enInputLayer), solidcolor_ctrl1.overlay); + } + else + { + /* input layer */ + solidcolor_ctrl0.field.solid_en = V2D_FUNC_DISABLE; + v2d_write(V2D_LAYER_SOLIDCOLOR_CTRL0_LAYER(enInputLayer), solidcolor_ctrl0.overlay); + if (pstV2DSurface->fbc_enable) + { + ConfigV2dFbcDecoder(pstV2DSurface, enInputLayer); + } + else + { + v2d_write(V2D_LAYER_Y_ADDR_L_LAYER(enInputLayer), pstV2DSurface->phyaddr_y_l); + v2d_write(V2D_LAYER_Y_ADDR_H_LAYER(enInputLayer), pstV2DSurface->phyaddr_y_h); + v2d_write(V2D_LAYER_UV_ADDR_L_LAYER(enInputLayer), pstV2DSurface->phyaddr_uv_l); + } + layer_in_ori_w_h.field.layer_in_ori_width = pstV2DSurface->w; + layer_in_ori_w_h.field.layer_in_ori_height = pstV2DSurface->h; + v2d_write(V2D_LAYER_WIDTH_HEIGHT_LAYER(enInputLayer), layer_in_ori_w_h.overlay); + + layer_in_ctrl.field.stride = pstV2DSurface->stride; + layer_in_ctrl.field.swap = do_swap(pstV2DSurface->format); + layer_in_ctrl.field.format = fmt_convert(pstV2DSurface->format); + layer_in_ctrl.field.rotation = enRotateAngle; + layer_in_ctrl.field.fbc_en = pstV2DSurface->fbc_enable; + v2d_write(V2D_LAYER_CTRL_LAYER(enInputLayer), layer_in_ctrl.overlay); + /* crop */ + layer_in_crop0.field.layer_in_crop_ltop_x = pstV2DArea->x; + layer_in_crop0.field.layer_in_crop_ltop_y = pstV2DArea->y; + layer_in_crop1.field.layer_in_crop_width = pstV2DArea->w; + layer_in_crop1.field.layer_in_crop_height = pstV2DArea->h; + LOG_D("crop:(%d,%d,%d,%d)", pstV2DArea->x, pstV2DArea->y, pstV2DArea->w, pstV2DArea->h); + v2d_write(V2D_LAYER_CROP_REG0_LAYER(enInputLayer), layer_in_crop0.overlay); + v2d_write(V2D_LAYER_CROP_REG1_LAYER(enInputLayer), layer_in_crop1.overlay); + /* csc */ + if (enCSCMode < V2D_CSC_MODE_BUTT) + { + layer_in_csc_ctrl0.field.csc_en = V2D_FUNC_ENABLE; + pCscMatrix = &cscmatrix[enCSCMode][0][0]; + layer_in_csc_ctrl0.field.csc_matrix0 = pCscMatrix[0]; + for (int i = 0; i < 5; i++) + { + layer_in_csc_ctrl1.field.csc_matrix1 = pCscMatrix[2 * i + 1]; + layer_in_csc_ctrl1.field.csc_matrix2 = pCscMatrix[2 * i + 2]; + v2d_write(V2D_LAYER_CSC_CRTL1_LAYER(enInputLayer) + 0x4 * i, layer_in_csc_ctrl1.overlay); + } + layer_in_csc_ctrl2.field.csc_matrix11 = pCscMatrix[11]; + v2d_write(V2D_LAYER_CSC_CRTL6_LAYER(enInputLayer), layer_in_csc_ctrl2.overlay); + } + else + { + layer_in_csc_ctrl0.field.csc_en = V2D_FUNC_DISABLE; + } + v2d_write(V2D_LAYER_CSC_CRTL0_LAYER(enInputLayer), layer_in_csc_ctrl0.overlay); + /* scale */ + if (enRotateAngle == V2D_ROT_90 || enRotateAngle == V2D_ROT_270) + { + width = pstV2DArea->h; height = pstV2DArea->w; + } + else + { + width = pstV2DArea->w; height = pstV2DArea->h; + } + if (width == pBlendLayerConf->blend_area.w && height == pBlendLayerConf->blend_area.h) + { + enScaleMode = V2D_NO_SCALE; + } + else if (width > pBlendLayerConf->blend_area.w || height > pBlendLayerConf->blend_area.h) + { + enScaleMode = V2D_SCALE_DOWN; + } + else if (width < pBlendLayerConf->blend_area.w || height < pBlendLayerConf->blend_area.h) + { + enScaleMode = V2D_SCALE_UP; + } + LOG_D("scale: %d", enScaleMode); + layer_scale_mode.overlay = layer_in_csc_ctrl2.overlay; + layer_scale_mode.field.scl_mode = enScaleMode; + v2d_write(V2D_LAYER_SCALE_MODE_LAYER(enInputLayer), layer_scale_mode.overlay); + if (enScaleMode) + { + layer_scale_delta_x.field.scl_delta_x = (width << 16) / pBlendLayerConf->blend_area.w; + layer_scale_delta_y.overlay = bld_layer_ctrl0.overlay; + layer_scale_delta_y.field.scl_delta_y = (height << 16) / pBlendLayerConf->blend_area.h; + v2d_write(V2D_LAYER_SCALE_DELTA_X_LAYER(enInputLayer), layer_scale_delta_x.overlay); + v2d_write(V2D_LAYER_SCALE_DELTA_Y_LAYER(enInputLayer), layer_scale_delta_y.overlay); + } + else + { + layer_scale_delta_x.field.scl_delta_x = (1 << 16); + layer_scale_delta_y.overlay = bld_layer_ctrl0.overlay; + layer_scale_delta_y.field.scl_delta_y = (1 << 16); + v2d_write(V2D_LAYER_SCALE_DELTA_X_LAYER(enInputLayer), layer_scale_delta_x.overlay); + v2d_write(V2D_LAYER_SCALE_DELTA_Y_LAYER(enInputLayer), layer_scale_delta_y.overlay); + } + } + } +} + +static void ConfigV2dMaskLayer(V2D_SURFACE_S *pstMask, V2D_AREA_S *pstMaskRect, V2D_BLEND_CONF_S *pstBlendConf) +{ + v2d_mask_width_reg_t mask_in_width = { 0 }; + v2d_mask_height_reg_t mask_in_height = { 0 }; + v2d_mask_crop0_reg_t mask_in_crop0 = { 0 }; + v2d_mask_crop1_reg_t mask_in_crop1 = { 0 }; + v2d_blend_mask_ctrl0_reg_t bld_mask_ctrl0 = { 0 }; + v2d_blend_mask_ctrl1_reg_t bld_mask_ctrl1 = { 0 }; + v2d_blend_mask_ctrl2_reg_t bld_mask_ctrl2 = { 0 }; + + bld_mask_ctrl0.overlay = 0; + mask_in_width.overlay = 0; + bld_mask_ctrl2.overlay = 0; + + if (pstMask->phyaddr_y_l != 0 || pstMask->phyaddr_y_h != 0) + { + LOG_D("ConfigV2dMaskLayer"); + mask_in_width.field.mask_addr_33_32 = (pstMask->phyaddr_y_h & V2D_H_ADDR_MASK); + mask_in_width.field.mask_ori_width = pstMask->w; + mask_in_height.field.mask_ori_height = pstMask->h; + mask_in_height.field.mask_ori_stride = pstMask->stride; + mask_in_crop0.field.mask_crop_ltop_x = pstMaskRect->x; + mask_in_crop0.field.mask_crop_ltop_y = pstMaskRect->y; + mask_in_crop1.field.mask_crop_width = pstMaskRect->w; + mask_in_crop1.field.mask_crop_height = pstMaskRect->h; + bld_mask_ctrl0.field.bld_mask_enable = pstBlendConf->mask_cmd; + bld_mask_ctrl0.field.bld_mask_rect_ltop_x = pstBlendConf->blend_mask_area.x; + bld_mask_ctrl1.field.bld_mask_rect_ltop_y = pstBlendConf->blend_mask_area.y; + bld_mask_ctrl1.field.bld_mask_rect_width = pstBlendConf->blend_mask_area.w; + bld_mask_ctrl2.field.bld_mask_rect_height = pstBlendConf->blend_mask_area.h; + v2d_write(V2D_MASK_ADDR_L, pstMask->phyaddr_y_l); + v2d_write(V2D_MASK_WIDTH, mask_in_width.overlay); + v2d_write(V2D_MASK_HEIGHT, mask_in_height.overlay); + v2d_write(V2D_MASK_CROP_REG0, mask_in_crop0.overlay); + v2d_write(V2D_MASK_CROP_REG1, mask_in_crop1.overlay); + v2d_write(V2D_BLD_MASK_REG0, bld_mask_ctrl0.overlay); + v2d_write(V2D_BLD_MASK_REG1, bld_mask_ctrl1.overlay); + v2d_write(V2D_BLD_MASK_REG2, bld_mask_ctrl2.overlay); + } + else + { + LOG_D("mask layer disable"); + bld_mask_ctrl0.field.bld_mask_enable = V2D_FUNC_DISABLE; + v2d_write(V2D_BLD_MASK_REG0, bld_mask_ctrl0.overlay); + } +} + +static void ConfigPaletteTable(V2D_SURFACE_S *pstBackGround, V2D_SURFACE_S *pstForeGround, V2D_PALETTE_S *pstPalette) +{ + int bpp; + uint32_t val; + uint8_t *pTmp, r, g, b, a; + + if (pstPalette->len != 0) + { + LOG_D("ConfigPaletteTable"); + pTmp = pstPalette->palVal; + bpp = Get_L8_Palette_bytePerPixel(pstBackGround, pstForeGround); + LOG_D("bpp: %d, palette len: %d", bpp, pstPalette->len); + for (int i = 0; i < (pstPalette->len / bpp); i++) + { + if (bpp == 4) + { + r = *(pTmp + 4 * i); g = *(pTmp + 4 * i + 1); + b = *(pTmp + 4 * i + 2); a = *(pTmp + 4 * i + 3); + } + else if (bpp == 3) + { + r = *(pTmp + 3 * i); g = *(pTmp + 3 * i + 1); + b = *(pTmp + 3 * i + 2); a = 0xFF; + } + else if (bpp == 2) + { + r = *(pTmp + 2 * i) & 0x1F; + g = ((*(pTmp + 2 * i) >> 5) & 0x7) | ((*(pTmp + 2 * i + 1) & 0x7) << 3); + b = (*(pTmp + 2 * i + 1) >> 3) & 0x1F; + a = 0xFF; + } + val = r | (g << 8) | (b << 16) | (a << 24); + v2d_write(V2D_PALETTE_TABLE(i), val); + } + } +} + +static void ConfigV2dBlendMode_And_BgColor(V2D_BLEND_CONF_S *pstBlendConf) +{ + V2D_FILLCOLOR_S *pFillColor; + uint8_t chl[4]; + v2d_blend_ctrl0_reg_t blend_ctrl0 = { 0 }; + v2d_blend_ctrl1_reg_t blend_ctrl1 = { 0 }; + + LOG_D("ConfigV2dBlendMode_And_BgColor"); + blend_ctrl0.overlay = 0; + blend_ctrl1.overlay = 0; + blend_ctrl0.field.bld_mode = pstBlendConf->blend_cmd; + blend_ctrl0.field.bld_bg_enable = pstBlendConf->bgcolor.enable; + pFillColor = &pstBlendConf->bgcolor.fillcolor; + split_fillcolor(pFillColor->colorvalue, V2D_COLOR_FORMAT_RGBA8888, chl); + LOG_D("bgcolor_en: %d,r: %d,g: %d,b: %d,alpha: %d", pstBlendConf->bgcolor.enable, chl[R], chl[G], chl[B], chl[A]); + blend_ctrl0.field.bld_bg_r = chl[R]; + blend_ctrl0.field.bld_bg_g = chl[G]; + blend_ctrl0.field.bld_bg_b = chl[B]; + blend_ctrl1.field.bld_bg_a = chl[A]; + v2d_write(V2D_BLEND_REG0, blend_ctrl0.overlay); + v2d_write(V2D_BLEND_REG1, blend_ctrl1.overlay); +} + +static void ConfigV2dOutput(V2D_SURFACE_S *pstDst, + V2D_AREA_S *pstDstRect, + V2D_CSC_MODE_E enForeCSCMode, + V2D_CSC_MODE_E enBackCSCMode, + V2D_DITHER_E dither) +{ + v2d_output_width_reg_t output_width = { 0 }; + v2d_output_height_reg_t output_height = { 0 }; + v2d_output_ctrl0_reg_t output_ctrl0 = { 0 }; + v2d_output_ctrl1_reg_t output_ctrl1 = { 0 }; + v2d_output_ctrl2_reg_t output_ctrl2 = { 0 }; + + LOG_D("config output"); + output_width.overlay = 0; + output_ctrl0.overlay = 0; + output_ctrl2.overlay = 0; + output_width.field.out_ori_width = pstDst->w; + output_width.field.out_addr_uv_33_32 = (pstDst->phyaddr_uv_h & V2D_H_ADDR_MASK); + output_height.field.out_ori_height = pstDst->h; + output_height.field.out_ori_stride = pstDst->stride; + output_ctrl0.field.format = fmt_convert(pstDst->format); + output_ctrl0.field.range = do_narrow(enForeCSCMode, enBackCSCMode); + output_ctrl0.field.dither = dither; + output_ctrl0.field.swap = do_swap(pstDst->format); + output_ctrl0.field.fbc_en = pstDst->fbc_enable; + output_ctrl0.field.crop_ltop_x = pstDstRect->x; + output_ctrl1.field.crop_ltop_y = pstDstRect->y; + output_ctrl1.field.crop_width = pstDstRect->w; + output_ctrl2.field.crop_height = pstDstRect->h; + LOG_D("dst:w=%d,h=%d", pstDst->w, pstDst->h); + LOG_D("crop=(%d,%d,%d,%d)", pstDstRect->x, pstDstRect->y, pstDstRect->w, pstDstRect->h); + LOG_D("dst:fmt=%d, dither: %d,narrow=%d, swap=%d, stride=%d", + output_ctrl0.field.format, output_ctrl0.field.dither, output_ctrl0.field.range, output_ctrl0.field.swap, pstDst->stride); + + v2d_write(V2D_OUTPUT_WIDTH, output_width.overlay); + v2d_write(V2D_OUTPUT_HEIGHT, output_height.overlay); + v2d_write(V2D_OUTPUT_CRTL0, output_ctrl0.overlay); + v2d_write(V2D_OUTPUT_CRTL1, output_ctrl1.overlay); + v2d_write(V2D_OUTPUT_CRTL2, output_ctrl2.overlay); + if (pstDst->fbc_enable) + { + ConfigV2dFbcEncoder(pstDst); + } + else + { + v2d_write(V2D_OUTPUT_Y_ADDR_L, pstDst->phyaddr_y_l); + v2d_write(V2D_OUTPUT_Y_ADDR_H, pstDst->phyaddr_y_h); + v2d_write(V2D_OUTPUT_UV_ADDR_L, pstDst->phyaddr_uv_l); + } +} + +static void ConfigV2dDmac(void) +{ + v2d_dma_ctrl_reg_t dma_ctrl; + + dma_ctrl.overlay = 0; + dma_ctrl.field.dmac_arb_mode = 2; + dma_ctrl.field.dmac_max_req_num = 7; + dma_ctrl.field.dmac_postwr_en = 255; + dma_ctrl.field.dmac_rst_n_pwr = 1; + dma_ctrl.field.dmac_arqos = 2; + dma_ctrl.field.dmac_awqos = 2; + v2d_write(V2D_DMA_CTRL, dma_ctrl.overlay); +} + +static void TriggerV2dRun(V2D_PARAM_S *pParam) +{ + v2d_ctrl_reg_t ctrl = { 0 }; + v2d_fbc_decoder_trigger_reg_t decTrigger = { 0 }; + v2d_fbc_encoder_trigger_reg_t encTrigger = { 0 }; + + if (pParam->layer0.fbc_enable) + { + decTrigger.overlay = 0; + decTrigger.field.direct_swap = 1; + v2d_write(V2D_L0_DEC_REG10, decTrigger.overlay); + } + if (pParam->layer1.fbc_enable) + { + decTrigger.overlay = 0; + decTrigger.field.direct_swap = 1; + v2d_write(V2D_L1_DEC_REG10, decTrigger.overlay); + } + if (pParam->dst.fbc_enable) + { + encTrigger.overlay = 0; + encTrigger.field.direct_swap = 1; + v2d_write(V2D_ENC_REG12, encTrigger.overlay); + } + ctrl.overlay = 0; + ctrl.field.rdma_burst_len = 4; + ctrl.field.wdma_burst_len = 16; + ctrl.field.trigger = 1; + rt_hw_dsb(); + v2d_write(V2D_CTRL_REG, ctrl.overlay); +} + +void config_v2d_hw(V2D_SUBMIT_TASK_S *pTask) +{ + V2D_SURFACE_S *pstBackGround, *pstForeGround, *pstMask, *pstDst; + V2D_AREA_S *pstBackGroundRect, *pstForeGroundRect, *pstMaskRect, *pstDstRect; + V2D_BLEND_CONF_S *pstBlendConf; + V2D_ROTATE_ANGLE_E enForeRoate, enBackRotate; + V2D_CSC_MODE_E enForeCscMode, enBackCscMode; + V2D_PALETTE_S *pstPalette; + V2D_DITHER_E enDither; + V2D_PARAM_S *pV2dParam; + + pV2dParam = &pTask->param; + pstBackGround = &pV2dParam->layer0; + pstBackGroundRect = &pV2dParam->l0_rect; + pstForeGround = &pV2dParam->layer1; + pstForeGroundRect = &pV2dParam->l1_rect; + pstMask = &pV2dParam->mask; + pstMaskRect = &pV2dParam->mask_rect; + pstDst = &pV2dParam->dst; + pstDstRect = &pV2dParam->dst_rect; + pstBlendConf = &pV2dParam->blendconf; + enBackRotate = pV2dParam->l0_rt; + enForeRoate = pV2dParam->l1_rt; + enBackCscMode = pV2dParam->l0_csc; + enForeCscMode = pV2dParam->l1_csc; + enDither = pV2dParam->dither; + pstPalette = &pV2dParam->palette; + + /* init scaler coef */ + v2d_scaler_coef_init(); + /* config layer0 */ + ConfigV2dInputLayer(pstBackGround, pstBackGroundRect, pstBlendConf, enBackRotate, enBackCscMode, V2D_INPUT_LAYER0); + /* config layer1 */ + ConfigV2dInputLayer(pstForeGround, pstForeGroundRect, pstBlendConf, enForeRoate, enForeCscMode, V2D_INPUT_LAYER1); + /* set palette */ + ConfigPaletteTable(pstBackGround, pstForeGround, pstPalette); + /* config mask */ + ConfigV2dMaskLayer(pstMask, pstMaskRect, pstBlendConf); + /* blend */ + ConfigV2dBlendMode_And_BgColor(pstBlendConf); + /* output */ + ConfigV2dOutput(pstDst, pstDstRect, enForeCscMode, enBackCscMode, enDither); + /* DMA control */ + ConfigV2dDmac(); + /* set v2d qos */ + ConfigAxiBus(); + /* trigger */ + TriggerV2dRun(pV2dParam); + LOG_D("v2d config done"); +} diff --git a/bsp/spacemit/dm/soc/v2d/v2d_internal.h b/bsp/spacemit/dm/soc/v2d/v2d_internal.h new file mode 100644 index 000000000000..e3f1916bbc72 --- /dev/null +++ b/bsp/spacemit/dm/soc/v2d/v2d_internal.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#ifndef __SPACEMIT_V2D_INTERNAL_H__ +#define __SPACEMIT_V2D_INTERNAL_H__ + +#include +#include +#include + +#include + +#define DBG_TAG "soc.spacemit.v2d" +#define DBG_LVL DBG_INFO +#include + +void v2d_hw_set_base(void *base); +int v2d_global_reset(void); +uint32_t v2d_irq_status(void); +uint32_t v2d_irqerr_status(void); +void v2d_dump_irqraw_status(void); +void v2d_irq_clear(uint32_t irq_status); +void v2d_irqerr_clear(uint32_t irq_error); +void v2d_irq_enable(void); +void v2d_irq_disable(void); +void config_v2d_hw(V2D_SUBMIT_TASK_S *task); + +#endif /* __SPACEMIT_V2D_INTERNAL_H__ */ diff --git a/bsp/spacemit/dm/soc/v2d/v2d_reg.h b/bsp/spacemit/dm/soc/v2d/v2d_reg.h new file mode 100644 index 000000000000..c36bca0cf026 --- /dev/null +++ b/bsp/spacemit/dm/soc/v2d/v2d_reg.h @@ -0,0 +1,922 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#ifndef __SPACEMIT_V2D_REG_H__ +#define __SPACEMIT_V2D_REG_H__ + +#define V2D_REG_BASE 0xC0100000 +#define PMUA_REG_BASE 0xd4282800 +#define V2D_TOP_BASE 0x000 +#define V2D_CORE_BASE 0x100 +#define V2D_ENC_BASE 0x800 +#define V2D_L0_DEC_BASE 0x900 +#define V2D_L1_DEC_BASE 0xa00 + +/* v2d clk offset */ +#define V2D_CLK_RES_CTRL0 0x44 +#define V2D_CLK_RES_CTRL1 0x4c + +/* v2d top offset */ +#define V2D_AUTO_CLK_REG (0x00 + V2D_TOP_BASE) +#define V2D_ERR_IRQ_MASK (0x04 + V2D_TOP_BASE) +#define V2D_IRQ_MASK (0x08 + V2D_TOP_BASE) +#define V2D_ERR_IRQ_STATUS (0x0C + V2D_TOP_BASE) +#define V2D_IRQ_STATUS (0x10 + V2D_TOP_BASE) +#define V2D_ERR_IRQ_RAW (0x14 + V2D_TOP_BASE) +#define V2D_IRQ_RAW (0x18 + V2D_TOP_BASE) +#define V2D_AXI_BUS_CTRL (0x1C + V2D_TOP_BASE) + +#define V2D_GLOBAL_RESET RT_BIT(8) +#define V2D_AUTO_CLK_EN RT_BIT(9) +#define V2D_ENC_AUTO_CLK_EN RT_BIT(10) +#define V2D_TOP_AUTO_CLK_EN RT_BIT(11) +#define V2D_EOF_IRQ_STATUS RT_BIT(0) +#define V2D_FBCENC_IRQ_STATUS RT_BIT(1) +#define V2D_EOF_IRQ_MASK RT_BIT(0) +#define V2D_FBCENC_IRQ_MASK RT_BIT(1) + +#define V2D_H_ADDR_MASK 0x3 +/* v2d core offset */ +#define V2D_CTRL_REG (0x00 + V2D_CORE_BASE) +#define V2D_SCALER_COEF_REG0 (0x04 + V2D_CORE_BASE) +#define V2D_SCALER_COEF_RGG1 (0x08 + V2D_CORE_BASE) +#define V2D_SCALER_COEF_REG2 (0x0C + V2D_CORE_BASE) +#define V2D_SCALER_COEF_RGG3 (0x10 + V2D_CORE_BASE) +#define V2D_SCALER_COEF_REG4 (0x14 + V2D_CORE_BASE) +#define V2D_SCALER_COEF_RGG5 (0x18 + V2D_CORE_BASE) +#define V2D_SCALER_COEF_REG6 (0x1C + V2D_CORE_BASE) +#define V2D_SCALER_COEF_RGG7 (0x20 + V2D_CORE_BASE) +#define V2D_SCALER_COEF_REG8 (0x24 + V2D_CORE_BASE) +#define V2D_SCALER_COEF_RGG9 (0x28 + V2D_CORE_BASE) +#define V2D_SCALER_COEF_REG10 (0x2C + V2D_CORE_BASE) +#define V2D_SCALER_COEF_RGG11 (0x30 + V2D_CORE_BASE) +#define V2D_SCALER_COEF_REG12 (0x34 + V2D_CORE_BASE) +#define V2D_SCALER_COEF_RGG13 (0x38 + V2D_CORE_BASE) +#define V2D_SCALER_COEF_REG14 (0x3C + V2D_CORE_BASE) +#define V2D_SCALER_COEF_RGG15 (0x40 + V2D_CORE_BASE) +#define V2D_SCALER_COEF_REG16 (0x44 + V2D_CORE_BASE) +#define V2D_SCALER_COEF_RGG17 (0x48 + V2D_CORE_BASE) +#define V2D_SCALER_COEF_REG18 (0x4C + V2D_CORE_BASE) +#define V2D_SCALER_COEF_RGG19 (0x50 + V2D_CORE_BASE) +#define V2D_SCALER_COEF_REG20 (0x54 + V2D_CORE_BASE) +#define V2D_SCALER_COEF_RGG21 (0x58 + V2D_CORE_BASE) +#define V2D_SCALER_COEF_REG22 (0x5C + V2D_CORE_BASE) +#define V2D_SCALER_COEF_RGG23 (0x60 + V2D_CORE_BASE) +#define V2D_SCALER_COEF_REG(i) (0x04 * (i + 1) + V2D_CORE_BASE) +#define SCALER_COEF_REG_NUM 24 + +#define V2D_BLEND_REG0 (0x64 + V2D_CORE_BASE) +#define V2D_BLEND_REG1 (0x68 + V2D_CORE_BASE) +#define V2D_BLD_MASK_REG0 (0x6C + V2D_CORE_BASE) +#define V2D_BLD_MASK_REG1 (0x70 + V2D_CORE_BASE) +#define V2D_BLD_MASK_REG2 (0x74 + V2D_CORE_BASE) + +#define V2D_OUTPUT_Y_ADDR_L (0x78 + V2D_CORE_BASE) +#define V2D_OUTPUT_Y_ADDR_H (0x7C + V2D_CORE_BASE) +#define V2D_OUTPUT_UV_ADDR_L (0x80 + V2D_CORE_BASE) +#define V2D_OUTPUT_UV_ADDR_H (0x84 + V2D_CORE_BASE) +#define V2D_OUTPUT_WIDTH (0x84 + V2D_CORE_BASE) +#define V2D_OUTPUT_HEIGHT (0x88 + V2D_CORE_BASE) +#define V2D_OUTPUT_CRTL0 (0x8C + V2D_CORE_BASE) +#define V2D_OUTPUT_CRTL1 (0x90 + V2D_CORE_BASE) +#define V2D_OUTPUT_CRTL2 (0x94 + V2D_CORE_BASE) + +#define V2D_MASK_ADDR_L (0x98 + V2D_CORE_BASE) +#define V2D_MASK_ADDR_H (0x9C + V2D_CORE_BASE) +#define V2D_MASK_WIDTH (0x9C + V2D_CORE_BASE) +#define V2D_MASK_HEIGHT (0xA0 + V2D_CORE_BASE) +#define V2D_MASK_CROP_REG0 (0xA4 + V2D_CORE_BASE) +#define V2D_MASK_CROP_REG1 (0xA8 + V2D_CORE_BASE) + +#define V2D_LAYER0_Y_ADDR_L (0xAC + V2D_CORE_BASE) +#define V2D_LAYER0_Y_ADDR_H (0xB0 + V2D_CORE_BASE) +#define V2D_LAYER0_UV_ADDR_L (0xB4 + V2D_CORE_BASE) +#define V2D_LAYER0_UV_ADDR_H (0xB8 + V2D_CORE_BASE) +#define V2D_LAYER0_BLD_FACTOR (0xB8 + V2D_CORE_BASE) +#define V2D_LAYER0_WIDTH_HEIGHT (0xBC + V2D_CORE_BASE) +#define V2D_LAYER0_CTRL (0xC0 + V2D_CORE_BASE) +#define V2D_LAYER0_CROP_REG0 (0xC4 + V2D_CORE_BASE) +#define V2D_LAYER0_CROP_REG1 (0xC8 + V2D_CORE_BASE) +#define V2D_LAYER0_SOLIDCOLOR_CTRL0 (0xCC + V2D_CORE_BASE) +#define V2D_LAYER0_SOLIDCOLOR_CTRL1 (0xD0 + V2D_CORE_BASE) +#define V2D_LAYER0_CSC_CRTL0 (0xD0 + V2D_CORE_BASE) +#define V2D_LAYER0_CSC_CRTL1 (0xD4 + V2D_CORE_BASE) +#define V2D_LAYER0_CSC_CRTL2 (0xD8 + V2D_CORE_BASE) +#define V2D_LAYER0_CSC_CRTL3 (0xDC + V2D_CORE_BASE) +#define V2D_LAYER0_CSC_CRTL4 (0xE0 + V2D_CORE_BASE) +#define V2D_LAYER0_CSC_CRTL5 (0xE4 + V2D_CORE_BASE) +#define V2D_LAYER0_CSC_CRTL6 (0xE8 + V2D_CORE_BASE) +#define V2D_LAYER0_SCALE_MODE (0xE8 + V2D_CORE_BASE) +#define V2D_LAYER0_SCALE_DELTA_X (0xEC + V2D_CORE_BASE) +#define V2D_LAYER0_SCALE_DELTA_Y (0xF0 + V2D_CORE_BASE) +#define V2D_LAYER0_BLD_CTRL0 (0xF0 + V2D_CORE_BASE) +#define V2D_LAYER0_BLD_CTRL1 (0xF4 + V2D_CORE_BASE) +#define V2D_LAYER0_BLD_CTRL2 (0xF8 + V2D_CORE_BASE) +#define V2D_LAYER0_BLD_CTRL3 (0xFC + V2D_CORE_BASE) + +#define V2D_LAYER1_Y_ADDR_L (0x100 + V2D_CORE_BASE) +#define V2D_LAYER1_Y_ADDR_H (0x104 + V2D_CORE_BASE) +#define V2D_LAYER1_UV_ADDR_L (0x108 + V2D_CORE_BASE) +#define V2D_LAYER1_UV_ADDR_H (0x10C + V2D_CORE_BASE) +#define V2D_LAYER1_BLD_FACTOR (0x10C + V2D_CORE_BASE) +#define V2D_LAYER1_WIDTH_HEIGHT (0x110 + V2D_CORE_BASE) +#define V2D_LAYER1_CTRL (0x114 + V2D_CORE_BASE) +#define V2D_LAYER1_CROP_REG0 (0x118 + V2D_CORE_BASE) +#define V2D_LAYER1_CROP_REG1 (0x11C + V2D_CORE_BASE) +#define V2D_LAYER1_SOLIDCOLOR_CTRL0 (0x120 + V2D_CORE_BASE) +#define V2D_LAYER1_SOLIDCOLOR_CTRL1 (0x124 + V2D_CORE_BASE) +#define V2D_LAYER1_CSC_CRTL0 (0x124 + V2D_CORE_BASE) +#define V2D_LAYER1_CSC_CRTL1 (0x128 + V2D_CORE_BASE) +#define V2D_LAYER1_CSC_CRTL2 (0x12C + V2D_CORE_BASE) +#define V2D_LAYER1_CSC_CRTL3 (0x130 + V2D_CORE_BASE) +#define V2D_LAYER1_CSC_CRTL4 (0x134 + V2D_CORE_BASE) +#define V2D_LAYER1_CSC_CRTL5 (0x138 + V2D_CORE_BASE) +#define V2D_LAYER1_CSC_CRTL6 (0x13C + V2D_CORE_BASE) +#define V2D_LAYER1_SCALE_MODE (0x13C + V2D_CORE_BASE) +#define V2D_LAYER1_SCALE_DELTA_X (0x140 + V2D_CORE_BASE) +#define V2D_LAYER1_SCALE_DELTA_Y (0x144 + V2D_CORE_BASE) +#define V2D_LAYER1_BLD_CTRL0 (0x144 + V2D_CORE_BASE) +#define V2D_LAYER1_BLD_CTRL1 (0x148 + V2D_CORE_BASE) +#define V2D_LAYER1_BLD_CTRL2 (0x14C + V2D_CORE_BASE) +#define V2D_LAYER1_BLD_CTRL3 (0x150 + V2D_CORE_BASE) + +#define V2D_LAYER_Y_ADDR_L_LAYER(i) (0xAC + i * 0x54 + V2D_CORE_BASE) +#define V2D_LAYER_Y_ADDR_H_LAYER(i) (0xB0 + i * 0x54 + V2D_CORE_BASE) +#define V2D_LAYER_UV_ADDR_L_LAYER(i) (0xB4 + i * 0x54 + V2D_CORE_BASE) +#define V2D_LAYER_UV_ADDR_H_LAYER(i) (0xB8 + i * 0x54 + V2D_CORE_BASE) +#define V2D_LAYER_BLD_FACTOR_LAYER(i) (0xB8 + i * 0x54 + V2D_CORE_BASE) +#define V2D_LAYER_WIDTH_HEIGHT_LAYER(i) (0xBC + i * 0x54 + V2D_CORE_BASE) +#define V2D_LAYER_CTRL_LAYER(i) (0xC0 + i * 0x54 + V2D_CORE_BASE) +#define V2D_LAYER_CROP_REG0_LAYER(i) (0xC4 + i * 0x54 + V2D_CORE_BASE) +#define V2D_LAYER_CROP_REG1_LAYER(i) (0xC8 + i * 0x54 + V2D_CORE_BASE) +#define V2D_LAYER_SOLIDCOLOR_CTRL0_LAYER(i) (0xCC + i * 0x54 + V2D_CORE_BASE) +#define V2D_LAYER_SOLIDCOLOR_CTRL1_LAYER(i) (0xD0 + i * 0x54 + V2D_CORE_BASE) +#define V2D_LAYER_CSC_CRTL0_LAYER(i) (0xD0 + i * 0x54 + V2D_CORE_BASE) +#define V2D_LAYER_CSC_CRTL1_LAYER(i) (0xD4 + i * 0x54 + V2D_CORE_BASE) +#define V2D_LAYER_CSC_CRTL2_LAYER(i) (0xD8 + i * 0x54 + V2D_CORE_BASE) +#define V2D_LAYER_CSC_CRTL3_LAYER(i) (0xDC + i * 0x54 + V2D_CORE_BASE) +#define V2D_LAYER_CSC_CRTL4_LAYER(i) (0xE0 + i * 0x54 + V2D_CORE_BASE) +#define V2D_LAYER_CSC_CRTL5_LAYER(i) (0xE4 + i * 0x54 + V2D_CORE_BASE) +#define V2D_LAYER_CSC_CRTL6_LAYER(i) (0xE8 + i * 0x54 + V2D_CORE_BASE) +#define V2D_LAYER_SCALE_MODE_LAYER(i) (0xE8 + i * 0x54 + V2D_CORE_BASE) +#define V2D_LAYER_SCALE_DELTA_X_LAYER(i) (0xEC + i * 0x54 + V2D_CORE_BASE) +#define V2D_LAYER_SCALE_DELTA_Y_LAYER(i) (0xF0 + i * 0x54 + V2D_CORE_BASE) +#define V2D_LAYER_BLD_CTRL0_LAYER(i) (0xF0 + i * 0x54 + V2D_CORE_BASE) +#define V2D_LAYER_BLD_CTRL1_LAYER(i) (0xF4 + i * 0x54 + V2D_CORE_BASE) +#define V2D_LAYER_BLD_CTRL2_LAYER(i) (0xF8 + i * 0x54 + V2D_CORE_BASE) +#define V2D_LAYER_BLD_CTRL3_LAYER(i) (0xFC + i * 0x54 + V2D_CORE_BASE) + +#define V2D_DEBUG_REG0 (0x1FC + V2D_CORE_BASE) +#define V2D_DEBUG_REG1 (0x200 + V2D_CORE_BASE) +#define V2D_DMA_CTRL (0x204 + V2D_CORE_BASE) +#define V2D_PALETTE_TABLE(i) (0x208 + i * 0x4 + V2D_CORE_BASE) + +#define V2D_L0_DEC_REG0 (V2D_L0_DEC_BASE + 0x000) /* register hdr_base_addr_low */ +#define V2D_L0_DEC_REG1 (V2D_L0_DEC_BASE + 0x004) /* register hdr_base_addr_high */ +#define V2D_L0_DEC_REG2 (V2D_L0_DEC_BASE + 0x008) /* register bbox_coor_x */ +#define V2D_L0_DEC_REG3 (V2D_L0_DEC_BASE + 0x00c) /* register bbox_coor_y */ +#define V2D_L0_DEC_REG4 (V2D_L0_DEC_BASE + 0x010) /* register image_size */ +#define V2D_L0_DEC_REG5 (V2D_L0_DEC_BASE + 0x014) /* register dec_mode */ +#define V2D_L0_DEC_REG6 (V2D_L0_DEC_BASE + 0x018) /* register dmac_ctrl */ +#define V2D_L0_DEC_REG7 (V2D_L0_DEC_BASE + 0x01c) /* register irq_mask */ +#define V2D_L0_DEC_REG8 (V2D_L0_DEC_BASE + 0x020) /* register irq_raw */ +#define V2D_L0_DEC_REG9 (V2D_L0_DEC_BASE + 0x024) /* register irq_status */ +#define V2D_L0_DEC_REG10 (V2D_L0_DEC_BASE + 0x028) /* register trig_ctrl */ +#define V2D_L0_DEC_REG11 (V2D_L0_DEC_BASE + 0x02c) /* register output_ybase */ +#define V2D_L0_DEC_REG12 (V2D_L0_DEC_BASE + 0x030) /* register output_cbase */ +#define V2D_L0_DEC_REG13 (V2D_L0_DEC_BASE + 0x034) /* register output_stride */ + +#define V2D_L1_DEC_REG0 (V2D_L1_DEC_BASE + 0x000) +#define V2D_L1_DEC_REG1 (V2D_L1_DEC_BASE + 0x004) +#define V2D_L1_DEC_REG2 (V2D_L1_DEC_BASE + 0x008) +#define V2D_L1_DEC_REG3 (V2D_L1_DEC_BASE + 0x00c) +#define V2D_L1_DEC_REG4 (V2D_L1_DEC_BASE + 0x010) +#define V2D_L1_DEC_REG5 (V2D_L1_DEC_BASE + 0x014) +#define V2D_L1_DEC_REG6 (V2D_L1_DEC_BASE + 0x018) +#define V2D_L1_DEC_REG7 (V2D_L1_DEC_BASE + 0x01c) +#define V2D_L1_DEC_REG8 (V2D_L1_DEC_BASE + 0x020) +#define V2D_L1_DEC_REG9 (V2D_L1_DEC_BASE + 0x024) +#define V2D_L1_DEC_REG10 (V2D_L1_DEC_BASE + 0x028) +#define V2D_L1_DEC_REG11 (V2D_L1_DEC_BASE + 0x02c) +#define V2D_L1_DEC_REG12 (V2D_L1_DEC_BASE + 0x030) +#define V2D_L1_DEC_REG13 (V2D_L1_DEC_BASE + 0x034) + +#define V2D_LAYER_DEC_REG0_L(i) (V2D_L0_DEC_BASE + i * 0x100 + 0x000) +#define V2D_LAYER_DEC_REG1_L(i) (V2D_L0_DEC_BASE + i * 0x100 + 0x004) +#define V2D_LAYER_DEC_REG2_L(i) (V2D_L0_DEC_BASE + i * 0x100 + 0x008) +#define V2D_LAYER_DEC_REG3_L(i) (V2D_L0_DEC_BASE + i * 0x100 + 0x00c) +#define V2D_LAYER_DEC_REG4_L(i) (V2D_L0_DEC_BASE + i * 0x100 + 0x010) +#define V2D_LAYER_DEC_REG5_L(i) (V2D_L0_DEC_BASE + i * 0x100 + 0x014) +#define V2D_LAYER_DEC_REG6_L(i) (V2D_L0_DEC_BASE + i * 0x100 + 0x018) +#define V2D_LAYER_DEC_REG7_L(i) (V2D_L0_DEC_BASE + i * 0x100 + 0x01c) +#define V2D_LAYER_DEC_REG8_L(i) (V2D_L0_DEC_BASE + i * 0x100 + 0x020) +#define V2D_LAYER_DEC_REG9_L(i) (V2D_L0_DEC_BASE + i * 0x100 + 0x024) +#define V2D_LAYER_DEC_REG10_L(i) (V2D_L0_DEC_BASE + i * 0x100 + 0x028) +#define V2D_LAYER_DEC_REG11_L(i) (V2D_L0_DEC_BASE + i * 0x100 + 0x02c) +#define V2D_LAYER_DEC_REG12_L(i) (V2D_L0_DEC_BASE + i * 0x100 + 0x030) +#define V2D_LAYER_DEC_REG13_L(i) (V2D_L0_DEC_BASE + i * 0x100 + 0x034) + +#define V2D_ENC_REG0 (V2D_ENC_BASE + 0x000) /* REGISTER HEADER_BASE_ADDR_LOW */ +#define V2D_ENC_REG1 (V2D_ENC_BASE + 0x004) /* REGISTER HEADER_BASE_ADDR_HIGH */ +#define V2D_ENC_REG2 (V2D_ENC_BASE + 0x008) /* REGISTER PAYLOAD_BASE_ADDR_LOW */ +#define V2D_ENC_REG3 (V2D_ENC_BASE + 0x00c) /* REGISTER PAYLOAD_BASE_ADDR_HIGH */ +#define V2D_ENC_REG4 (V2D_ENC_BASE + 0x010) /* REGISTER Bbox_coor_x */ +#define V2D_ENC_REG5 (V2D_ENC_BASE + 0x014) /* REGISTER Bbox_coor_y */ +#define V2D_ENC_REG6 (V2D_ENC_BASE + 0x018) /* REGISTER Y_BUF_BASE_ADDR */ +#define V2D_ENC_REG7 (V2D_ENC_BASE + 0x01c) /* REGISTER Y_BUF_PITCH */ +#define V2D_ENC_REG8 (V2D_ENC_BASE + 0x020) /* REGISTER UV_BUF_BASE_ADDR */ +#define V2D_ENC_REG9 (V2D_ENC_BASE + 0x024) /* REGISTER UV_BUF_PITCH */ +#define V2D_ENC_REG10 (V2D_ENC_BASE + 0x028) /* REGISTER Y_BUF_SIZE */ +#define V2D_ENC_REG11 (V2D_ENC_BASE + 0x02c) /* REGISTER UV_BUF_SIZE */ +#define V2D_ENC_REG12 (V2D_ENC_BASE + 0x030) /* REGISTER REG_SHADOW_CTRL */ +#define V2D_ENC_REG13 (V2D_ENC_BASE + 0x034) /* REGISTER IRQ_MASK */ +#define V2D_ENC_REG14 (V2D_ENC_BASE + 0x038) /* REGISTER IRQ_CLEAR */ +#define V2D_ENC_REG15 (V2D_ENC_BASE + 0x03c) /* REGISTER DMAC_CTRL_0 */ +#define V2D_ENC_REG16 (V2D_ENC_BASE + 0x040) /* REGISTER ENC_MODE */ +#define V2D_ENC_REG17 (V2D_ENC_BASE + 0x044) /* REGISTER DMAC_LENGTH */ +#define V2D_ENC_REG18 (V2D_ENC_BASE + 0x048) /* REGISTER IRQ_STATUS */ +/* v2d iommu */ +#define TBU_NUM 32 +#define V2D_MMU_TTBLR_BASE 0x40 +#define V2D_MMU_TTBHR_BASE 0x44 +#define V2D_MMU_TCR0_BASE 0x48 +#define V2D_MMU_TCR1_BASE 0x4c +#define V2D_MMU_TBU_STATUS_BASE 0x50 +#define V2D_MMU_TBUx_STEP 0x20 +#define V2D_MMU_BVA_LO 0x00 +#define V2D_MMU_BVA_HI 0x04 +#define V2D_MMU_TIMEOUT_VA_ADDR_LO 0x08 +#define V2D_MMU_TIMEOUT_VA_ADDR_HI 0x0C +#define V2D_MMU_IRQ_STATUS 0x10 +#define V2D_MMU_IRQ_ENABLE 0x14 +#define V2D_MMU_TIMEOUT_VALUE 0x18 +#define V2D_MMU_ERROR_CLEAR 0x1C +#define V2D_MMU_LAST_VA_ADDR_LO 0x20 +#define V2D_MMU_LAST_VA_ADDR_HI 0x24 +#define V2D_MMU_LAST_PA_ADDR_LO 0x28 +#define V2D_MMU_LAST_PA_ADDR_HI 0x2C +#define V2D_MMU_VERSION 0x3C +#define V2D_IOMMU_BASE_OFFSET 0xB00 + +/** + *@brief V2D Control register + */ +typedef union +{ + struct + { + unsigned int trigger : 1; /**< trigger v2d to work */ + unsigned int rdma_burst_len : 3; /**< set rdma burst lenght */ + unsigned int reserved1 : 4; /**< Reserved */ + unsigned int wdma_burst_len : 5; /**< set wdma burst length */ + unsigned int reserved2 : 19; /**< Reserved */ + } field; /**< Fields view */ + unsigned int overlay; /**< Overlay view */ +} v2d_ctrl_reg_t; + +/** + *@brief V2D DMA Control register + */ +typedef union +{ + struct + { + unsigned int dmac_arb_mode : 2; + unsigned int dmac_arqos : 4; + unsigned int reserved : 2; /**< Reserved */ + unsigned int dmac_awqos : 4; + unsigned int dmac_axi_sec : 1; + unsigned int dmac_max_req_num : 3; + unsigned int dmac_postwr_en : 8; + unsigned int dmac_rst_n_pwr : 1; + unsigned int dmac_rst_req : 1; + unsigned int dmac_user_id : 4; + unsigned int damc_rd_int_clr : 1; + unsigned int damc_wr_int_clr : 1; + } field; /**< Fields view */ + unsigned int overlay; /**< Overlay view */ +} v2d_dma_ctrl_reg_t; + +/** + *@brief V2D Scaler Coefficient register + */ +typedef union +{ + struct + { + int scaler_coef0 : 12; /**< scaler coefficient0 */ + unsigned int reserved1 : 4; /**< Reserved */ + int scaler_coef1 : 12; /**< scaler coefficient1 */ + unsigned int reserved2 : 4; /**< Reserved */ + } field; /**< Fields view */ + unsigned int overlay; /**< Overlay view */ +} v2d_scaler_coef_reg_t; + +/** + *@brief V2D Blend Control0 register + */ +typedef union +{ + struct + { + unsigned int bld_mode : 1; /**< blend mode alpha blending or ROP operation */ + unsigned int bld_bg_enable : 1; /**< background color enable */ + unsigned int reserved : 6; /**< Rerserved */ + unsigned int bld_bg_r : 8; /**< background color R value */ + unsigned int bld_bg_g : 8; /**< background color G value */ + unsigned int bld_bg_b : 8; /**< background color B value */ + } field; /**< Fields view */ + unsigned int overlay; /**< Overlay view */ +} v2d_blend_ctrl0_reg_t; + +/** + *@brief V2D Blend Control1 register + */ +typedef union +{ + struct + { + unsigned int bld_bg_a : 8; /**< background color alpha value */ + unsigned int reserved : 24; /**< Rerserved */ + } field; /**< Fields view */ + unsigned int overlay; /**< Overlay view */ +} v2d_blend_ctrl1_reg_t; + +/** + *@brief V2D Blend Mask Control0 register + */ +typedef union +{ + struct + { + unsigned int bld_mask_enable : 2; /**< blend mask enable */ + unsigned int reserved1 : 6; /**< Rerserved */ + unsigned int bld_mask_rect_ltop_x : 16; /**< blend mask rectangle left-top point x-axis coordinate */ + unsigned int reserved2 : 8; /**< Rerserved */ + } field; /**< Fields view */ + unsigned int overlay; /**< Overlay view */ +} v2d_blend_mask_ctrl0_reg_t; + +/** + *@brief V2D Blend Mask Control1 register + */ +typedef union +{ + struct + { + unsigned int bld_mask_rect_ltop_y : 16; /**< blend mask rectangle left-top point y-axis coordinate */ + unsigned int bld_mask_rect_width : 16; /**< blend mask rectangle width */ + } field; /**< Fields view */ + unsigned int overlay; /**< Overlay view */ +} v2d_blend_mask_ctrl1_reg_t; + +/** + *@brief V2D Blend Mask Control2 register + */ +typedef union +{ + struct + { + unsigned int bld_mask_rect_height : 16; /**< blend mask rectangle height */ + unsigned int reserved : 16; /**< Rerserved */ + } field; /**< Fields view */ + unsigned int overlay; /**< Overlay view */ +} v2d_blend_mask_ctrl2_reg_t; + +/** + *@brief V2D Output Width register + */ +typedef union +{ + struct + { + unsigned int out_addr_uv_33_32 : 2; /**< output uv address_h_bit */ + unsigned int reserved1 : 6; /**< Rerserved */ + unsigned int out_ori_width : 16; /**< output width */ + unsigned int reserved2 : 8; /**< Rerserved */ + } field; /**< Fields view */ + unsigned int overlay; /**< Overlay view */ +} v2d_output_width_reg_t; + +/** + *@brief V2D Output Height register + */ +typedef union +{ + struct + { + unsigned int out_ori_height : 16; /**< output height */ + unsigned int out_ori_stride : 16; /**< output stride */ + } field; /**< Fields view */ + unsigned int overlay; /**< Overlay view */ +} v2d_output_height_reg_t; + +/** + *@brief V2D Output Control0 register + */ +typedef union +{ + struct + { + unsigned int format : 4; /**< output format */ + unsigned int range : 1; /**< output range yuv narrow/wide */ + unsigned int dither : 2; /**< output dither mode */ + unsigned int swap : 1; /**< output swap */ + unsigned int fbc_en : 1; /**< output fbc enable */ + unsigned int reserved : 7; /**< Rerserved */ + unsigned int crop_ltop_x : 16; /**< output crop left-top point x-axis coordinate */ + } field; /**< Fields view */ + unsigned int overlay; /**< Overlay view */ +} v2d_output_ctrl0_reg_t; + +/** + *@brief V2D Output Control1 register + */ +typedef union +{ + struct + { + unsigned int crop_ltop_y : 16; /**< output crop left-top point y-axis coordinate */ + unsigned int crop_width : 16; /**< output crop width */ + } field; /**< Fields view */ + unsigned int overlay; /**< Overlay view */ +} v2d_output_ctrl1_reg_t; + +/** + *@brief V2D Output Control2 register + */ +typedef union +{ + struct + { + unsigned int crop_height : 16; /**< output crop height */ + unsigned int reserved : 16; /**< Rerserved */ + } field; /**< Fields view */ + unsigned int overlay; /**< Overlay view */ +} v2d_output_ctrl2_reg_t; + +/** + *@brief V2D mask input Width register + */ +typedef union +{ + struct + { + unsigned int mask_addr_33_32 : 2; /**< mask address_h_bit */ + unsigned int reserved1 : 6; /**< Rerserved */ + unsigned int mask_ori_width : 16; /**< mask in width */ + unsigned int reserved2 : 8; /**< Rerserved */ + } field; /**< Fields view */ + unsigned int overlay; /**< Overlay view */ +} v2d_mask_width_reg_t; + +/** + *@brief V2D mask input Height register + */ +typedef union +{ + struct + { + unsigned int mask_ori_height : 16; /**< mask in height */ + unsigned int mask_ori_stride : 16; /**< mask in stride */ + } field; /**< Fields view */ + unsigned int overlay; /**< Overlay view */ +} v2d_mask_height_reg_t; + +/** + *@brief V2D mask input crop0 register + */ +typedef union +{ + struct + { + unsigned int mask_crop_ltop_x : 16; /**< mask crop left-top point x-axis coordinate */ + unsigned int mask_crop_ltop_y : 16; /**< mask crop left-top point y-axis coordinate */ + } field; /**< Fields view */ + unsigned int overlay; /**< Overlay view */ +} v2d_mask_crop0_reg_t; + +/** + *@brief V2D mask input crop1 register + */ +typedef union +{ + struct + { + unsigned int mask_crop_width : 16; /**< mask crop in width */ + unsigned int mask_crop_height : 16; /**< mask crop in height */ + } field; /**< Fields view */ + unsigned int overlay; /**< Overlay view */ +} v2d_mask_crop1_reg_t; + +/** + *@brief V2D Blend Layer Factor register + */ +typedef union +{ + struct + { + unsigned int in_addr_uv_33_32 : 2; /**< input layer uv address_h_bit */ + unsigned int bld_src_color_factor : 3; /**< blend source color factor */ + unsigned int bld_dst_color_factor : 3; /**< blend dst color factor */ + unsigned int bld_src_alpha_factor : 3; /**< blend source alpha factor */ + unsigned int bld_dst_alpha_factor : 3; /**< blend dst alpha factor */ + unsigned int reserved1 : 2; /**< Reserved */ + unsigned int bld_color_rop2_code : 4; /**< ROP color code */ + unsigned int bld_alpha_rop2_code : 4; /**< ROP alpha code */ + unsigned int reserved2 : 8; /**< Reserved */ + } field; /**< Fields view */ + unsigned int overlay; /**< Overlay view */ +} v2d_blend_layer_factor_reg_t; + +/** + *@brief V2D Input Layer width/height register + */ +typedef union +{ + struct + { + unsigned int layer_in_ori_width : 16; /**< input layer width */ + unsigned int layer_in_ori_height : 16; /**< input layer height */ + } field; /**< Fields view */ + unsigned int overlay; /**< Overlay view */ +} v2d_input_layer_width_height_reg_t; + +/** + *@brief V2D Input Layer Control register + */ +typedef union +{ + struct + { + unsigned int stride : 16; /**< input layer stride */ + unsigned int format : 4; /**< input layer format */ + unsigned int rotation : 3; /**< input layer rotation */ + unsigned int swap : 1; /**< input layer swap */ + unsigned int fbc_en : 1; /**< input layer fbc enbale */ + unsigned int reserved : 7; /**< Reserved */ + } field; /**< Fields view */ + unsigned int overlay; /**< Overlay view */ +} v2d_input_layer_ctrl_reg_t; + +/** + *@brief V2D input layer crop0 register + */ +typedef union +{ + struct + { + unsigned int layer_in_crop_ltop_x : 16; /**< input layer crop left-top point x-axis coordinate */ + unsigned int layer_in_crop_ltop_y : 16; /**< input layer crop left-top point y-axis coordinate */ + } field; /**< Fields view */ + unsigned int overlay; /**< Overlay view */ +} v2d_input_layer_crop0_reg_t; + +/** + *@brief V2D input layer crop1 register + */ +typedef union +{ + struct + { + unsigned int layer_in_crop_width : 16; /**< input layer crop in width */ + unsigned int layer_in_crop_height : 16; /**< input layer crop in height */ + } field; /**< Fields view */ + unsigned int overlay; /**< Overlay view */ +} v2d_input_layer_crop1_reg_t; + +/** + *@brief V2D input solid color control0 register + */ +typedef union +{ + struct + { + unsigned int solid_en : 1; /**< input layer solid color enable */ + unsigned int reserved : 7; /**< Rrserved */ + unsigned int solid_R : 8; /**< solid color R channel value */ + unsigned int solid_G : 8; /**< solid color G channel value */ + unsigned int solid_B : 8; /**< solid color B channel value */ + } field; /**< Fields view */ + unsigned int overlay; /**< Overlay view */ +} v2d_solid_color_ctrl0_reg_t; + +/** + *@brief V2D input solid color control1 register + */ +typedef union +{ + struct + { + unsigned int solid_A : 8; /**< solid color alpha channel value */ + unsigned int csc_en : 1; /**< input layer csc enable */ + unsigned int reserved1 : 7; /**< Rrserved */ + int csc_matrix0 : 13; /**< input layer csc matrix0 */ + unsigned int reserved2 : 3; /**< Rrserved */ + } field; /**< Fields view */ + unsigned int overlay; /**< Overlay view */ +} v2d_solid_color_ctrl1_reg_t; +typedef v2d_solid_color_ctrl1_reg_t v2d_input_layer_csc_ctrl0_reg_t; + +/** + *@brief V2D input layer csc control1~5 register + */ +typedef union +{ + struct + { + int csc_matrix1 : 13; /**< input layer csc matrix 2*i-1 */ + unsigned int reserved1 : 3; /**< Rrserved */ + int csc_matrix2 : 13; /**< input layer csc matrix 2*i */ + unsigned int reserved2 : 3; /**< Rrserved */ + } field; /**< Fields view */ + unsigned int overlay; /**< Overlay view */ +} v2d_input_layer_csc_ctrl1_reg_t; + +/** + *@brief V2D input layer csc control6 register + */ +typedef union +{ + struct + { + int csc_matrix11 : 13; /**< input layer csc matrix11 */ + unsigned int scl_mode : 2; /**< scaler mode 0:bypass, 1:scale down, 2:scale up */ + unsigned int reserved1 : 17; /**< Rrserved */ + } field; /**< Fields view */ + unsigned int overlay; /**< Overlay view */ +} v2d_input_layer_csc_ctrl2_reg_t; +typedef v2d_input_layer_csc_ctrl2_reg_t v2d_input_layer_scale_mode_reg_t; + +/** + *@brief V2D input layer scale delta x register + */ +typedef union +{ + struct + { + unsigned int scl_delta_x : 20; /**< input layer scale delta x, (in_width<<16) /bld_rectWidth */ + unsigned int reserved : 12; /**< Rrserved */ + } field; /**< Fields view */ + unsigned int overlay; /**< Overlay view */ +} v2d_input_layer_scale_delta_x_reg_t; + +/** + *@brief V2D input layer scale delta y register + */ +typedef union +{ + struct + { + unsigned int scl_delta_y : 20; /**< input layer scale delta y, (in_height<<16) /bld_rectHeight */ + unsigned int bld_alpha_source : 2; /**< blend alpha source, 0:pixel, 1:golbal, 2: mask value */ + unsigned int bld_pre_alp_func : 2; /**< blend premultiplied function, 0:disable, 1:global alpha* src_alpha, 2:mask*src_a */ + unsigned int bld_glb_alp : 8; /**< global alpha value */ + } field; /**< Fields view */ + unsigned int overlay; /**< Overlay view */ +} v2d_input_layer_scale_delta_y_reg_t; +typedef v2d_input_layer_scale_delta_y_reg_t v2d_blend_layer_ctrl0_reg_t; + +/** + * @brief V2D Blend Layer Control1 register + */ +typedef union +{ + struct + { + unsigned int blend_en : 1; /**< blend layer enable */ + unsigned int reserved1 : 7; /**< Reserved */ + unsigned int bld_rect_ltop_x : 16; /**< blend layer rectangle left-top point x-axis coordinate */ + unsigned int reserved2 : 8; /**< Reserved */ + } field; /**< Fields view */ + unsigned int overlay; /**< Overlay view */ +} v2d_blend_layer_ctrl1_reg_t; + +/** + * @brief V2D Blend Layer Control2 register + */ +typedef union +{ + struct + { + unsigned int bld_rect_ltop_y : 16; /**< blend layer rectangle left-top point y-axis coordinate */ + unsigned int bld_rect_width : 16; /**< blend layer rectangle width */ + } field; /**< Fields view */ + unsigned int overlay; /**< Overlay view */ +} v2d_blend_layer_ctrl2_reg_t; + +/** + * @brief V2D Blend Layer Control3 register + */ +typedef union +{ + struct + { + unsigned int bld_rect_height : 16; /**< blend layer rectangle height */ + unsigned int reserved : 16; /**< Reserved */ + } field; /**< Fields view */ + unsigned int overlay; /**< Overlay view */ +} v2d_blend_layer_ctrl3_reg_t; + +/** + * @brief V2D FBC decoder bbox register + */ +typedef union +{ + struct + { + unsigned int bbox_start : 13; /**< v2d fbc decoder bbox start */ + unsigned int reserved1 : 3; /**< Reserved */ + unsigned int bbox_end : 13; /**< v2d fbc decoder bbox end */ + unsigned int reserved2 : 3; /**< Reserved */ + } field; /**< Fields view */ + unsigned int overlay; /**< Overlay view */ +} v2d_fbc_decoder_bbox_reg_t; + +/** + * @brief V2D FBC decoder image size register + */ +typedef union +{ + struct + { + unsigned int width : 16; /**< v2d fbc decoder image width */ + unsigned int height : 16; /**< v2d fbc decoder image height */ + } field; /**< Fields view */ + unsigned int overlay; /**< Overlay view */ +} v2d_fbc_decoder_imgae_size_reg_t; + +/** + * @brief V2D FBC decoder mode register + */ +typedef union +{ + struct + { + unsigned int mode : 3; /**< v2d fbc decoder mode */ + unsigned int format : 3; /**< v2d fbc decoder pixel format */ + unsigned int is_split : 1; /**< v2d fbc decoder split mode */ + unsigned int rgb_pack_en : 1; /**< v2d fbc decoder rgb pack enable */ + unsigned int reserved : 24; /**< Reserved */ + } field; /**< Fields view */ + unsigned int overlay; /**< Overlay view */ +} v2d_fbc_decoder_mode_reg_t; + +/** + * @brief V2D FBC decoder dma control register + */ +typedef union +{ + struct + { + unsigned int dmac_arqos : 4; /**< v2d fbc decoder dma qos */ + unsigned int damc_axi_sec : 1; /**< v2d fbc decoder dma axi sec */ + unsigned int dmac_user_id : 4; /**< v2d fbc decoder dma user id */ + unsigned int dmac_rstn_pwr : 1; /**< v2d fbc decoder dma rstn pwr */ + unsigned int dmac_rst_req : 1; /**< v2d fbc decoder dma rst req*/ + unsigned int dmac_max_req_num : 3; /**< v2d fbc decoder dma max req num */ + unsigned int dmac_arb_mode : 2; /**< v2d fbc decoder dma arb mode */ + unsigned int rdma_timeout_num : 16; /**< v2d fbc decoder dma timeout num */ + } field; /**< Fields view */ + unsigned int overlay; /**< Overlay view */ +} v2d_fbc_decoder_dma_ctrl_reg_t; + +/** + * @brief V2D FBC decoder irq mask/raw/status register + */ +typedef union +{ + struct + { + unsigned int decode_eof : 1; /**< v2d fbc decoder eof irq mask */ + unsigned int cfg_swaped : 1; /**< v2d fbc decoder cfg sswap irq mask */ + unsigned int dmac_err : 1; /**< v2d fbc decoder dmac err irq mask */ + unsigned int rdma_timeout : 1; /**< v2d fbc decoder rdma timeout mask */ + unsigned int dec_err : 1; /**< v2d fbc decoder decode err irq mask */ + unsigned int reserved : 27; /**< Reserved */ + } field; /**< Fields view */ + unsigned int overlay; /**< Overlay view */ +} v2d_fbc_decoder_irq_ctrl_reg_t; + +/** + * @brief V2D FBC decoder trigger register + */ +typedef union +{ + struct + { + unsigned int direct_swap : 1; /**< v2d fbc decoder direct swap */ + unsigned int pending_swap : 1; /**< v2d fbc decoder pending swap */ + unsigned int reserved : 30; /**< Reserved */ + } field; /**< Fields view */ + unsigned int overlay; /**< Overlay view */ +} v2d_fbc_decoder_trigger_reg_t; + +/** + * @brief V2D FBC encoder bbox register + */ +typedef union +{ + struct + { + unsigned int bbox_start : 16; /**< v2d fbc encoder bbox start */ + unsigned int bbox_end : 16; /**< v2d fbc encoder bbox end */ + } field; /**< Fields view */ + unsigned int overlay; /**< Overlay view */ +} v2d_fbc_encoder_bbox_reg_t; + +/** + * @brief V2D FBC encoder y or uv buf szie register + */ +typedef union +{ + struct + { + unsigned int x_size : 16; /**< v2d fbc encoder buf x size */ + unsigned int y_size : 16; /**< v2d fbc encoder buf y size */ + } field; /**< Fields view */ + unsigned int overlay; /**< Overlay view */ +} v2d_fbc_encoder_buf_size_reg_t; + +/** + * @brief V2D FBC encoder trigger register + */ +typedef union +{ + struct + { + unsigned int direct_swap : 1; /**< v2d fbc encoder direct swap */ + unsigned int pending_swap : 1; /**< v2d fbc encoder pending swap */ + unsigned int reserved : 30; /**< Reserved */ + } field; /**< Fields view */ + unsigned int overlay; /**< Overlay view */ +} v2d_fbc_encoder_trigger_reg_t; + +/** + * @brief V2D FBC encoder irq mask,raw,status register + */ +typedef union +{ + struct + { + unsigned int dma_wr_err : 16; /**< v2d fbc encoder dma wr err */ + unsigned int dma_wr_eof : 1; /**< v2d fbc encoder dma wr eof */ + unsigned int cfg_update_done : 1; /**< v2d fbc encoder cfg update done */ + unsigned int reserved : 14; /**< Reserved */ + } field; /**< Fields view */ + unsigned int overlay; /**< Overlay view */ +} v2d_fbc_encoder_irq_reg_t; + +/** + * @brief V2D FBC encoder mode register + */ +typedef union +{ + struct + { + unsigned int encode_enable : 1; /**< v2d fbc encoder enable */ + unsigned int split_mode_en : 1; /**< v2d fbc encoder split mode */ + unsigned int img_pix_format : 2; /**< v2d fbc encoder pixel format */ + unsigned int reserved : 28; /**< Reserved */ + } field; /**< Fields view */ + unsigned int overlay; /**< Overlay view */ +} v2d_fbc_encoder_mode_reg_t; + +/** + * @brief V2D FBC encoder dmac length register + */ +typedef union +{ + struct + { + unsigned int burst_length : 7; /**< v2d fbc encoder dmac burst length */ + unsigned int reserved : 25; /**< Reserved */ + } field; /**< Fields view */ + unsigned int overlay; /**< Overlay view */ +} v2d_fbc_encoder_dmac_burst_reg_t; + +/** +*@brief V2D Top AXI bus control register +*/ +typedef union +{ + struct + { + unsigned int arqos_m : 4; /**< v2d axi bus read qos */ + unsigned int aruser_m : 4; /**< v2d axi bus read user */ + unsigned int awqos_m : 4; /** + +#include +#include +#include +#include + +#define QSPI_WAIT_TIMEOUT 300 /* ms */ +#define QSPI_AUTOSUSPEND_TIMEOUT 2000 +#define K1X_MPMU_ACGR 0xd4051024 + +/* QSPI PMUap register */ +#define PMUA_QSPI_CLK_RES_CTRL 0xd4282860 +#define QSPI_CLK_SEL(x) ((x) << 6) +#define QSPI_CLK_SEL_MASK RT_GENMASK(8, 6) +#define QSPI_CLK_EN RT_BIT(4) +#define QSPI_BUS_CLK_EN RT_BIT(3) +#define QSPI_CLK_RST RT_BIT(1) +#define QSPI_BUS_RST RT_BIT(0) + +/* QSPI memory base */ +#define QSPI_AMBA_BASE(qspi) ((qspi)->memmap_base) +#define QSPI_FLASH_A1_BASE(qspi) QSPI_AMBA_BASE(qspi) +#define QSPI_FLASH_A1_TOP(qspi) (QSPI_FLASH_A1_BASE(qspi) + 0x4000000) +#define QSPI_FLASH_A2_BASE(qspi) QSPI_FLASH_A1_TOP(qspi) +#define QSPI_FLASH_A2_TOP(qspi) (QSPI_FLASH_A2_BASE(qspi) + 0x100000) +#define QSPI_FLASH_B1_BASE(qspi) QSPI_FLASH_A2_TOP(qspi) +#define QSPI_FLASH_B1_TOP(qspi) (QSPI_FLASH_B1_BASE(qspi) + 0x100000) +#define QSPI_FLASH_B2_BASE(qspi) QSPI_FLASH_B1_TOP(qspi) +#define QSPI_FLASH_B2_TOP(qspi) (QSPI_FLASH_B2_BASE(qspi) + 0x100000) + +/* TX/RX/ABH buffer max */ +#define QSPI_RX_BUFF_MAX 128 +#define QSPI_TX_BUFF_MAX 256 +#define QSPI_TX_BUFF_POP_MIN 16 +#define QSPI_AHB_BUFF_MAX_SIZE 512 +#define QSPI_TX_DMA_BURST 16 + +#define QSPI_WAIT_BIT_CLEAR 0 +#define QSPI_WAIT_BIT_SET 1 + +/* QSPI Host Registers used by the driver */ +#define QSPI_MCR 0x00 +#define QSPI_MCR_ISD_MASK RT_GENMASK(19, 16) +#define QSPI_MCR_MDIS_MASK RT_BIT(14) +#define QSPI_MCR_CLR_TXF_MASK RT_BIT(11) +#define QSPI_MCR_CLR_RXF_MASK RT_BIT(10) +#define QSPI_MCR_DDR_EN_MASK RT_BIT(7) +#define QSPI_MCR_END_CFG_MASK RT_GENMASK(3, 2) +#define QSPI_MCR_SWRSTHD_MASK RT_BIT(1) +#define QSPI_MCR_SWRSTSD_MASK RT_BIT(0) + +#define QSPI_TCR 0x04 +#define QSPI_IPCR 0x08 +#define QSPI_IPCR_SEQID(x) ((x) << 24) + +#define QSPI_FLSHCR 0x0c + +#define QSPI_BUF0CR 0x10 +#define QSPI_BUF1CR 0x14 +#define QSPI_BUF2CR 0x18 +#define QSPI_BUF3CR 0x1c +#define QSPI_BUF3CR_ALLMST_MASK RT_BIT(31) +#define QSPI_BUF3CR_ADATSZ(x) ((x) << 8) +#define QSPI_BUF3CR_ADATSZ_MASK RT_GENMASK(15, 8) + +#define QSPI_BFGENCR 0x20 +#define QSPI_BFGENCR_SEQID(x) ((x) << 12) + +#define QSPI_SOCCR 0x24 + +#define QSPI_BUF0IND 0x30 +#define QSPI_BUF1IND 0x34 +#define QSPI_BUF2IND 0x38 + +#define QSPI_SFAR 0x100 +#define QSPI_SFACR 0x104 + +#define QSPI_SMPR 0x108 +#define QSPI_SMPR_DDRSMP_MASK RT_GENMASK(18, 16) +#define QSPI_SMPR_FSDLY_MASK RT_BIT(6) +#define QSPI_SMPR_FSPHS_MASK RT_BIT(5) +#define QSPI_SMPR_FSPHS_CLK (416000000) +#define QSPI_SMPR_HSENA_MASK RT_BIT(0) + +#define QSPI_RBSR 0x10c + +#define QSPI_RBCT 0x110 +#define QSPI_RBCT_WMRK_MASK RT_GENMASK(4, 0) +#define QSPI_RBCT_RXBRD_MASK RT_BIT(8) + +#define QSPI_TBSR 0x150 +#define QSPI_TBDR 0x154 +#define QSPI_TBCT 0x158 +#define QSPI_TX_WMRK (QSPI_TX_DMA_BURST / 4 - 1) + +#define QSPI_SR 0x15c +#define QSPI_SR_BUSY RT_BIT(0) +#define QSPI_SR_IP_ACC_MASK RT_BIT(1) +#define QSPI_SR_AHB_ACC_MASK RT_BIT(2) +#define QSPI_SR_TXFULL RT_BIT(27) + +#define QSPI_FR 0x160 +#define QSPI_FR_TFF_MASK RT_BIT(0) +#define QSPI_FR_IPGEF RT_BIT(4) +#define QSPI_FR_IPIEF RT_BIT(6) +#define QSPI_FR_IPAEF RT_BIT(7) +#define QSPI_FR_IUEF RT_BIT(11) +#define QSPI_FR_ABOF RT_BIT(12) +#define QSPI_FR_AIBSEF RT_BIT(13) +#define QSPI_FR_AITEF RT_BIT(14) +#define QSPI_FR_ABSEF RT_BIT(15) +#define QSPI_FR_RBDF RT_BIT(16) +#define QSPI_FR_RBOF RT_BIT(17) +#define QSPI_FR_ILLINE RT_BIT(23) +#define QSPI_FR_TBUF RT_BIT(26) +#define QSPI_FR_TBFF RT_BIT(27) +#define BUFFER_FR_FLAG (QSPI_FR_ABOF| QSPI_FR_RBOF| QSPI_FR_TBUF) + +#define COMMAND_FR_FLAG (QSPI_FR_ABSEF | QSPI_FR_AITEF | QSPI_FR_AIBSEF | QSPI_FR_IUEF | \ + QSPI_FR_IPAEF |QSPI_FR_IPIEF | QSPI_FR_IPGEF) + +#define QSPI_RSER 0x164 +#define QSPI_RSER_TFIE RT_BIT(0) +#define QSPI_RSER_IPGEIE RT_BIT(4) +#define QSPI_RSER_IPIEIE RT_BIT(6) +#define QSPI_RSER_IPAEIE RT_BIT(7) +#define QSPI_RSER_IUEIE RT_BIT(11) +#define QSPI_RSER_ABOIE RT_BIT(12) +#define QSPI_RSER_AIBSIE RT_BIT(13) +#define QSPI_RSER_AITIE RT_BIT(14) +#define QSPI_RSER_ABSEIE RT_BIT(15) +#define QSPI_RSER_RBDIE RT_BIT(16) +#define QSPI_RSER_RBOIE RT_BIT(17) +#define QSPI_RSER_RBDDE RT_BIT(21) +#define QSPI_RSER_ILLINIE RT_BIT(23) +#define QSPI_RSER_TBFDE RT_BIT(25) +#define QSPI_RSER_TBUIE RT_BIT(26) +#define QSPI_RSER_TBFIE RT_BIT(27) +#define BUFFER_ERROR_INT (QSPI_RSER_ABOIE| QSPI_RSER_RBOIE | QSPI_RSER_TBUIE) + +#define COMMAND_ERROR_INT (QSPI_RSER_ABSEIE | QSPI_RSER_AITIE | QSPI_RSER_AIBSIE | QSPI_RSER_IUEIE | \ + QSPI_RSER_IPAEIE |QSPI_RSER_IPIEIE | QSPI_RSER_IPGEIE) + +#define QSPI_SPNDST 0x168 +#define QSPI_SPTRCLR 0x16c +#define QSPI_SPTRCLR_IPPTRC RT_BIT(8) +#define QSPI_SPTRCLR_BFPTRC RT_BIT(0) + +#define QSPI_SFA1AD 0x180 +#define QSPI_SFA2AD 0x184 +#define QSPI_SFB1AD 0x188 +#define QSPI_SFB2AD 0x18c +#define QSPI_DLPR 0x190 +#define QSPI_RBDR(x) (0x200 + ((x) * 4)) + +#define QSPI_LUTKEY 0x300 +#define QSPI_LUTKEY_VALUE 0x5af05af0 + +#define QSPI_LCKCR 0x304 +#define QSPI_LCKER_LOCK RT_BIT(0) +#define QSPI_LCKER_UNLOCK RT_BIT(1) + +#define QSPI_LUT_BASE 0x310 +/* 16Bytes per sequence */ +#define QSPI_LUT_REG(seqid, i) (QSPI_LUT_BASE + (seqid) * 16 + (i) * 4) + +/* + * QSPI Sequence index. + * index 0 is preset at boot for AHB read, + * index 1 is used for other command. + */ +#define SEQID_LUT_AHBREAD_ID 0 +#define SEQID_LUT_SHARED_ID 1 + +/* QSPI Instruction set for the LUT register */ +#define LUT_INSTR_STOP 0 +#define LUT_INSTR_CMD 1 +#define LUT_INSTR_ADDR 2 +#define LUT_INSTR_DUMMY 3 +#define LUT_INSTR_MODE 4 +#define LUT_INSTR_MODE2 5 +#define LUT_INSTR_MODE4 6 +#define LUT_INSTR_READ 7 +#define LUT_INSTR_WRITE 8 +#define LUT_INSTR_JMP_ON_CS 9 +#define LUT_INSTR_ADDR_DDR 10 +#define LUT_INSTR_MODE_DDR 11 +#define LUT_INSTR_MODE2_DDR 12 +#define LUT_INSTR_MODE4_DDR 13 +#define LUT_INSTR_READ_DDR 14 +#define LUT_INSTR_WRITE_DDR 15 +#define LUT_INSTR_DATA_LEARN 16 + +/* + * The PAD definitions for LUT register. + * + * The pad stands for the number of IO lines [0:3]. + * For example, the quad read needs four IO lines, + * so you should use LUT_PAD(4). + */ +#define LUT_PAD(x) (fls(x) - 1) + +/* + * One sequence must be consisted of 4 LUT enteries(16Bytes). + * LUT entries with the following register layout: + * b'31 b'0 + * --------------------------------------------------------------------------- + * |INSTR1[15~10]|PAD1[9~8]|OPRND1[7~0] | INSTR0[15~10]|PAD0[9~8]|OPRND0[7~0]| + * --------------------------------------------------------------------------- + */ +#define LUT_DEF(idx, ins, pad, opr) ((((ins) << 10) | ((pad) << 8) | (opr)) << (((idx) & 0x1) * 16)) + +#define READ_FROM_CACHE_OP 0x03 +#define READ_FROM_CACHE_OP_Fast 0x0b +#define READ_FROM_CACHE_OP_X2 0x3b +#define READ_FROM_CACHE_OP_X4 0x6b +#define READ_FROM_CACHE_OP_DUALIO 0xbb +#define READ_FROM_CACHE_OP_QUADIO 0xeb + +enum qpsi_cs +{ + QSPI_CS_A1 = 0, + QSPI_CS_A2, + QSPI_CS_B1, + QSPI_CS_B2, + QSPI_CS_MAX, + QSPI_DEFAULT_CS = QSPI_CS_A1, +}; + +enum qpsi_mode +{ + QSPI_NORMAL_MODE = 0, + QSPI_DISABLE_MODE, + QSPI_STOP_MODE, +}; + +struct k1x_qspi +{ + struct rt_spi_bus parent; + + struct rt_clk *clk; + struct rt_clk *bus_clk; + struct rt_reset_control *rstc; + + int irq; + void *io_map; + rt_ubase_t io_phys; + + void *ahb_map; + rt_ubase_t memmap_base; + rt_ubase_t memmap_size; + + rt_uint32_t sfa1ad; + rt_uint32_t sfa2ad; + rt_uint32_t sfb1ad; + rt_uint32_t sfb2ad; + + void *pmuap_addr; + void *mpmu_acgr; + rt_uint32_t pmuap_reg; + rt_uint32_t mpmu_acgr_reg; + + rt_uint32_t rx_buf_size; + rt_uint32_t tx_buf_size; + rt_uint32_t ahb_buf_size; + rt_uint32_t ahb_read_enable; + rt_uint32_t tx_unit_size; + rt_uint32_t rx_unit_size; + + rt_uint32_t cmd_interrupt; + rt_uint32_t fr_error_flag; + + rt_uint32_t cs_selected; + rt_uint32_t max_hz; + rt_uint32_t endian_xchg; + rt_uint32_t dma_enable; + + rt_uint32_t tx_wmrk; + rt_uint32_t tx_dma_enable; + rt_uint32_t rx_dma_enable; + + struct rt_dma_slave_config rx_config; + struct rt_dma_slave_config tx_config; + struct rt_dma_slave_transfer rx_transfer; + struct rt_dma_slave_transfer tx_transfer; + + struct rt_dma_chan *dma_rx; + struct rt_dma_chan *dma_tx; + + struct rt_completion cmd_completion; + struct rt_completion dma_completion; +}; + +#define raw_to_k1x_qspi(raw) rt_container_of(raw, struct k1x_qspi, parent) + +static void qspi_writel(struct k1x_qspi *qspi, rt_uint32_t val, void *addr) +{ + if (qspi->endian_xchg) + { + HWREG32(addr) = rt_cpu_to_be32(val); + } + else + { + HWREG32(addr) = val; + } +} + +static rt_uint32_t qspi_readl(struct k1x_qspi *qspi, void *addr) +{ + if (qspi->endian_xchg) + { + return rt_be32_to_cpu(HWREG32(addr)); + } + else + { + return HWREG32(addr); + } +} + +static rt_err_t k1x_qspi_readl_poll_tout(struct k1x_qspi *qspi, void *base, + rt_uint32_t mask, rt_uint32_t timeout_us, rt_uint8_t wait_set) +{ + rt_uint32_t reg; + + if (qspi->endian_xchg) + { + mask = __builtin_bswap32(mask); + } + + if (wait_set) + { + return readl_poll_timeout(base, reg, (reg & mask), 10, timeout_us); + } + else + { + return readl_poll_timeout(base, reg, !(reg & mask), 10, timeout_us); + } +} + +static void qspi_reset(struct k1x_qspi *qspi) +{ + rt_uint32_t reg; + + /* QSPI_SR[QSPI_SR_BUSY] must be 0 */ + if (k1x_qspi_readl_poll_tout(qspi, qspi->io_map + QSPI_SR, + QSPI_SR_BUSY, QSPI_WAIT_TIMEOUT*1000, QSPI_WAIT_BIT_CLEAR)) + { + return; + } + + /* qspi softreset first */ + reg = qspi_readl(qspi, qspi->io_map + QSPI_MCR); + reg |= QSPI_MCR_SWRSTHD_MASK | QSPI_MCR_SWRSTSD_MASK; + qspi_writel(qspi, reg, qspi->io_map + QSPI_MCR); + reg = qspi_readl(qspi, qspi->io_map + QSPI_MCR); + + if ((reg & 0x3) != 0x3) + { + LOG_I("Reset ignored %#x", reg); + } + + rt_hw_us_delay(1); + reg &= ~(QSPI_MCR_SWRSTHD_MASK | QSPI_MCR_SWRSTSD_MASK); + qspi_writel(qspi, reg, qspi->io_map + QSPI_MCR); +} + +static void qspi_enter_mode(struct k1x_qspi *qspi, rt_uint32_t mode) +{ + rt_uint32_t mcr; + + mcr = qspi_readl(qspi, qspi->io_map + QSPI_MCR); + if (mode == QSPI_NORMAL_MODE) + { + mcr &= ~QSPI_MCR_MDIS_MASK; + } + else if (mode == QSPI_DISABLE_MODE) + { + mcr |= QSPI_MCR_MDIS_MASK; + } + qspi_writel(qspi, mcr, qspi->io_map + QSPI_MCR); +} + +static void qspi_write_sfar(struct k1x_qspi *qspi, rt_uint32_t val) +{ + /* QSPI_SR[IP_ACC] must be 0 */ + if (k1x_qspi_readl_poll_tout(qspi, qspi->io_map + QSPI_SR, + QSPI_SR_IP_ACC_MASK, QSPI_WAIT_TIMEOUT*1000, QSPI_WAIT_BIT_CLEAR)) + { + return; + } + qspi_writel(qspi, val, qspi->io_map + QSPI_SFAR); +} + +/* + * IP Command Trigger could not be executed Error Flag may happen for write + * access to RBCT/SFAR register, need retry for these two register + */ +static void qspi_write_rbct(struct k1x_qspi *qspi, rt_uint32_t val) +{ + /* QSPI_SR[IP_ACC] must be 0 */ + if (k1x_qspi_readl_poll_tout(qspi, qspi->io_map + QSPI_SR, + QSPI_SR_IP_ACC_MASK, QSPI_WAIT_TIMEOUT*1000, QSPI_WAIT_BIT_CLEAR)) + { + return; + } + + qspi_writel(qspi, val, qspi->io_map + QSPI_RBCT); +} + +/* + * If the slave device content being changed by Write/Erase, need to + * invalidate the AHB buffer. This can be achieved by doing the reset + * of controller after setting MCR0[SWRESET] bit. + */ +rt_inline void k1x_qspi_invalid(struct k1x_qspi *qspi) +{ + rt_uint32_t reg; + + reg = qspi_readl(qspi, qspi->io_map + QSPI_MCR); + reg |= QSPI_MCR_SWRSTHD_MASK | QSPI_MCR_SWRSTSD_MASK; + qspi_writel(qspi, reg, qspi->io_map + QSPI_MCR); + + /* + * The minimum delay : 1 AHB + 2 SFCK clocks. + * Delay 1 us is enough. + */ + rt_hw_us_delay(1); + + reg &= ~(QSPI_MCR_SWRSTHD_MASK | QSPI_MCR_SWRSTSD_MASK); + qspi_writel(qspi, reg, qspi->io_map + QSPI_MCR); +} + +static void k1x_qspi_prepare_lut(struct k1x_qspi *qspi, + struct rt_qspi_message *qxfer, rt_uint32_t seq_id) +{ + int lutidx = 0; + rt_uint32_t lutval[4] = {}; + + /* qspi cmd */ + lutval[0] |= LUT_DEF(lutidx, LUT_INSTR_CMD, + LUT_PAD(qxfer->instruction.qspi_lines), qxfer->instruction.content); + lutidx++; + + /* addr bytes */ + if (qxfer->address.size) + { + lutval[lutidx / 2] |= LUT_DEF(lutidx, LUT_INSTR_ADDR, + LUT_PAD(qxfer->address.qspi_lines), qxfer->address.size * 8); + lutidx++; + } + + /* dummy bytes, if needed */ + if (qxfer->alternate_bytes.size) + { + lutval[lutidx / 2] |= LUT_DEF(lutidx, LUT_INSTR_DUMMY, + LUT_PAD(qxfer->alternate_bytes.qspi_lines), + qxfer->alternate_bytes.size * 8 / qxfer->alternate_bytes.qspi_lines); + lutidx++; + } + + /* read/write data bytes */ + if (qxfer->parent.length) + { + lutval[lutidx / 2] |= LUT_DEF(lutidx, + qxfer->parent.recv_buf ? LUT_INSTR_READ : LUT_INSTR_WRITE, + LUT_PAD(qxfer->qspi_data_lines), 0); + lutidx++; + } + + /* stop condition. */ + lutval[lutidx / 2] |= LUT_DEF(lutidx, LUT_INSTR_STOP, 0, 0); + + /* unlock LUT */ + qspi_writel(qspi, QSPI_LUTKEY_VALUE, qspi->io_map + QSPI_LUTKEY); + qspi_writel(qspi, QSPI_LCKER_UNLOCK, qspi->io_map + QSPI_LCKCR); + + /* fill LUT register */ + for (int i = 0; i < RT_ARRAY_SIZE(lutval); ++i) + { + qspi_writel(qspi, lutval[i], qspi->io_map + QSPI_LUT_REG(seq_id, i)); + } + + /* lock LUT */ + qspi_writel(qspi, QSPI_LUTKEY_VALUE, qspi->io_map + QSPI_LUTKEY); + qspi_writel(qspi, QSPI_LCKER_LOCK, qspi->io_map + QSPI_LCKCR); +} + +static void k1x_qspi_enable_interrupt(struct k1x_qspi *qspi, rt_uint32_t val) +{ + rt_uint32_t resr = 0; + + resr = qspi_readl(qspi, qspi->io_map + QSPI_RSER); + resr |= val; + qspi_writel(qspi, resr, qspi->io_map + QSPI_RSER); +} + +static void k1x_qspi_disable_interrupt(struct k1x_qspi *qspi, rt_uint32_t val) +{ + rt_uint32_t resr = 0; + + resr = qspi_readl(qspi, qspi->io_map + QSPI_RSER); + resr &= ~val; + qspi_writel(qspi, resr, qspi->io_map + QSPI_RSER); +} + +static void k1x_qspi_dma_callback(struct rt_dma_chan *chan, rt_size_t size) +{ + struct k1x_qspi *qspi = chan->priv; + + rt_completion_done(&qspi->dma_completion); +} + +static rt_err_t k1x_qspi_tx_dma_exec(struct k1x_qspi *qspi, struct rt_qspi_message *qxfer) +{ + rt_err_t err; + + qspi->tx_config.src_addr = (rt_ubase_t)rt_kmem_v2p((void *)qxfer->parent.send_buf); + + if ((err = rt_dma_chan_config(qspi->dma_tx, &qspi->tx_config))) + { + return err; + } + + qspi->tx_transfer.buffer_len = qxfer->parent.length; + qspi->tx_transfer.src_addr = qspi->tx_config.src_addr; + + if ((err = rt_dma_prep_single(qspi->dma_tx, &qspi->tx_transfer))) + { + return err; + } + + if ((err = rt_dma_chan_start(qspi->dma_tx))) + { + return err; + } + + return rt_completion_wait(&qspi->dma_completion, RT_WAITING_FOREVER); +} + +static rt_err_t k1x_qspi_rx_dma_exec(struct k1x_qspi *qspi, struct rt_qspi_message *qxfer) +{ + rt_err_t err; + + qspi->rx_config.dst_addr = (rt_ubase_t)rt_kmem_v2p(qxfer->parent.recv_buf); + + if ((err = rt_dma_chan_config(qspi->dma_rx, &qspi->rx_config))) + { + return err; + } + + qspi->rx_transfer.buffer_len = qxfer->parent.length; + qspi->rx_transfer.dst_addr = qspi->rx_config.dst_addr; + + if ((err = rt_dma_prep_memcpy(qspi->dma_rx, &qspi->rx_transfer))) + { + return err; + } + + if ((err = rt_dma_chan_start(qspi->dma_rx))) + { + return err; + } + + return rt_completion_wait(&qspi->dma_completion, + rt_tick_from_millisecond(qxfer->parent.length)); +} + +static rt_err_t k1x_qspi_ahb_read(struct k1x_qspi *qspi, struct rt_qspi_message *qxfer) +{ + rt_err_t err; + rt_uint32_t len = qxfer->parent.length, from = qxfer->address.content; + + /* Read out the data directly from the AHB buffer. */ + if (from + len > qspi->memmap_size) + { + return -RT_ENOSYS; + } + + /* Firstly try the DMA */ + if (qspi->rx_dma_enable) + { + if (!(err = k1x_qspi_rx_dma_exec(qspi, qxfer))) + { + return RT_EOK; + } + else + { + LOG_D("Read rx dma fallback to memcpy read"); + } + } + + rt_memcpy(qxfer->parent.recv_buf, (qspi->ahb_map + qxfer->address.content), len); + + return RT_EOK; +} + +static rt_err_t k1x_qspi_fill_txfifo(struct k1x_qspi *qspi, struct rt_qspi_message *qxfer) +{ + int i; + void *base = qspi->io_map; + rt_uint32_t val, tbsr, wait_cnt; + rt_size_t length = qxfer->parent.length; + + if (!qspi->tx_dma_enable || (length % QSPI_TX_BUFF_POP_MIN)) + { + qspi->tx_wmrk = 0; + for (i = 0; i < RT_ALIGN_DOWN(length, 4); i += 4) + { + rt_memcpy(&val, qxfer->parent.send_buf + i, 4); + qspi_writel(qspi, val, base + QSPI_TBDR); + } + + if (i < length) + { + rt_memcpy(&val, qxfer->parent.send_buf + i, length - i); + qspi_writel(qspi, val, base + QSPI_TBDR); + } + + /* + * There must be at least 128bit data available in TX FIFO + * for any pop operation otherwise QSPI_FR[TBUF] will be set + */ + for (i = length; i < RT_ALIGN_DOWN(length + (QSPI_TX_BUFF_POP_MIN - 1), QSPI_TX_BUFF_POP_MIN); i += 4) + { + qspi_writel(qspi, 0, base + QSPI_TBDR); + } + } + else + { + /* + * Note that the number of bytes per DMA loop is determined + * by thee size of the QSPI_TBCT[WMRK]. + * bytes per DMA loop = (QSPI_TBCT[WMRK] + 1) * 4. + * set QSPI_TX_WMRK as the TX watermark. + */ + qspi->tx_wmrk = QSPI_TX_WMRK; + qspi_writel(qspi, qspi->tx_wmrk, base + QSPI_TBCT); + + /* Config DMA channel and start */ + if (k1x_qspi_tx_dma_exec(qspi, qxfer)) + { + qspi->tx_wmrk = 0; + LOG_E("Failed to start tx dma"); + return -RT_EIO; + } + + /* Enable DMA request */ + k1x_qspi_enable_interrupt(qspi, QSPI_RSER_TBFDE); + + /* + * before trigger qspi to send data to external bus, TX bufer + * need to have some data, or underrun error may happen. + * DMA need some time to write data to TX buffer, so add + * a delay here for this requirement. + */ + wait_cnt = 0; + tbsr = qspi_readl(qspi, base + QSPI_TBSR); + + while (4 * (tbsr >> 16) < rt_min_t(unsigned int, qspi->tx_buf_size, length)) + { + rt_hw_us_delay(1); + tbsr = qspi_readl(qspi, base + QSPI_TBSR); + + if (wait_cnt++ >= 100) + { + rt_thread_mdelay(100); + tbsr = qspi_readl(qspi, base + QSPI_TBSR); + + if (4 * (tbsr >> 16) < rt_min_t(unsigned int, qspi->tx_buf_size, length)) + { + LOG_E("Failed to fill tx dma"); + /* Disable all interrupts */ + qspi_writel(qspi, 0, qspi->io_map + QSPI_RSER); + rt_dma_chan_stop(qspi->dma_tx); + qspi->tx_wmrk = 0; + + return -RT_EIO; + } + else + { + break; + } + } + } + } + + return RT_EOK; +} + +static void k1x_qspi_read_rxfifo(struct k1x_qspi *qspi, struct rt_qspi_message *qxfer) +{ + int i; + rt_uint32_t val; + rt_uint8_t *buf; + void *base = qspi->io_map; + rt_size_t length = qxfer->parent.length; + + buf = qxfer->parent.recv_buf; + + for (i = 0; i < RT_ALIGN_DOWN(length, 4); i += 4) + { + val = qspi_readl(qspi, base + QSPI_RBDR(i / 4)); + rt_memcpy(buf + i, &val, 4); + } + + if (i < length) + { + val = qspi_readl(qspi, base + QSPI_RBDR(i / 4)); + rt_memcpy(buf + i, &val, length - i); + } +} + +static rt_err_t k1x_qspi_do_op(struct k1x_qspi *qspi, struct rt_qspi_message *qxfer) +{ + rt_uint32_t mcr; + rt_err_t err = RT_EOK; + void *base = qspi->io_map; + rt_size_t length = qxfer->parent.length; + + if (qspi->cmd_interrupt) + { + k1x_qspi_enable_interrupt(qspi, QSPI_RSER_TFIE | BUFFER_ERROR_INT | COMMAND_ERROR_INT); + } + + /* Trigger LUT */ + qspi_writel(qspi, length | QSPI_IPCR_SEQID(SEQID_LUT_SHARED_ID), base + QSPI_IPCR); + + /* Wait for the transaction complete */ + if (qspi->cmd_interrupt) + { + rt_completion_wait(&qspi->cmd_completion, RT_WAITING_FOREVER); + } + else + { + err = k1x_qspi_readl_poll_tout(qspi, base + QSPI_FR, QSPI_FR_TFF_MASK, + QSPI_WAIT_TIMEOUT * 1000, QSPI_WAIT_BIT_SET); + } + + if (err) + { + goto _tx_dma_unmap; + } + + if ((err = k1x_qspi_readl_poll_tout(qspi, base + QSPI_SR, QSPI_SR_BUSY, + QSPI_WAIT_TIMEOUT * 1000, QSPI_WAIT_BIT_CLEAR))) + { + goto _tx_dma_unmap; + } + + /* Read RX buffer for IP command read */ + if (length && qxfer->parent.recv_buf) + { + k1x_qspi_read_rxfifo(qspi, qxfer); + } + + if (qspi->fr_error_flag & QSPI_FR_TBUF) + { + /* Abort current dma transfer */ + if (qspi->tx_dma_enable) + { + rt_dma_chan_stop(qspi->dma_tx); + } + + /* Clear TX buf */ + mcr = qspi_readl(qspi, qspi->io_map + QSPI_MCR); + mcr |= QSPI_MCR_CLR_TXF_MASK ; + qspi_writel(qspi, mcr, qspi->io_map + QSPI_MCR); + + /* Reduce tx unit size and retry */ + if (qspi->tx_dma_enable) + { + qspi->tx_unit_size = qspi->tx_buf_size; + } + + err = -RT_EIO; + } + else + { + if (qspi->tx_dma_enable) + { + qspi->tx_unit_size = qspi->tx_buf_size; + } + } + +_tx_dma_unmap: + if (qspi->tx_wmrk) + { + /* Disable TBFDE interrupt and dma unmap */ + k1x_qspi_disable_interrupt(qspi, QSPI_RSER_TBFDE); + qspi->tx_wmrk = 0; + } + + return err; +} + +static rt_bool_t is_read_from_cache_opcode(rt_uint8_t opcode) +{ + return ((opcode == READ_FROM_CACHE_OP) || + (opcode == READ_FROM_CACHE_OP_Fast) || + (opcode == READ_FROM_CACHE_OP_X2) || + (opcode == READ_FROM_CACHE_OP_X4) || + (opcode == READ_FROM_CACHE_OP_DUALIO) || + (opcode == READ_FROM_CACHE_OP_QUADIO)); +} + +static rt_err_t k1x_qspi_configure(struct rt_spi_device *device, + struct rt_spi_configuration *conf) +{ + return RT_EOK; +} + +static rt_ssize_t k1x_qspi_xfer(struct rt_spi_device *device, + struct rt_spi_message *xfer) +{ + void *base; + rt_err_t err = RT_EOK; + rt_uint32_t mask, reg; + struct k1x_qspi *qspi = raw_to_k1x_qspi(device->bus); + struct rt_qspi_message *qxfer = rt_container_of(xfer, struct rt_qspi_message, parent); + + base = qspi->io_map; + + /* Wait for controller being ready */ + mask = QSPI_SR_BUSY | QSPI_SR_IP_ACC_MASK | QSPI_SR_AHB_ACC_MASK; + if ((err = k1x_qspi_readl_poll_tout(qspi, + base + QSPI_SR, mask, QSPI_WAIT_TIMEOUT * 1000, QSPI_WAIT_BIT_CLEAR))) + { + LOG_E("Controller not ready"); + return err; + } + + /* Clear TX/RX buffer before transaction */ + reg = qspi_readl(qspi, base + QSPI_MCR); + reg |= QSPI_MCR_CLR_TXF_MASK | QSPI_MCR_CLR_RXF_MASK; + qspi_writel(qspi, reg, base + QSPI_MCR); + + /* + * Reset the sequence pointers whenever the sequence ID is changed by + * updating the SEDID filed in QSPI_IPCR OR QSPI_BFGENCR. + */ + reg = qspi_readl(qspi, base + QSPI_SPTRCLR); + reg |= (QSPI_SPTRCLR_IPPTRC | QSPI_SPTRCLR_BFPTRC); + qspi_writel(qspi, reg, base + QSPI_SPTRCLR); + + /* Set the flash address into the QSPI_SFAR */ + qspi_write_sfar(qspi, qspi->memmap_base + qxfer->address.content); + + /* Clear QSPI_FR before trigger LUT command */ + if ((reg = qspi_readl(qspi, base + QSPI_FR))) + { + qspi_writel(qspi, reg, base + QSPI_FR); + } + qspi->fr_error_flag = 0; + + /* + * Read page command 13h must be done by IP command. + * read from cache through the AHB bus by accessing the mapped memory. + * In all other cases we use IP commands to access the flash. + */ + if (xfer->length > (qspi->rx_buf_size - 4) && + xfer->recv_buf && qspi->ahb_read_enable && + is_read_from_cache_opcode(qxfer->instruction.content)) + { + k1x_qspi_prepare_lut(qspi, qxfer, SEQID_LUT_AHBREAD_ID); + err = k1x_qspi_ahb_read(qspi, qxfer); + } + else + { + /* IP command */ + k1x_qspi_prepare_lut(qspi, qxfer, SEQID_LUT_SHARED_ID); + + if (xfer->length && xfer->send_buf) + { + err = k1x_qspi_fill_txfifo(qspi, qxfer); + } + if (!err) + { + err = k1x_qspi_do_op(qspi, qxfer); + } + } + + /* Invalidate the data in the AHB buffer. */ + k1x_qspi_invalid(qspi); + + return err ? : xfer->length; +} + +static const struct rt_spi_ops k1x_qspi_ops = +{ + .configure = k1x_qspi_configure, + .xfer = k1x_qspi_xfer, +}; + +static void k1x_qspi_isr(int irq, void *param) +{ + rt_uint32_t fr; + struct k1x_qspi *qspi = param; + + /* Disable all interrupts */ + qspi_writel(qspi, 0, qspi->io_map + QSPI_RSER); + + fr = qspi_readl(qspi, qspi->io_map + QSPI_FR); + + /* Check QSPI_FR error flag */ + if (fr & (COMMAND_FR_FLAG | BUFFER_FR_FLAG)) + { + qspi->fr_error_flag = fr & (COMMAND_FR_FLAG | BUFFER_FR_FLAG); + + if (fr & QSPI_FR_IPGEF) + { + LOG_E("IP command trigger during AHB grant"); + } + if (fr & QSPI_FR_IPIEF) + { + LOG_E("IP command trigger could not be executed"); + } + if (fr & QSPI_FR_IPAEF) + { + LOG_E("IP command trigger during AHB access"); + } + if (fr & QSPI_FR_IUEF) + { + LOG_E("IP command usage error"); + } + if (fr & QSPI_FR_AIBSEF) + { + LOG_E("AHB illegal burst size error"); + } + if (fr & QSPI_FR_AITEF) + { + LOG_E("AHB illegal transaction error"); + } + if (fr & QSPI_FR_ABSEF) + { + LOG_E("AHB sequence error"); + } + + if (fr & QSPI_FR_TBUF) + { + /* Disable TBFDE interrupt */ + k1x_qspi_disable_interrupt(qspi, QSPI_RSER_TBFDE); + LOG_E("TX buffer underrun"); + } + if (fr & QSPI_FR_RBOF) + { + LOG_E("RX buffer overflow"); + } + if (fr & QSPI_FR_ABOF) + { + LOG_E("AHB buffer overflow"); + } + } + + if (qspi->cmd_interrupt && (fr & (QSPI_FR_TFF_MASK | COMMAND_FR_FLAG | BUFFER_FR_FLAG))) + { + rt_completion_done(&qspi->cmd_completion); + } +} + +static void k1x_qspi_free(struct k1x_qspi *qspi, struct rt_device *dev) +{ + /* Set disable mode */ + qspi_writel(qspi, QSPI_MCR_MDIS_MASK, qspi->io_map + QSPI_MCR); + qspi_writel(qspi, 0x0, qspi->io_map + QSPI_RSER); + + if (qspi->io_map) + { + rt_iounmap(qspi->io_map); + } + + if (qspi->pmuap_addr) + { + rt_iounmap(qspi->pmuap_addr); + } + + if (!rt_is_err_or_null(qspi->dma_tx)) + { + rt_dma_chan_release(qspi->dma_tx); + } + + if (!rt_is_err_or_null(qspi->dma_rx)) + { + rt_dma_chan_release(qspi->dma_rx); + } + + if (!rt_is_err_or_null(qspi->rstc)) + { + rt_reset_control_assert(qspi->rstc); + rt_reset_control_put(qspi->rstc); + } + + if (!rt_is_err_or_null(qspi->clk)) + { + rt_clk_disable_unprepare(qspi->clk); + rt_clk_put(qspi->clk); + } + + if (!rt_is_err_or_null(qspi->bus_clk)) + { + rt_clk_disable_unprepare(qspi->bus_clk); + rt_clk_put(qspi->bus_clk); + } + + rt_free(qspi); +} + +static rt_err_t k1x_qspi_probe(struct rt_platform_device *pdev) +{ + void *base; + rt_err_t err; + rt_uint32_t reg; + const char *bus_name; + rt_uint64_t addr, size; + rt_uint32_t qspi_bus_num = 0; + struct rt_device *dev = &pdev->parent; + struct k1x_qspi *qspi = rt_calloc(1, sizeof(*qspi)); + + if (!qspi) + { + return -RT_ENOMEM; + } + + if (!(qspi->io_map = rt_dm_dev_iomap_by_name(dev, "qspi-base"))) + { + err = -RT_EIO; + goto _fail; + } + qspi->io_phys = (rt_ubase_t)rt_kmem_v2p(qspi->io_map); + + if ((err = rt_dm_dev_get_address_by_name(dev, "qspi-mmap", &addr, &size))) + { + err = -RT_EIO; + goto _fail; + } + qspi->ahb_map = rt_ioremap((void *)addr, size); + qspi->memmap_base = addr; + qspi->memmap_size = size; + + if ((qspi->irq = rt_dm_dev_get_irq(dev, 0)) < 0) + { + err = qspi->irq; + goto _fail; + } + + if ((err = rt_dm_dev_prop_read_u32(dev, "k1x,qspi-freq", &qspi->max_hz))) + { + goto _fail; + } + + if (rt_dm_dev_prop_read_u32(dev, "k1x,qspi-sfa1ad", &qspi->sfa1ad)) + { + qspi->sfa1ad = QSPI_FLASH_A1_TOP(qspi); + } + else + { + qspi->sfa1ad += qspi->memmap_base; + } + if (rt_dm_dev_prop_read_u32(dev, "k1x,qspi-sfa2ad", &qspi->sfa2ad)) + { + qspi->sfa2ad = QSPI_FLASH_A2_TOP(qspi); + } + else + { + qspi->sfa2ad += qspi->sfa1ad; + } + if (rt_dm_dev_prop_read_u32(dev, "k1x,qspi-sfb1ad", &qspi->sfb1ad)) + { + qspi->sfb1ad = QSPI_FLASH_B1_TOP(qspi); + } + else + { + qspi->sfb1ad = qspi->sfa2ad; + } + if (rt_dm_dev_prop_read_u32(dev, "k1x,qspi-sfb2ad", &qspi->sfb2ad)) + { + qspi->sfb2ad = QSPI_FLASH_B2_TOP(qspi); + } + else + { + qspi->sfb2ad += qspi->sfb1ad; + } + + /* map QSPI PMUap register address */ + if (rt_dm_dev_prop_read_u32(dev, "k1x,qspi-pmuap-reg", &qspi->pmuap_reg)) + { + qspi->pmuap_reg = PMUA_QSPI_CLK_RES_CTRL; + } + qspi->pmuap_addr = rt_ioremap((void *)(rt_ubase_t)qspi->pmuap_reg, 4); + + if (rt_dm_dev_prop_read_u32(dev, "k1x,qspi-mpmu-acgr-reg", &qspi->mpmu_acgr_reg)) + { + qspi->mpmu_acgr_reg = K1X_MPMU_ACGR; + } + qspi->mpmu_acgr = rt_ioremap((void *)(rt_ubase_t)qspi->mpmu_acgr_reg, 4); + + if (rt_dm_dev_prop_read_u32(dev, "k1x,qspi-rx-buf", &qspi->rx_buf_size)) + { + qspi->rx_buf_size = QSPI_RX_BUFF_MAX; + } + + if (rt_dm_dev_prop_read_u32(dev, "k1x,qspi-tx-buf", &qspi->tx_buf_size)) + { + qspi->tx_buf_size = QSPI_TX_BUFF_MAX; + } + + if (rt_dm_dev_prop_read_u32(dev, "k1x,qspi-ahb-buf", &qspi->ahb_buf_size)) + { + qspi->ahb_buf_size = QSPI_AHB_BUFF_MAX_SIZE; + } + + if (rt_dm_dev_prop_read_u32(dev, "k1x,qspi-ahb-enable", &qspi->ahb_read_enable)) + { + qspi->ahb_read_enable = 1; + } + + if (rt_dm_dev_prop_read_u32(dev, "k1x,qspi-interrupt", &qspi->cmd_interrupt)) + { + qspi->cmd_interrupt = 1; + } + + if (rt_dm_dev_prop_read_u32(dev, "k1x,qspi-endian-xchg", &qspi->endian_xchg)) + { + qspi->endian_xchg = 0; + } + + if (rt_dm_dev_prop_read_u32(dev, "k1x,qspi-cs", &qspi->cs_selected)) + { + qspi->cs_selected = QSPI_DEFAULT_CS; + } + + if (rt_dm_dev_prop_read_u32(dev, "k1x,qspi-tx-dma", &qspi->tx_dma_enable)) + { + qspi->tx_dma_enable = 0; + } + + if (rt_dm_dev_prop_read_u32(dev, "k1x,qspi-rx-dma", &qspi->rx_dma_enable)) + { + qspi->rx_dma_enable = 0; + } + + rt_dm_dev_prop_read_u32(dev, "k1x,qspi-id", &qspi_bus_num); + + /* Prepare DMA */ + if (qspi->rx_dma_enable) + { + qspi->dma_rx = rt_dma_chan_request(dev, RT_NULL); + + if (!rt_is_err_or_null(qspi->dma_rx)) + { + qspi->dma_rx->callback = k1x_qspi_dma_callback; + + qspi->rx_config.direction = RT_DMA_MEM_TO_MEM; + qspi->rx_config.src_addr = qspi->memmap_base; + + qspi->rx_transfer.src_addr = qspi->rx_config.src_addr; + } + else + { + qspi->dma_rx = RT_NULL; + qspi->rx_dma_enable = 0; + } + } + + if (qspi->tx_dma_enable) + { + qspi->dma_tx = rt_dma_chan_request(dev, "tx-dma"); + + if (!rt_is_err_or_null(qspi->dma_tx)) + { + qspi->dma_tx->callback = k1x_qspi_dma_callback; + + qspi->tx_config.direction = RT_DMA_MEM_TO_DEV; + qspi->tx_config.dst_addr_width = RT_DMA_SLAVE_BUSWIDTH_4_BYTES; + qspi->tx_config.dst_addr = qspi->io_phys + QSPI_TBDR - 4; + qspi->tx_config.dst_maxburst = QSPI_TX_DMA_BURST; + + qspi->tx_transfer.dst_addr = qspi->tx_config.dst_addr; + } + else + { + qspi->dma_tx = RT_NULL; + qspi->tx_dma_enable = 0; + } + } + + if (qspi->dma_tx || qspi->dma_rx) + { + rt_completion_init(&qspi->dma_completion); + } + + if (qspi->tx_dma_enable) + { + qspi->tx_unit_size = qspi->tx_buf_size; + } + else + { + qspi->tx_unit_size = qspi->tx_buf_size; + } + + if (qspi->ahb_read_enable) + { + qspi->rx_unit_size = 4 * SIZE_KB; + } + else + { + qspi->rx_unit_size = qspi->rx_buf_size; + } + + /* QSPI init start */ + base = qspi->io_map; + + qspi->rstc = rt_reset_control_get_by_index(dev, 0); + if (rt_is_err(qspi->rstc)) + { + err = rt_ptr_err(qspi->rstc); + goto _fail; + } + + rt_reset_control_assert(qspi->rstc); + + /* Set PMUap */ + qspi->clk = rt_clk_get_by_name(dev, "qspi_clk"); + if (rt_is_err(qspi->clk)) + { + err = rt_ptr_err(qspi->clk); + goto _fail; + } + + qspi->bus_clk = rt_clk_get_by_name(dev, "qspi_bus_clk"); + if (rt_is_err(qspi->bus_clk)) + { + err = rt_ptr_err(qspi->bus_clk); + goto _fail; + } + + if ((err = rt_clk_set_rate(qspi->clk, qspi->max_hz))) + { + LOG_E("Fail to set clk"); + goto _fail; + } + + if ((err = rt_clk_prepare_enable(qspi->clk))) + { + LOG_E("Fail to enable clk"); + goto _fail; + } + + rt_clk_prepare_enable(qspi->bus_clk); + + rt_reset_control_deassert(qspi->rstc); + + /* Rest qspi */ + qspi_reset(qspi); + + /* Clock settings */ + qspi_enter_mode(qspi, QSPI_DISABLE_MODE); + + /* Sampled by sfif_clk_b; half cycle delay; */ + if (qspi->max_hz < (QSPI_SMPR_FSPHS_CLK >> 2)) + { + qspi_writel(qspi, 0x0, base + QSPI_SMPR); + } + else + { + qspi_writel(qspi, QSPI_SMPR_FSPHS_MASK, base + QSPI_SMPR); + } + + /* Fix wirte failure issue*/ + qspi_writel(qspi, 0x8, base + QSPI_SOCCR); + + /* Set the default source address QSPI_AMBA_BASE*/ + qspi_write_sfar(qspi, qspi->memmap_base); + qspi_writel(qspi, 0x0, base + QSPI_SFACR); + + /* Config ahb read start */ + /* Disable BUF0~BUF1, use BUF3 for all masters */ + qspi_writel(qspi, 0, base + QSPI_BUF0IND); + qspi_writel(qspi, 0, base + QSPI_BUF1IND); + qspi_writel(qspi, 0, base + QSPI_BUF2IND); + + /* AHB Master port */ + qspi_writel(qspi, 0xe, base + QSPI_BUF0CR); + qspi_writel(qspi, 0xe, base + QSPI_BUF1CR); + qspi_writel(qspi, 0xe, base + QSPI_BUF2CR); + qspi_writel(qspi, + QSPI_BUF3CR_ALLMST_MASK | QSPI_BUF3CR_ADATSZ((qspi->ahb_buf_size / 8)), + base + QSPI_BUF3CR); + + /* Set AHB read sequence id */ + qspi_writel(qspi, + QSPI_BFGENCR_SEQID(SEQID_LUT_AHBREAD_ID), + base + QSPI_BFGENCR); + /* Config ahb read end */ + + /* Set flash memory map */ + qspi_writel(qspi, qspi->sfa1ad & 0xfffffc00, base + QSPI_SFA1AD); + qspi_writel(qspi, qspi->sfa2ad & 0xfffffc00, base + QSPI_SFA2AD); + qspi_writel(qspi, qspi->sfb1ad & 0xfffffc00, base + QSPI_SFB1AD); + qspi_writel(qspi, qspi->sfb2ad & 0xfffffc00, base + QSPI_SFB2AD); + + /* ISD3FB, ISD2FB, ISD3FA, ISD2FA = 1; END_CFG=0x3 */ + reg = qspi_readl(qspi, base + QSPI_MCR); + reg |= QSPI_MCR_END_CFG_MASK | QSPI_MCR_ISD_MASK; + qspi_writel(qspi, reg, base + QSPI_MCR); + + /* Module enabled */ + qspi_enter_mode(qspi, QSPI_NORMAL_MODE); + + /* Read using the IP Bus registers QSPI_RBDR0 to QSPI_RBDR31*/ + qspi_write_rbct(qspi, QSPI_RBCT_RXBRD_MASK); + + /* Clear all interrupt status */ + qspi_writel(qspi, 0xffffffff, base + QSPI_FR); + /* QSPI init end */ + + rt_completion_init(&qspi->cmd_completion); + + dev->user_data = qspi; + + qspi->parent.parent.ofw_node = dev->ofw_node; + + rt_dm_dev_set_name(&qspi->parent.parent, "qspi%d", qspi_bus_num); + bus_name = rt_dm_dev_get_name(&qspi->parent.parent); + + rt_hw_interrupt_install(qspi->irq, k1x_qspi_isr, qspi, bus_name); + rt_hw_interrupt_umask(qspi->irq); + + if ((err = rt_qspi_bus_register(&qspi->parent, bus_name, &k1x_qspi_ops))) + { + goto _fail; + } + + return RT_EOK; +_fail: + k1x_qspi_free(qspi, dev); + + return err; +} + +static rt_err_t k1x_qspi_remove(struct rt_platform_device *pdev) +{ + struct rt_device *dev = &pdev->parent; + struct k1x_qspi *qspi = dev->user_data; + + rt_hw_interrupt_mask(qspi->irq); + rt_pic_detach_irq(qspi->irq, qspi); + + rt_device_unregister(&qspi->parent.parent); + + k1x_qspi_free(qspi, dev); + + return RT_EOK; +} + +static const struct rt_ofw_node_id k1x_qspi_ofw_ids[] = +{ + { .compatible = "spacemit,k1x-qspi", }, + { /* sentinel */ } +}; + +static struct rt_platform_driver k1x_qspi_driver = +{ + .name = "k1x-qspi", + .ids = k1x_qspi_ofw_ids, + + .probe = k1x_qspi_probe, + .remove = k1x_qspi_remove, +}; +RT_PLATFORM_DRIVER_EXPORT(k1x_qspi_driver); diff --git a/bsp/spacemit/dm/spi/spi-k1x.c b/bsp/spacemit/dm/spi/spi-k1x.c new file mode 100644 index 000000000000..fbc7777b8974 --- /dev/null +++ b/bsp/spacemit/dm/spi/spi-k1x.c @@ -0,0 +1,1142 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#include "dev_spi_dm.h" + +#define DBG_TAG "spi.k1x.spi" +#define DBG_LVL DBG_INFO +#include + +#include +#include +#include +#include + +/* Spacemit k1x SPI Registers */ +#define TOP_CTRL 0x00 /* SSP Top Control Register */ +#define FIFO_CTRL 0x04 /* SSP FIFO Control Register */ +#define INT_EN 0x08 /* SSP Interrupt Enable Register */ +#define TO 0x0c /* SSP Time Out Register */ +#define DATAR 0x10 /* SSP Data Register */ +#define STATUS 0x14 /* SSP Stauts Register */ +#define PSP_CTRL 0x18 /* SSP Programmable Serial Protocal Control Register */ +#define NET_WORK_CTRL 0x1c /* SSP NET Work Control Register */ +#define NET_WORK_STATUS 0x20 /* SSP Net Work Status Register */ +#define RWOT_CTRL 0x24 /* SSP RWOT Control Register */ +#define RWOT_CCM 0x28 /* SSP RWOT Counter Cycles Match Register */ +#define RWOT_CVWRn 0x2c /* SSP RWOT Counter Value Write for Read Request Register */ +#define CLK_PHASE_ADJ 0x30 /* SSP clock phase adjustment for debug */ + +/* 0x00 TOP_CTRL */ +#define TOP_TTELP RT_BIT(18) +#define TOP_TTE RT_BIT(17) +#define TOP_SCFR RT_BIT(16) +#define TOP_IFS RT_BIT(15) +#define TOP_HOLD_FRAME_LOW RT_BIT(14) +#define TOP_TRAIL RT_BIT(13) +#define TOP_LBM RT_BIT(12) +#define TOP_SPH RT_BIT(11) +#define TOP_SPO RT_BIT(10) +#define TOP_DSS(x) ((x - 1) << 5) +#define TOP_DSS_MASK (0x1f << 5) +#define TOP_SFRMDIR RT_BIT(4) +#define TOP_SCLKDIR RT_BIT(3) +#define TOP_FRF_MASK (0x3 << 1) +#define TOP_FRF_Motorola (0x0 << 1) /* Motorola's Serial Peripheral Interface (SPI) */ +#define TOP_FRF_TI (0x1 << 1) /* Texas Instruments' Synchronous Serial Protocol (SSP) */ +#define TOP_FRF_National (0x2 << 1) /* National Microwire */ +#define TOP_FRF_PSP (0x3 << 1) /* Programmable Serial Protocol(PSP) */ +#define TOP_SSE RT_BIT(0) + +/* 0x04 FIFO_CTRL */ +#define FIFO_STRF RT_BIT(19) +#define FIFO_EFWR RT_BIT(18) +#define FIFO_RXFIFO_AUTO_FULL_CTRL RT_BIT(17) +#define FIFO_FPCKE RT_BIT(16) +#define FIFO_TXFIFO_WR_ENDIAN_MASK (0x3 << 14) +#define FIFO_RXFIFO_RD_ENDIAN_MASK (0x3 << 12) +#define FIFO_WR_ENDIAN_16BITS RT_BIT(14) /* Swap first 16 bits and last 16 bits */ +#define FIFO_WR_ENDIAN_8BITS (2 << 14) /* Swap all 4 bytes */ +#define FIFO_RD_ENDIAN_16BITS RT_BIT(12) /* Swap first 16 bits and last 16 bits */ +#define FIFO_RD_ENDIAN_8BITS (2 << 12) /* Swap all 4 bytes */ +#define FIFO_RSRE RT_BIT(11) +#define FIFO_TSRE RT_BIT(10) + +/* 0x08 INT_EN */ +#define INT_EN_EBCEI RT_BIT(6) +#define INT_EN_TIM RT_BIT(5) +#define INT_EN_RIM RT_BIT(4) +#define INT_EN_TIE RT_BIT(3) +#define INT_EN_RIE RT_BIT(2) +#define INT_EN_TINTE RT_BIT(1) +#define INT_EN_PINTE RT_BIT(0) + +/* 0x0C TO */ +#define TIMEOUT(x) ((x) << 0) + +/* 0x10 DATAR */ +#define DATA(x) ((x) << 0) + +/* 0x14 STATUS */ +#define STATUS_OSS RT_BIT(23) +#define STATUS_TX_OSS RT_BIT(22) +#define STATUS_BCE RT_BIT(21) +#define STATUS_ROR RT_BIT(20) +#define STATUS_RNE RT_BIT(14) +#define STATUS_RFS RT_BIT(13) +#define STATUS_TUR RT_BIT(12) +#define STATUS_TNF RT_BIT(6) +#define STATUS_TFS RT_BIT(5) +#define STATUS_EOC RT_BIT(4) +#define STATUS_TINT RT_BIT(3) +#define STATUS_PINT RT_BIT(2) +#define STATUS_CSS RT_BIT(1) +#define STATUS_BSY RT_BIT(0) + +/* 0x18 PSP_CTRL */ +#define PSP_EDMYSTOP(x) ((x) << 27) +#define PSP_EMYSTOP(x) ((x) << 25) +#define PSP_EDMYSTRT(x) ((x) << 23) +#define PSP_DMYSTRT(x) ((x) << 21) +#define PSP_STRTDLY(x) ((x) << 18) +#define PSP_SFRMWDTH(x) ((x) << 12) +#define PSP_SFRMDLY(x) ((x) << 5) +#define PSP_SFRMP (1 << 4) +#define PSP_FSRT (1 << 3) +#define PSP_ETDS (1 << 2) +#define PSP_SCMODE(x) ((x) << 0) + +/* 0x1C NET_WORK_CTRL */ +#define RTSA(x) ((x) << 12) +#define RTSA_MASK (0xff << 12) +#define TTSA(x) ((x) << 4) +#define TTSA_MASK (0xff << 4) +#define NET_FRDC(x) ((x) << 1) +#define NET_WORK_MODE (1 << 0) + +/* 0x20 NET_WORK_STATUS */ +#define NET_SATUS_NMBSY (1 << 3) +#define NET_STATUS_TSS(x) ((x) << 0) + +/* 0x24 RWOT_CTRL */ +#define RWOT_MASK_RWOT_LAST_SAMPLE RT_BIT(4) +#define RWOT_CLR_RWOT_CYCLE RT_BIT(3) +#define RWOT_SET_RWOT_CYCLE RT_BIT(2) +#define RWOT_CYCLE_RWOT_EN RT_BIT(1) +#define RWOT_RWOT RT_BIT(0) + +#define TIMOUT_DFLT 3000 +#define TIMOUT_DFLT_SLAVE 0x40000 + +#define RX_THRESH_DFLT 9 +#define TX_THRESH_DFLT 8 +/* 0x14 */ +#define STATUS_TFL_MASK (0x1f << 7) /* Transmit FIFO Level mask */ +#define STATUS_RFL_MASK (0x1f << 15) /* Receive FIFO Level mask */ +/* 0x4 */ +#define FIFO_TFT (0x0000001f) /* Transmit FIFO Threshold (mask) */ +#define FIFO_TxTresh(x) (((x) - 1) << 0) /* level [1..32] */ +#define FIFO_RFT (0x000003e0) /* Receive FIFO Threshold (mask) */ +#define FIFO_RxTresh(x) (((x) - 1) << 5) /* level [1..32] */ +/* + * Select the right DMA implementation. + */ +#define MAX_DMA_LEN (512 * SIZE_KB) +#define DEFAULT_DMA_FIFO_CTRL (FIFO_TSRE | FIFO_RSRE) +#define DEFAULT_DMA_TOP_CTRL (TOP_TRAIL) + +struct k1x_spi; + +struct chip_data +{ + rt_uint32_t top_ctrl; + rt_uint32_t fifo_ctrl; + rt_uint32_t timeout; + rt_uint8_t n_bytes; + rt_uint32_t dma_burst_size; + rt_uint32_t threshold; + rt_uint32_t dma_threshold; + rt_uint8_t enable_dma; + rt_bool_t (*write)(struct k1x_spi *spi); + rt_bool_t (*read)(struct k1x_spi *spi); +}; + +struct k1x_spi +{ + struct rt_spi_bus parent; + + struct rt_clk *clk; + struct rt_reset_control *rstc; + + int irq; + void *ioaddr; + rt_uint32_t ssdr_physical; + rt_uint32_t max_speed_hz; + + /* SSP masks*/ + rt_uint32_t dma_fifo_ctrl; + rt_uint32_t dma_top_ctrl; + rt_uint32_t int_cr; + rt_uint32_t dma_cr; + rt_uint32_t clear_sr; + rt_uint32_t mask_sr; + + rt_bool_t enable_dma; + rt_atomic_t dma_running; + struct rt_dma_chan *rx_chan; + struct rt_dma_chan *tx_chan; + struct rt_dma_slave_config rx_config; + struct rt_dma_slave_config tx_config; + struct rt_dma_slave_transfer rx_transfer; + struct rt_dma_slave_transfer tx_transfer; + + rt_bool_t (*write)(struct k1x_spi *spi); + rt_bool_t (*read)(struct k1x_spi *spi); + void (*transfer_handler)(struct k1x_spi *spi); + + void *tx, *tx_end; + void *rx, *rx_end; + rt_uint8_t n_bytes; + struct rt_spi_message *cur_msg; + + struct chip_data cur_chip; + struct rt_completion cur_msg_completion; + + /* Support RX FIFO auto full control and endian swap */ + rt_bool_t slave_mode; + rt_uint32_t ssp_enhancement; + struct rt_timer slave_rx_timer; +}; + +#define raw_to_k1x_spi(raw) rt_container_of(raw, struct k1x_spi, parent) + +rt_inline rt_uint32_t k1x_spi_read(struct k1x_spi *spi, int reg) +{ + return HWREG32(spi->ioaddr + reg); +} + +rt_inline void k1x_spi_write(struct k1x_spi *spi, int reg, rt_uint32_t val) +{ + HWREG32(spi->ioaddr + reg) = val; +} + +static void k1x_spi_dma_transfer_complete(struct k1x_spi *spi, rt_bool_t error) +{ + if (!rt_atomic_dec_and_test(&spi->dma_running)) + { + return; + } + + /* + * If the other CPU is still handling the ROR interrupt we + * might not know about the error yet. So we re-check the + * ROR bit here before we clear the status register. + */ + if (!error) + { + rt_uint32_t status = k1x_spi_read(spi, STATUS) & spi->mask_sr; + + error = status & STATUS_ROR; + } + + /* Clear status & disable interrupts */ + k1x_spi_write(spi, FIFO_CTRL, k1x_spi_read(spi, FIFO_CTRL) & ~spi->dma_fifo_ctrl); + k1x_spi_write(spi, TOP_CTRL, k1x_spi_read(spi, TOP_CTRL) & ~spi->dma_top_ctrl); + k1x_spi_write(spi, STATUS, spi->clear_sr); + k1x_spi_write(spi, TO, 0); + + if (error) + { + /* In case we got an error we disable the SSP now */ + k1x_spi_write(spi, TOP_CTRL, k1x_spi_read(spi, TOP_CTRL) & ~TOP_SSE); + } +} + +static void k1x_spi_dma_callback(struct rt_dma_chan *chan, rt_size_t size) +{ + struct k1x_spi *spi = chan->priv; + + k1x_spi_dma_transfer_complete(spi, RT_FALSE); +} + +static void k1x_spi_dma_transfer(struct k1x_spi *spi) +{ + rt_uint32_t status; + + status = k1x_spi_read(spi, STATUS) & spi->mask_sr; + + if ((spi->slave_mode && status & STATUS_TINT) || (status & STATUS_ROR)) + { + if (spi->rx) + { + rt_dma_chan_stop(spi->rx_chan); + } + if (spi->tx) + { + rt_dma_chan_stop(spi->tx_chan); + } + k1x_spi_dma_transfer_complete(spi, RT_TRUE); + } +} + +static rt_err_t k1x_spi_set_dma_burst_and_threshold(struct chip_data *chip, + struct rt_spi_device *device, + rt_uint8_t bits_per_word, rt_uint32_t *burst_code, rt_uint32_t *threshold) +{ + /* + * If the DMA burst size is given in chip_info we use + * that, otherwise we set it to half of FIFO size; SPI + * FIFO has 16 entry, so FIFO size = 16*bits_per_word/8; + * Also we use the default FIFO thresholds for now. + */ + if (chip && chip->dma_burst_size) + { + *burst_code = chip->dma_burst_size; + } + else if (bits_per_word <= 8) + { + *burst_code = 8; + } + else if (bits_per_word <= 16) + { + *burst_code = 16; + } + else + { + *burst_code = 32; + } + + *threshold = FIFO_RxTresh(RX_THRESH_DFLT) | FIFO_TxTresh(TX_THRESH_DFLT); + + return RT_EOK; +} + +static rt_bool_t k1x_spi_txfifo_full(struct k1x_spi *spi) +{ + return !(k1x_spi_read(spi, STATUS) & STATUS_TNF); +} + +/* Clear all rx fifo useless data */ +static int k1x_spi_flush(struct k1x_spi *spi) +{ + unsigned long limit = RT_TICK_PER_SECOND << 1; + + do { + while (k1x_spi_read(spi, STATUS) & STATUS_RNE) + { + k1x_spi_read(spi, DATAR); + } + } while ((k1x_spi_read(spi, STATUS) & STATUS_BSY) && --limit); + + k1x_spi_write(spi, STATUS, STATUS_ROR); + + return limit; +} + +static rt_bool_t null_writer(struct k1x_spi *spi) +{ + rt_uint8_t n_bytes = spi->n_bytes; + + if (k1x_spi_txfifo_full(spi) || spi->tx == spi->tx_end) + { + return RT_FALSE; + } + + k1x_spi_write(spi, DATAR, 0); + spi->tx += n_bytes; + + return RT_TRUE; +} + +static rt_bool_t null_reader(struct k1x_spi *spi) +{ + rt_uint8_t n_bytes = spi->n_bytes; + + while ((k1x_spi_read(spi, STATUS) & STATUS_RNE) && (spi->rx < spi->rx_end)) + { + k1x_spi_read(spi, DATAR); + spi->rx += n_bytes; + } + + return spi->rx == spi->rx_end; +} + +static rt_bool_t u8_writer(struct k1x_spi *spi) +{ + if (k1x_spi_txfifo_full(spi) || spi->tx == spi->tx_end) + { + return RT_FALSE; + } + + k1x_spi_write(spi, DATAR, *(rt_uint8_t *)(spi->tx)); + ++spi->tx; + + return RT_TRUE; +} + +static rt_bool_t u8_reader(struct k1x_spi *spi) +{ + while ((k1x_spi_read(spi, STATUS) & STATUS_RNE) && spi->rx < spi->rx_end) + { + *(rt_uint8_t *)(spi->rx) = k1x_spi_read(spi, DATAR); + ++spi->rx; + } + + return spi->rx == spi->rx_end; +} + +static rt_bool_t u16_writer(struct k1x_spi *spi) +{ + if (k1x_spi_txfifo_full(spi) || spi->tx == spi->tx_end) + { + return RT_FALSE; + } + + k1x_spi_write(spi, DATAR, *(rt_uint16_t *)(spi->tx)); + spi->tx += 2; + + return RT_TRUE; +} + +static rt_bool_t u16_reader(struct k1x_spi *spi) +{ + while ((k1x_spi_read(spi, STATUS) & STATUS_RNE) && spi->rx < spi->rx_end) + { + *(rt_uint16_t *)(spi->rx) = k1x_spi_read(spi, DATAR); + spi->rx += 2; + } + + return spi->rx == spi->rx_end; +} + +static rt_bool_t u32_writer(struct k1x_spi *spi) +{ + if (k1x_spi_txfifo_full(spi) || spi->tx == spi->tx_end) + { + return RT_FALSE; + } + + k1x_spi_write(spi, DATAR, *(rt_uint32_t *)(spi->tx)); + spi->tx += 4; + + return RT_TRUE; +} + +static rt_bool_t u32_reader(struct k1x_spi *spi) +{ + while ((k1x_spi_read(spi, STATUS) & STATUS_RNE) && spi->rx < spi->rx_end) + { + *(rt_uint32_t *)(spi->rx) = k1x_spi_read(spi, DATAR); + spi->rx += 4; + } + + return spi->rx == spi->rx_end; +} + +static void reset_fifo_ctrl(struct k1x_spi *spi) +{ + rt_uint32_t fifo_ctrl = 0; + struct chip_data *chip = &spi->cur_chip; + + fifo_ctrl |= chip->threshold; + k1x_spi_write(spi, FIFO_CTRL, fifo_ctrl); +} + +static void int_transfer_stop(struct k1x_spi *spi) +{ + rt_uint32_t int_en = 0; + + /* Stop SSP */ + k1x_spi_write(spi, STATUS, spi->clear_sr); + reset_fifo_ctrl(spi); + + int_en = k1x_spi_read(spi, INT_EN); + int_en &= ~spi->int_cr; + k1x_spi_write(spi, INT_EN, int_en); + + k1x_spi_write(spi, TO, 0); +} + +static void interrupt_transfer(struct k1x_spi *spi) +{ + rt_uint32_t irq_mask, irq_status; + + irq_mask = (k1x_spi_read(spi, INT_EN) & INT_EN_TIE) ? + spi->mask_sr : spi->mask_sr & ~STATUS_TFS; + irq_status = k1x_spi_read(spi, STATUS) & irq_mask; + + if (irq_status & STATUS_ROR) + { + /* Stop and rstc SSP */ + int_transfer_stop(spi); + k1x_spi_flush(spi); + k1x_spi_write(spi, TOP_CTRL, k1x_spi_read(spi, TOP_CTRL) & ~(TOP_SSE | TOP_HOLD_FRAME_LOW)); + return; + } + + if (irq_status & STATUS_TINT) + { + k1x_spi_write(spi, STATUS, STATUS_TINT); + + if (spi->read(spi)) + { + int_transfer_stop(spi); + return; + } + } + + /* Drain rx fifo, Fill tx fifo and prevent overruns */ + do { + if (spi->read(spi)) + { + int_transfer_stop(spi); + return; + } + } while (spi->write(spi)); + + if (spi->read(spi)) + { + int_transfer_stop(spi); + return; + } + + if (spi->tx == spi->tx_end) + { + rt_uint32_t int_en; + + int_en = k1x_spi_read(spi, INT_EN); + int_en &= ~INT_EN_TIE; + + k1x_spi_write(spi, INT_EN, int_en); + } +} + +static void slave_rx_timer_expired(void *param) +{ + struct k1x_spi *spi = param; + + if (spi->rx) + { + rt_dma_chan_stop(spi->rx_chan); + } + if (spi->tx) + { + rt_dma_chan_stop(spi->tx_chan); + } + k1x_spi_dma_transfer_complete(spi, RT_TRUE); +} + +static rt_err_t k1x_spi_spi_configure(struct rt_spi_device *device, + struct rt_spi_configuration *conf) +{ + rt_uint32_t tx_thres, rx_thres; + struct k1x_spi *spi = raw_to_k1x_spi(device->bus); + struct chip_data *chip = &spi->cur_chip; + + tx_thres = TX_THRESH_DFLT; + rx_thres = RX_THRESH_DFLT; + + chip->top_ctrl = 0; + chip->fifo_ctrl = 0; + chip->enable_dma = spi->enable_dma; + + if (spi->slave_mode) + { + chip->dma_burst_size = 32; + } + + if (chip->enable_dma) + { + /* Set up legal burst and threshold for dma */ + if (k1x_spi_set_dma_burst_and_threshold(chip, device, + device->config.data_width, &chip->dma_burst_size, &chip->dma_threshold)) + { + LOG_W("DMA burst size reduced to match bits_per_word"); + } + } + chip->threshold = (FIFO_RxTresh(rx_thres) & FIFO_RFT) | (FIFO_TxTresh(tx_thres) & FIFO_TFT); + + chip->top_ctrl &= ~(TOP_SPO | TOP_SPH); + chip->top_ctrl |= (((device->config.mode & RT_SPI_CPHA) != 0) ? TOP_SPH : 0) + | (((device->config.mode & RT_SPI_CPOL) != 0) ? TOP_SPO : 0); + + /* Enable rx fifo auto full control */ + if (spi->ssp_enhancement) + { + chip->fifo_ctrl |= FIFO_RXFIFO_AUTO_FULL_CTRL; + } + + if (device->config.data_width <= 8) + { + chip->n_bytes = 1; + chip->read = u8_reader; + chip->write = u8_writer; + } + else if (device->config.data_width <= 16) + { + chip->n_bytes = 2; + chip->read = u16_reader; + chip->write = u16_writer; + } + else if (device->config.data_width <= 32) + { + chip->n_bytes = 4; + chip->read = u32_reader; + chip->write = u32_writer; + } + + if (rt_clk_get_rate(spi->clk) != spi->max_speed_hz) + { + rt_clk_set_rate(spi->clk, spi->max_speed_hz); + } + + return RT_EOK; +} + +static rt_ssize_t k1x_spi_spi_xfer(struct rt_spi_device *device, + struct rt_spi_message *msg) +{ + rt_err_t err; + rt_uint8_t bits = 0; + rt_uint32_t top_ctrl, fifo_ctrl, int_en = 0, dma_thresh, dma_burst; + struct k1x_spi *spi = raw_to_k1x_spi(device->bus); + struct chip_data *chip = &spi->cur_chip; + + dma_thresh = chip->dma_threshold; + dma_burst = chip->dma_burst_size; + + if (spi->slave_mode) + { + rt_tick_t tick = rt_tick_from_millisecond(1000); + + rt_timer_control(&spi->slave_rx_timer, RT_TIMER_CTRL_SET_TIME, &tick); + + rt_timer_start(&spi->slave_rx_timer); + } + + /* Setup the transfer state based on the type of transfer */ + if (k1x_spi_flush(spi) == 0) + { + rt_timer_stop(&spi->slave_rx_timer); + + LOG_E("Flush failed"); + return -RT_EIO; + } + + if (device->config.max_hz && device->config.max_hz != rt_clk_get_rate(spi->clk)) + { + rt_clk_set_rate(spi->clk, device->config.max_hz); + } + + spi->n_bytes = chip->n_bytes; + spi->tx = (void *)msg->send_buf; + spi->tx_end = spi->tx + msg->length; + spi->rx = msg->recv_buf; + spi->rx_end = spi->rx + msg->length; + spi->write = spi->tx ? chip->write : null_writer; + spi->read = spi->rx ? chip->read : null_reader; + spi->cur_msg = msg; + + /* Change speed and bit per word on a per transfer */ + bits = device->config.data_width; + + if (bits <= 8) + { + spi->n_bytes = 1; + spi->read = spi->read != null_reader ? u8_reader : null_reader; + spi->write = spi->write != null_writer ? u8_writer : null_writer; + } + else if (bits <= 16) + { + spi->n_bytes = 2; + spi->read = spi->read != null_reader ? u16_reader : null_reader; + spi->write = spi->write != null_writer ? u16_writer : null_writer; + } + else if (bits <= 32) + { + spi->n_bytes = 4; + spi->read = spi->read != null_reader ? u32_reader : null_reader; + spi->write = spi->write != null_writer ? u32_writer : null_writer; + } + + /* + * If bits/word is changed in dma mode, then must check the + * thresholds and burst also + */ + if (chip->enable_dma) + { + if (k1x_spi_set_dma_burst_and_threshold(chip, + device, bits, &dma_burst, &dma_thresh)) + { + LOG_W("DMA burst size reduced to match bits_per_word"); + } + } + + /* + * Configure topctrl: + * set Motorola Frame Format + * set DSS + */ + top_ctrl = TOP_FRF_Motorola | TOP_DSS(bits); + LOG_D("%u Hz, %s", spi->max_speed_hz, chip->enable_dma ? "DMA" : "PIO"); + + top_ctrl |= chip->top_ctrl; + fifo_ctrl = chip->fifo_ctrl; + + if (spi->ssp_enhancement) + { + /* + * If transfer length is times of 4, then use + * 32 bit fifo width with endian swap support + */ + if (msg->length % 4 == 0 && bits <= 16) + { + if (bits <= 8) + { + fifo_ctrl |= FIFO_WR_ENDIAN_8BITS | FIFO_RD_ENDIAN_8BITS; + } + else if (bits <= 16) + { + fifo_ctrl |= FIFO_WR_ENDIAN_16BITS | FIFO_RD_ENDIAN_16BITS; + } + + bits = 32; + spi->n_bytes = 4; + if (msg->recv_buf) + { + spi->read = u32_reader; + } + if (msg->send_buf) + { + spi->write = u32_writer; + } + + if (chip->enable_dma) + { + if (k1x_spi_set_dma_burst_and_threshold(chip, + device, bits, &dma_burst, &dma_thresh)) + { + LOG_W("DMA burst size reduced to match bits_per_word"); + } + } + + top_ctrl &= ~TOP_DSS_MASK; + top_ctrl |= TOP_DSS(32); + } + } + + /* Check DMA is possible */ + if (msg->length <= MAX_DMA_LEN) + { + enum rt_dma_slave_buswidth width; + + /* Ensure we have the correct interrupt handler */ + spi->transfer_handler = k1x_spi_dma_transfer; + + switch (spi->n_bytes) + { + case 1: + width = RT_DMA_SLAVE_BUSWIDTH_1_BYTE; + break; + case 2: + width = RT_DMA_SLAVE_BUSWIDTH_2_BYTES; + break; + default: + width = RT_DMA_SLAVE_BUSWIDTH_4_BYTES; + break; + } + + if (spi->rx) + { + spi->rx_config.dst_addr = (rt_ubase_t)rt_kmem_v2p(spi->rx); + spi->rx_config.dst_addr_width = width; + spi->rx_config.dst_maxburst = msg->length; + + if ((err = rt_dma_chan_config(spi->rx_chan, &spi->rx_config))) + { + return err; + } + + spi->rx_transfer.buffer_len = msg->length; + spi->rx_transfer.dst_addr = spi->rx_config.dst_addr; + + if ((err = rt_dma_prep_single(spi->rx_chan, &spi->rx_transfer))) + { + return err; + } + + if ((err = rt_dma_chan_start(spi->rx_chan))) + { + return err; + } + } + + if (spi->tx) + { + spi->tx_config.src_addr = (rt_ubase_t)rt_kmem_v2p(spi->tx); + spi->tx_config.src_addr_width = width; + spi->tx_config.src_maxburst = chip->dma_burst_size; + + if ((err = rt_dma_chan_config(spi->tx_chan, &spi->tx_config))) + { + return err; + } + + spi->tx_transfer.buffer_len = msg->length; + spi->tx_transfer.src_addr = spi->tx_config.src_addr; + + if ((err = rt_dma_prep_single(spi->tx_chan, &spi->tx_transfer))) + { + return err; + } + + if ((err = rt_dma_chan_start(spi->tx_chan))) + { + return err; + } + } + + /* Clear status and start DMA engine */ + fifo_ctrl |= chip->fifo_ctrl | dma_thresh | spi->dma_fifo_ctrl; + top_ctrl |= chip->top_ctrl | spi->dma_top_ctrl; + k1x_spi_write(spi, STATUS, spi->clear_sr); + + rt_atomic_store(&spi->dma_running, 1); + + int_en = k1x_spi_read(spi, INT_EN) | spi->dma_cr; + } + else + { + /* Ensure we have the correct interrupt handler */ + spi->transfer_handler = interrupt_transfer; + + fifo_ctrl = fifo_ctrl | chip->fifo_ctrl | chip->threshold; + int_en = k1x_spi_read(spi, INT_EN) | spi->int_cr; + k1x_spi_write(spi, STATUS, spi->clear_sr); + } + + k1x_spi_write(spi, TO, chip->timeout); + + if (spi->slave_mode) + { + top_ctrl |= TOP_SSE | TOP_SCLKDIR | TOP_SFRMDIR; + } + else + { + top_ctrl |= TOP_HOLD_FRAME_LOW; + } + + /* + * This part changed the logic + * 1. clear SSE + * 2. write TOP_CTRL and other register + * 3. set SSE in the end of this function + */ + top_ctrl &= ~TOP_SSE; + k1x_spi_write(spi, TOP_CTRL, top_ctrl); + k1x_spi_write(spi, FIFO_CTRL, fifo_ctrl); + k1x_spi_write(spi, INT_EN, int_en); + top_ctrl |= TOP_SSE; + k1x_spi_write(spi, TOP_CTRL, top_ctrl); + + rt_completion_wait(&spi->cur_msg_completion, RT_WAITING_FOREVER); + + /* Disable the SSP now */ + k1x_spi_write(spi, TOP_CTRL, k1x_spi_read(spi, TOP_CTRL) & ~(TOP_SSE | TOP_HOLD_FRAME_LOW)); + + return msg->length; +} + +static struct rt_spi_ops k1x_spi_spi_ops = +{ + .configure = k1x_spi_spi_configure, + .xfer = k1x_spi_spi_xfer, +}; + +static void k1x_spi_spi_isr(int irq, void *param) +{ + rt_uint32_t int_en, mask, isr; + struct k1x_spi *spi = param; + + /* + * If the device is not yet in RPM suspended state and we get an + * interrupt that is meant for another device, check if status bits + * are all set to one. That means that the device is already powered off. + */ + isr = k1x_spi_read(spi, STATUS); + if (isr == ~0) + { + return; + } + + int_en = k1x_spi_read(spi, INT_EN); + mask = spi->mask_sr; + + /* Ignore possible writes if we don't need to write */ + if (!(int_en & INT_EN_TIE)) + { + mask &= ~STATUS_TFS; + } + + /* Ignore RX timeout interrupt if it is disabled */ + if (!(int_en & INT_EN_TINTE)) + { + mask &= ~STATUS_TINT; + } + + if (!(isr & mask)) + { + return; + } + + if (!spi->cur_msg) + { + k1x_spi_write(spi, TOP_CTRL, + k1x_spi_read(spi, TOP_CTRL) & ~(TOP_SSE | TOP_HOLD_FRAME_LOW)); + k1x_spi_write(spi, INT_EN, + k1x_spi_read(spi, INT_EN) & ~spi->int_cr); + k1x_spi_write(spi, TO, 0); + k1x_spi_write(spi, STATUS, spi->clear_sr); + + LOG_E("Bad message state in interrupt handler"); + + /* Never fail */ + return; + } + + return spi->transfer_handler(spi); +} + +static void k1x_spi_free(struct k1x_spi *spi, struct rt_device *dev) +{ + if (!rt_is_err_or_null(spi->rstc)) + { + rt_reset_control_assert(spi->rstc); + rt_reset_control_put(spi->rstc); + } + + if (!rt_is_err_or_null(spi->clk)) + { + rt_clk_disable_unprepare(spi->clk); + rt_clk_put(spi->clk); + } + + if (!rt_is_err_or_null(spi->rx_chan)) + { + rt_dma_chan_release(spi->rx_chan); + } + + if (!rt_is_err_or_null(spi->tx_chan)) + { + rt_dma_chan_release(spi->tx_chan); + } +} + +static rt_err_t k1x_spi_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + rt_uint32_t value, bus_num; + const char *bus_name; + struct rt_device *dev = &pdev->parent; + struct k1x_spi *spi = rt_calloc(1, sizeof(*spi)); + + if (!spi) + { + return -RT_ENOMEM; + } + + if (!(spi->ioaddr = rt_dm_dev_iomap(dev, 0))) + { + err = -RT_EIO; + goto _fail; + } + spi->ssdr_physical = (rt_ubase_t)rt_kmem_v2p(spi->ioaddr) + DATAR; + + if ((spi->irq = rt_dm_dev_get_irq(dev, 0)) < 0) + { + err = spi->irq; + goto _fail; + } + + spi->clk = rt_clk_get_by_index(dev, 0); + if (rt_is_err(spi->clk)) + { + err = rt_ptr_err(spi->clk); + goto _fail; + } + + spi->rstc = rt_reset_control_get_by_index(dev, 0); + if (rt_is_err(spi->rstc)) + { + err = rt_ptr_err(spi->rstc); + goto _fail; + } + + spi->enable_dma = !rt_dm_dev_prop_read_bool(dev, "k1x,ssp-disable-dma"); + spi->ssp_enhancement = rt_dm_dev_prop_read_bool(dev, "k1x,ssp-enhancement"); + spi->slave_mode = rt_dm_dev_prop_read_bool(dev, "k1x,ssp-slave-mode"); + + if ((err = rt_dm_dev_prop_read_u32(dev, "k1x,ssp-clock-rate", &spi->max_speed_hz))) + { + goto _fail; + } + + spi->int_cr = INT_EN_TIE | INT_EN_RIE | INT_EN_TINTE; /* INT_EN */ + spi->dma_cr = spi->slave_mode ? INT_EN_TINTE : 0; + spi->clear_sr = STATUS_ROR | STATUS_TINT; + spi->mask_sr = STATUS_TINT | STATUS_RFS | STATUS_TFS | STATUS_ROR; + spi->dma_top_ctrl = DEFAULT_DMA_TOP_CTRL; + spi->dma_fifo_ctrl = DEFAULT_DMA_FIFO_CTRL; + + /* Setup DMA if requested */ + if (spi->enable_dma) + { + spi->tx_chan = rt_dma_chan_request(dev, "tx"); + + if (!rt_is_err_or_null(spi->tx_chan)) + { + spi->tx_chan->callback = k1x_spi_dma_callback; + + spi->tx_config.direction = RT_DMA_MEM_TO_DEV; + spi->tx_config.dst_addr = spi->ssdr_physical; + + spi->tx_transfer.dst_addr = spi->tx_config.dst_addr; + } + else + { + goto _fail; + } + + spi->rx_chan = rt_dma_chan_request(dev, "rx"); + + if (!rt_is_err_or_null(spi->rx_chan)) + { + spi->rx_chan->callback = k1x_spi_dma_callback; + + spi->rx_config.direction = RT_DMA_MEM_TO_DEV; + spi->rx_config.src_addr = spi->ssdr_physical; + + spi->rx_transfer.src_addr = spi->rx_config.src_addr; + } + else + { + goto _fail; + } + } + + rt_clk_set_rate(spi->clk, spi->max_speed_hz); + spi->max_speed_hz = rt_clk_get_rate(spi->clk); + + rt_clk_prepare_enable(spi->clk); + rt_reset_control_deassert(spi->rstc); + + bus_num = 0; + rt_dm_dev_prop_read_u32(dev, "k1x,ssp-id", &bus_num); + + if ((bus_num == 2 || bus_num == 3) && + rt_dm_dev_prop_read_bool(dev, "k1x,ssp-enable-clk-phase-adj")) + { + k1x_spi_write(spi, CLK_PHASE_ADJ, 0x1); + } + + /* Load default SSP configuration */ + k1x_spi_write(spi, TOP_CTRL, 0); + k1x_spi_write(spi, FIFO_CTRL, 0); + value = FIFO_RxTresh(RX_THRESH_DFLT) | FIFO_TxTresh(TX_THRESH_DFLT); + k1x_spi_write(spi, FIFO_CTRL, value); + value = TOP_FRF_Motorola | TOP_DSS(8); + k1x_spi_write(spi, TOP_CTRL, value); + k1x_spi_write(spi, TO, 0); + + k1x_spi_write(spi, PSP_CTRL, 0); + + rt_completion_init(&spi->cur_msg_completion); + + dev->user_data = spi; + + spi->parent.parent.ofw_node = dev->ofw_node; + + if (pdev->dev_id >= 0) + { + rt_dm_dev_set_name(&spi->parent.parent, "spi%u", pdev->dev_id); + } + else + { + if (bus_num >= 0) + { + rt_dm_dev_set_name(&spi->parent.parent, "spi%u", bus_num); + } + else + { + rt_dm_dev_set_name_auto(&spi->parent.parent, "spi"); + } + } + bus_name = rt_dm_dev_get_name(&spi->parent.parent); + + if (spi->slave_mode) + { + rt_timer_init(&spi->slave_rx_timer, bus_name, slave_rx_timer_expired, spi, + 0, RT_TIMER_FLAG_PERIODIC); + } + + rt_hw_interrupt_install(spi->irq, k1x_spi_spi_isr, spi, bus_name); + rt_hw_interrupt_umask(spi->irq); + + if ((err = rt_spi_bus_register(&spi->parent, bus_name, &k1x_spi_spi_ops))) + { + goto _free_irq; + } + + return RT_EOK; + +_free_irq: + rt_hw_interrupt_mask(spi->irq); + rt_pic_detach_irq(spi->irq, spi); + +_fail: + k1x_spi_free(spi, dev); + + return err; +} + +static rt_err_t k1x_spi_remove(struct rt_platform_device *pdev) +{ + struct rt_device *dev = &pdev->parent; + struct k1x_spi *spi = dev->user_data; + + rt_hw_interrupt_mask(spi->irq); + rt_pic_detach_irq(spi->irq, spi); + + rt_device_unregister(&spi->parent.parent); + + /* Disable the SSP at the peripheral and SOC level */ + k1x_spi_write(spi, TOP_CTRL, 0); + k1x_spi_write(spi, FIFO_CTRL, 0); + + k1x_spi_free(spi, dev); + + return RT_EOK; +} + +static const struct rt_ofw_node_id k1x_spi_ofw_ids[] = +{ + { .compatible = "spacemit,k1x-spi" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver k1x_spi_driver = +{ + .name = "k1x-spi", + .ids = k1x_spi_ofw_ids, + + .probe = k1x_spi_probe, + .remove = k1x_spi_remove, +}; +RT_PLATFORM_DRIVER_EXPORT(k1x_spi_driver); diff --git a/bsp/spacemit/dm/thermal/Kconfig b/bsp/spacemit/dm/thermal/Kconfig new file mode 100644 index 000000000000..38ce5540f8a6 --- /dev/null +++ b/bsp/spacemit/dm/thermal/Kconfig @@ -0,0 +1,3 @@ +config RT_THERMAL_K1X + bool "Spacemit K1X" + default n diff --git a/bsp/spacemit/dm/thermal/SConscript b/bsp/spacemit/dm/thermal/SConscript new file mode 100644 index 000000000000..78fbfcc7fa8e --- /dev/null +++ b/bsp/spacemit/dm/thermal/SConscript @@ -0,0 +1,13 @@ +from building import * + +group = [] +src = [] +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../include'] + +if GetDepend(['RT_THERMAL_K1X']): + src += ['thermal-k1x.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/spacemit/dm/thermal/thermal-k1x.c b/bsp/spacemit/dm/thermal/thermal-k1x.c new file mode 100644 index 000000000000..58344f7f9f43 --- /dev/null +++ b/bsp/spacemit/dm/thermal/thermal-k1x.c @@ -0,0 +1,484 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#include +#include +#include + +#define DBG_TAG "thermal.k1x" +#define DBG_LVL DBG_INFO +#include + +#define BITS(_start, _end) ((RT_BIT(_end) - RT_BIT(_start)) + RT_BIT(_end)) + +#define MAX_SENSOR_NUMBER 5 +#define TEMPERATURE_OFFSET 278 + +#define REG_TSEN_INT_MASK 0x14 +#define TSEN_EMERGENT_INT_OFFSET 23 +#define REG_EMERGENT_REBOOT_TEMP_THR 0x68 +#define REG_EMERGENT_REBOOT_TEMP_THR_MSK 0xffff + +#define REG_TSEN_TIME_CTRL 0x0c +#define BITS_TIME_CTRL_MASK BITS(0, 23) +#define VALUE_FILTER_PERIOD (0x3000 << 8) +#define BITS_RST_ADC_CNT BITS(4, 7) +#define VALUE_WAIT_REF_CNT (0xf << 0) + +#define BIT_TSEN_RAW_SEL RT_BIT(7) +#define BIT_TEMP_MODE RT_BIT(3) +#define BIT_EN_SENSOR RT_BIT(0) +#define BITS_TSEN_SW_CTRL BITS(18, 21) +#define BITS_CTUNE BITS(8, 11) +#define REG_TSEN_PCTRL 0x00 + +#define REG_TSEN_PCTRL2 0x04 +#define BITS_SDM_CLK_SEL BITS(14, 15) +#define BITS_SDM_CLK_SEL_24M (0 << 14) + +#define TSEN_INT_MASK RT_BIT(0) +#define BIT_HW_AUTO_MODE RT_BIT(23) + +#define MAX_SENSOR_NUMBER 5 + +struct sensor_enable +{ + rt_uint32_t bjt_en; + rt_uint32_t offset; + rt_uint32_t bit_msk; + rt_uint32_t en_val; +}; + +struct sensor_data +{ + rt_uint32_t data_reg; + rt_uint32_t offset; + rt_uint32_t bit_msk; +}; + +struct sensor_thrsh +{ + rt_uint32_t temp_thrsh; + rt_uint32_t low_offset; + rt_uint32_t high_offset; +}; + +struct k1x_thermal_sensor_desc +{ + rt_uint32_t int_msk; + rt_uint32_t int_clr; + rt_uint32_t int_sta; + rt_uint32_t offset; + rt_uint32_t bit_msk; + struct sensor_enable se; + struct sensor_data sd; + struct sensor_thrsh sr; +}; + +struct k1x_thermal; + +struct k1x_thermal_sensor +{ + struct rt_thermal_zone_device parent; + + void *regs; + struct k1x_thermal_sensor_desc *desc; +}; + +#define raw_to_k1x_thermal_sensor(raw) rt_container_of(raw, struct k1x_thermal_sensor, parent) + +struct k1x_thermal +{ + int irq; + void *regs; + struct rt_clk *clk; + struct rt_reset_control *rstc; + + /* Sensor range */ + rt_uint32_t sr[2]; + struct k1x_thermal_sensor *sensors; +}; + +static rt_err_t k1x_thermal_get_temp(struct rt_thermal_zone_device *zdev, int *out_temp) +{ + struct k1x_thermal_sensor *sensor = raw_to_k1x_thermal_sensor(zdev); + struct k1x_thermal_sensor_desc *desc = sensor->desc; + + *out_temp = HWREG32(sensor->regs + desc->sd.data_reg); + *out_temp &= desc->sd.bit_msk; + *out_temp >>= desc->sd.offset; + *out_temp -= TEMPERATURE_OFFSET; + *out_temp *= 1000; + + return RT_EOK; +} + +static rt_err_t k1x_thermal_set_trips(struct rt_thermal_zone_device *zdev, + int low_temp, int high_temp) +{ + rt_uint32_t temp; + int over_thrsh = high_temp, under_thrsh = low_temp; + struct k1x_thermal_sensor *sensor = raw_to_k1x_thermal_sensor(zdev); + struct k1x_thermal_sensor_desc *desc = sensor->desc; + + /* Set overflow */ + over_thrsh /= 1000; + over_thrsh += TEMPERATURE_OFFSET; + + temp = HWREG32(sensor->regs + desc->sr.temp_thrsh); + temp &= ~0xffff0000; + temp |= (over_thrsh << desc->sr.high_offset); + HWREG32(sensor->regs + desc->sr.temp_thrsh) = temp; + + /* set underflow */ + if (low_temp < 0) + { + under_thrsh = 0; + } + + under_thrsh /= 1000; + under_thrsh += TEMPERATURE_OFFSET; + temp = HWREG32(sensor->regs + desc->sr.temp_thrsh); + temp &= ~0xffff; + temp |= (under_thrsh << desc->sr.low_offset); + HWREG32(sensor->regs + desc->sr.temp_thrsh) = temp; + + return RT_EOK; +} + +static const struct rt_thermal_zone_ops k1x_thermal_ops = +{ + .get_temp = k1x_thermal_get_temp, + .set_trips = k1x_thermal_set_trips, +}; + +static void k1x_thermal_isr(int irqno, void *param) +{ + rt_uint32_t status, msk; + struct k1x_thermal_sensor *sensor = param; + struct k1x_thermal_sensor_desc *desc = sensor->desc; + + /* Get the status */ + status = HWREG32(sensor->regs + desc->int_sta); + status &= desc->bit_msk; + + if (!status) + { + return; + } + + /* Then clear the pending */ + msk = HWREG32(sensor->regs + desc->int_clr); + msk |= status; + HWREG32(sensor->regs + desc->int_clr) = msk; + + rt_thermal_zone_device_update(&sensor->parent, RT_THERMAL_MSG_EVENT_UNSPECIFIED); +} + +static rt_err_t init_sensors(struct rt_device *dev, struct k1x_thermal *thermal, + struct k1x_thermal_sensor_desc *desc) +{ + rt_err_t err; + rt_uint32_t temp; + + /* Read the sensor range */ + err = rt_dm_dev_prop_read_u32_array_index(dev, "sensor_range", 0, 2, thermal->sr); + if (err < 0) + { + LOG_E("Get sensor range error"); + return err; + } + + if (thermal->sr[1] >= MAX_SENSOR_NUMBER) + { + LOG_E("Un-fitable sensor range"); + return -RT_EINVAL; + } + + /* First: disable all the interrupts */ + HWREG32(thermal->regs + REG_TSEN_INT_MASK) = 0xffffffff; + + /* + * Decrease filter period time from 0x4000 to 0x3000, that + * means decrease 1/4 ADC sampling time for each sensor. + */ + temp = HWREG32(thermal->regs + REG_TSEN_TIME_CTRL); + temp &= ~BITS_TIME_CTRL_MASK; + temp |= VALUE_FILTER_PERIOD; + temp |= BITS_RST_ADC_CNT; + temp |= VALUE_WAIT_REF_CNT; + HWREG32(thermal->regs + REG_TSEN_TIME_CTRL) = temp; + + /* + * Enable all sensors' auto mode, enable dither control, + * consecutive mode, and power up sensor. + */ + temp = HWREG32(thermal->regs + REG_TSEN_PCTRL); + temp |= BIT_TSEN_RAW_SEL | BIT_TEMP_MODE | BIT_EN_SENSOR; + temp &= ~BITS_TSEN_SW_CTRL; + temp &= ~BITS_CTUNE; + HWREG32(thermal->regs + REG_TSEN_PCTRL) = temp; + + /* Select 24M clk for high speed mode */ + temp = HWREG32(thermal->regs + REG_TSEN_PCTRL2); + temp &= ~BITS_SDM_CLK_SEL; + temp |= BITS_SDM_CLK_SEL_24M; + HWREG32(thermal->regs + REG_TSEN_PCTRL2) = temp; + + /* Enable the sensor interrupt */ + for (int i = thermal->sr[0]; i <= thermal->sr[1]; ++i) + { + struct sensor_enable *se = &desc[i].se; + + temp = HWREG32(thermal->regs + se->bjt_en); + temp &= ~se->bit_msk; + temp |= se->en_val << se->offset; + HWREG32(thermal->regs + se->bjt_en) = temp; + } + + return 0; +} + +static void enable_sensors(struct k1x_thermal *thermal) +{ + HWREG32(thermal->regs + REG_TSEN_INT_MASK) = + HWREG32(thermal->regs + REG_TSEN_INT_MASK) | TSEN_INT_MASK; + HWREG32(thermal->regs + REG_TSEN_PCTRL) = + HWREG32(thermal->regs + REG_TSEN_PCTRL) | BIT_HW_AUTO_MODE; +} + +static void enable_sensor_irq(struct k1x_thermal_sensor *sensor) +{ + rt_uint32_t temp; + struct k1x_thermal_sensor_desc *desc = sensor->desc; + + /* Clear the interrupt */ + temp = HWREG32(sensor->regs + desc->int_clr); + temp |= desc->bit_msk; + HWREG32(sensor->regs + desc->int_clr) = temp; + + /* Enable the interrupt */ + temp = HWREG32(sensor->regs + desc->int_msk); + temp &= ~desc->bit_msk; + HWREG32(sensor->regs + desc->int_msk) = temp; +} + +static void k1x_thermal_free(struct k1x_thermal *thermal) +{ + if (thermal->regs) + { + rt_iounmap(thermal->regs); + } + + if (!rt_is_err_or_null(thermal->clk)) + { + rt_clk_disable_unprepare(thermal->clk); + rt_clk_put(thermal->clk); + } + + if (!rt_is_err_or_null(thermal->rstc)) + { + rt_reset_control_assert(thermal->rstc); + rt_reset_control_put(thermal->rstc); + } + + if (thermal->sensors) + { + rt_free(thermal->sensors); + } + + rt_free(thermal); +} + +static rt_err_t k1x_thermal_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + struct rt_device *dev = &pdev->parent; + struct k1x_thermal *thermal; + struct k1x_thermal_sensor_desc *desc = (void *)pdev->id->data; + + if (!desc) + { + return -RT_EINVAL; + } + + if (!(thermal = rt_calloc(1, sizeof(*thermal)))) + { + return -RT_ENOMEM; + } + + thermal->regs = rt_dm_dev_iomap(dev, 0); + if (!thermal->regs) + { + err = -RT_EINVAL; + goto _fail; + } + + thermal->irq = rt_dm_dev_get_irq(dev, 0); + if (thermal->irq < 0) + { + err = thermal->irq; + goto _fail; + } + + thermal->rstc = rt_reset_control_get_by_index(dev, 0); + if (rt_is_err(thermal->rstc)) + { + err = rt_ptr_err(thermal->rstc); + goto _fail; + } + + rt_reset_control_deassert(thermal->rstc); + + thermal->clk = rt_clk_get_by_index(dev, 0); + if (rt_is_err(thermal->clk)) + { + err = rt_ptr_err(thermal->clk); + goto _fail; + } + + rt_clk_prepare_enable(thermal->clk); + + /* Initialize the sensors */ + if ((err = init_sensors(dev, thermal, desc))) + { + goto _fail; + } + + thermal->sensors = rt_calloc(thermal->sr[1] - thermal->sr[0] + 1, sizeof(*thermal->sensors)); + if (!thermal->sensors) + { + err = -RT_ENOMEM; + goto _fail; + } + + /* Then register the thermal zone */ + for (int i = thermal->sr[0]; i <= thermal->sr[1]; ++i) + { + struct k1x_thermal_sensor *sensor; + struct rt_thermal_zone_device *tz; + + sensor = &thermal->sensors[i - thermal->sr[0]]; + sensor->regs = thermal->regs; + sensor->desc = &desc[i]; + + tz = &sensor->parent; + tz->ops = &k1x_thermal_ops; + tz->parent.ofw_node = dev->ofw_node; + + rt_dm_dev_set_name(&tz->parent, "tk1x-tz-%d", i); + rt_thermal_zone_device_register(tz); + + rt_hw_interrupt_install(thermal->irq, k1x_thermal_isr, sensor, + rt_dm_dev_get_name(&tz->parent)); + + /* Enable sensor low & higth threshold interrupt */ + enable_sensor_irq(sensor); + } + + /* Enable the sensor interrupt & using auto mode */ + enable_sensors(thermal); + + rt_hw_interrupt_umask(thermal->irq); + + dev->user_data = thermal; + + return RT_EOK; + +_fail: + k1x_thermal_free(thermal); + + return err; +} + +static rt_err_t k1x_thermal_remove(struct rt_platform_device *pdev) +{ + struct k1x_thermal *thermal = pdev->parent.user_data; + + rt_hw_interrupt_mask(thermal->irq); + + for (int i = thermal->sr[0]; i <= thermal->sr[1]; ++i) + { + struct k1x_thermal_sensor *sensor; + + sensor = &thermal->sensors[i - thermal->sr[0]]; + + rt_pic_detach_irq(thermal->irq, sensor); + rt_thermal_zone_device_unregister(&sensor->parent); + } + + k1x_thermal_free(thermal); + + return RT_EOK; +} + +static struct k1x_thermal_sensor_desc gsdesc[] = +{ + /* bjt0: local, sensor internal temperature */ + [0] = + { + .int_msk = 0x14, .int_clr = 0x10, .int_sta = 0x18, .offset = 0x0, .bit_msk = 0x6, + .se = { .bjt_en = 0x8, .en_val = 0x1, .offset = 0x0, .bit_msk = 0x1, }, + .sd = { .data_reg = 0x20, .offset = 0x0, .bit_msk = 0xffff, }, + .sr = { .temp_thrsh = 0x40, .low_offset = 0x0, .high_offset = 16, }, + }, + + /* bjt1: top */ + [1] = + { + .int_msk = 0x14, .int_clr = 0x10, .int_sta = 0x18, .offset = 0x3, .bit_msk = 0x18, + .se = { .bjt_en = 0x8, .en_val = 0x1, .offset = 0x1, .bit_msk = 0x2, }, + .sd = { .data_reg = 0x20, .offset = 16, .bit_msk = 0xffff0000, }, + .sr = { .temp_thrsh = 0x44, .low_offset = 0x0, .high_offset = 16, }, + }, + + /* bjt2: gpu */ + [2] = + { + .int_msk = 0x14, .int_clr = 0x10, .int_sta = 0x18, .offset = 0x5, .bit_msk = 0x60, + .se = { .bjt_en = 0x8, .en_val = 0x1, .offset = 0x2, .bit_msk = 0x4, }, + .sd = { .data_reg = 0x24, .offset = 0, .bit_msk = 0xffff, }, + .sr = { .temp_thrsh = 0x48, .low_offset = 0x0, .high_offset = 16, }, + }, + + /* bjt3: cluster0 */ + [3] = + { + .int_msk = 0x14, .int_clr = 0x10, .int_sta = 0x18, .offset = 0x7, .bit_msk = 0x180, + .se = { .bjt_en = 0x8, .en_val = 0x1, .offset = 0x3, .bit_msk = 0x8, }, + .sd = { .data_reg = 0x24, .offset = 16, .bit_msk = 0xffff0000, }, + .sr = { .temp_thrsh = 0x4c, .low_offset = 0x0, .high_offset = 16, }, + }, + + /* bjt4: cluster1 */ + [4] = + { + .int_msk = 0x14, .int_clr = 0x10, .int_sta = 0x18, .offset = 0x9, .bit_msk = 0x600, + .se = { .bjt_en = 0x8, .en_val = 0x1, .offset = 0x4, .bit_msk = 0x10, }, + .sd = { .data_reg = 0x28, .offset = 0, .bit_msk = 0xffff, }, + .sr = { .temp_thrsh = 0x50, .low_offset = 0x0, .high_offset = 16, }, + }, +}; + +static const struct rt_ofw_node_id k1x_thermal_ofw_ids[] = +{ + { .compatible = "spacemit,k1x-tsensor", .data = gsdesc, }, + { /* sentinel */ } +}; + +static struct rt_platform_driver k1x_thermal_driver = +{ + .name = "k1x-thermal", + .ids = k1x_thermal_ofw_ids, + + .probe = k1x_thermal_probe, + .remove = k1x_thermal_remove, +}; +RT_PLATFORM_DRIVER_EXPORT(k1x_thermal_driver); diff --git a/bsp/spacemit/dm/watchdog/Kconfig b/bsp/spacemit/dm/watchdog/Kconfig new file mode 100644 index 000000000000..e84991358e42 --- /dev/null +++ b/bsp/spacemit/dm/watchdog/Kconfig @@ -0,0 +1,3 @@ +config RT_WDT_SPACEMIT_WATCHDOG + bool "Spacemit-k1x SoC Watchdog" + default n diff --git a/bsp/spacemit/dm/watchdog/SConscript b/bsp/spacemit/dm/watchdog/SConscript new file mode 100644 index 000000000000..5b3ece5b2e24 --- /dev/null +++ b/bsp/spacemit/dm/watchdog/SConscript @@ -0,0 +1,13 @@ +from building import * + +group = [] +src = [] +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../include'] + +if GetDepend(['RT_WDT_SPACEMIT_WATCHDOG']): + src += ['watchdog-k1x.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/spacemit/dm/watchdog/watchdog-k1x.c b/bsp/spacemit/dm/watchdog/watchdog-k1x.c new file mode 100644 index 000000000000..a0a7b519d2ed --- /dev/null +++ b/bsp/spacemit/dm/watchdog/watchdog-k1x.c @@ -0,0 +1,470 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#include +#include + +#define DBG_TAG "wdt.k1x" +#define DBG_LVL DBG_INFO +#include + +/* Watchdog Timer Registers Offset */ +#define WDT_WMER 0x00b8 +#define WDT_WMR 0x00bc +#define WDT_WVR 0x00cc +#define WDT_WCR 0x00c8 +#define WDT_WSR 0x00c0 +#define WDT_WFAR 0x00b0 +#define WDT_WSAR 0x00b4 +#define WDT_WICR 0x00c4 + +/* Default timeout is 60s */ +#define SPACEMIT_WATCHDOG_MAX_TIMEOUT 255 +#define SPACEMIT_WATCHDOG_EXPIRE_TIME 100 +/* Touch watchdog every 30s */ +#define SPACEMIT_WATCHDOG_FEED_TIMEOUT 30 + +#define MPMU_APRR 0x1020 +#define MPMU_APRR_WDTR RT_BIT(4) +#define DEFAULT_SHIFT 8 +/* + * MPMU_APSR is a dummy reg which is used to handle reboot + * cmds. Its layout is: + * bit0~7: untouchable + * bit8~11: set to 0x1 when normal boot with no parameter + * set to 0x5 for other valid cmds. + */ +#define MPMU_ARSR 0x1028 +#define MPMU_ARSR_REBOOT_CMD(x) ((x) << 8) +#define MPMU_ARSR_SWR_MASK (0xf << 8) +#define REBOOT_CMD_NORMAL 0x1 +#define REBOOT_CMD_VALID 0x5 + +struct spa_wdt +{ + rt_watchdog_t parent; + + void *wdt_base; + void *mpmu_base; + + struct rt_clk *clk; + struct rt_reset_control *rstc; + + rt_uint32_t timeout; + + rt_bool_t ctrl; + rt_bool_t wdt_clk_open; + rt_bool_t enable_restart_handler; + + struct rt_spinlock wdt_lock; +}; + +#define raw_to_spa_wdt(raw) rt_container_of(raw, struct spa_wdt, parent) + +rt_inline rt_uint32_t spa_wdt_read(struct spa_wdt *swdt, unsigned reg) +{ + return HWREG32(swdt->wdt_base + reg); +} + +rt_inline void spa_wdt_write_access(struct spa_wdt *swdt) +{ + HWREG32(swdt->wdt_base + WDT_WFAR) = 0xbaba; + HWREG32(swdt->wdt_base + WDT_WSAR) = 0xeb10; +} + +rt_inline void spa_wdt_write(struct spa_wdt *swdt, unsigned reg, rt_uint32_t val) +{ + spa_wdt_write_access(swdt); + HWREG32(swdt->wdt_base + reg) = val; +} + +static rt_err_t spa_wdt_set_timeout(struct spa_wdt *swdt, unsigned timeout) +{ + /* + * the wdt timer is 16 bit, + * frequence is 256HZ + */ + unsigned int tick = timeout << DEFAULT_SHIFT; + + if ((long long)tick > 0xffff) + { + timeout = SPACEMIT_WATCHDOG_MAX_TIMEOUT; + tick = timeout << DEFAULT_SHIFT; + } + + spa_wdt_write(swdt, WDT_WMR, tick); + + swdt->timeout = timeout; + + return RT_EOK; +} + +static void spa_enable_wdt_clk(struct spa_wdt *swdt) +{ + rt_spin_lock(&swdt->wdt_lock); + + if (!swdt->wdt_clk_open) + { + rt_clk_prepare_enable(swdt->clk); + rt_reset_control_deassert(swdt->rstc); + swdt->wdt_clk_open = RT_TRUE; + } + + rt_spin_unlock(&swdt->wdt_lock); +} + +static void spa_disable_wdt_clk(struct spa_wdt *swdt) +{ + rt_spin_lock(&swdt->wdt_lock); + + if (swdt->wdt_clk_open) + { + rt_clk_disable_unprepare(swdt->clk); + rt_reset_control_assert(swdt->rstc); + swdt->wdt_clk_open = RT_FALSE; + } + + rt_spin_unlock(&swdt->wdt_lock); +} + +static rt_err_t spa_wdt_stop(struct spa_wdt *swdt) +{ + rt_spin_lock(&swdt->wdt_lock); + + /* Reset counter */ + spa_wdt_write(swdt, WDT_WCR, 0x1); + + /* Disable WDT */ + spa_wdt_write(swdt, WDT_WMER, 0x0); + + swdt->ctrl = RT_FALSE; + + rt_spin_unlock(&swdt->wdt_lock); + + rt_thread_mdelay(3); + + spa_disable_wdt_clk(swdt); + + return RT_EOK; +} + +static rt_err_t spa_wdt_start(struct spa_wdt *swdt) +{ + void *mpmu_aprr; + rt_uint32_t reg; + + spa_enable_wdt_clk(swdt); + + rt_spin_lock(&swdt->wdt_lock); + + /* Set timeout = 100s */ + spa_wdt_set_timeout(swdt, SPACEMIT_WATCHDOG_EXPIRE_TIME); + + /* Enable counter and rstc/interrupt */ + spa_wdt_write(swdt, WDT_WMER, 0x3); + + /* Negate hardware rstc to the WDT after system rstc */ + mpmu_aprr = swdt->mpmu_base + MPMU_APRR; + reg = HWREG32(mpmu_aprr); + reg |= MPMU_APRR_WDTR; + HWREG32(mpmu_aprr) = reg; + + /* Clear previous WDT status */ + spa_wdt_write(swdt, WDT_WSR, 0x0); + + swdt->ctrl = RT_TRUE; + + rt_spin_unlock(&swdt->wdt_lock); + + return RT_EOK; +} + +static rt_err_t spa_wdt_ping(struct spa_wdt *swdt) +{ + rt_spin_lock(&swdt->wdt_lock); + + spa_wdt_write(swdt, WDT_WCR, 0x1); + + rt_spin_unlock(&swdt->wdt_lock); + + return RT_EOK; +} + +static rt_err_t spa_wdt_init(rt_watchdog_t *wdt) +{ + return RT_EOK; +} + +static rt_err_t spa_wdt_control(rt_watchdog_t *wdt, int cmd, void *args) +{ + rt_err_t err = RT_EOK; + struct spa_wdt *swdt = raw_to_spa_wdt(wdt); + + switch (cmd) + { + case RT_DEVICE_CTRL_WDT_GET_TIMEOUT: + *(rt_uint32_t *)args = swdt->timeout; + break; + + case RT_DEVICE_CTRL_WDT_SET_TIMEOUT: + spa_wdt_set_timeout(swdt, *(rt_uint32_t *)args); + break; + + case RT_DEVICE_CTRL_WDT_GET_TIMELEFT: + err = -RT_ENOSYS; + break; + + case RT_DEVICE_CTRL_WDT_KEEPALIVE: + spa_wdt_ping(swdt); + break; + + case RT_DEVICE_CTRL_WDT_START: + spa_wdt_start(swdt); + break; + + case RT_DEVICE_CTRL_WDT_STOP: + spa_wdt_stop(swdt); + break; + + default: + err = -RT_EINVAL; + } + + return err; +} + +static const struct rt_watchdog_ops spa_wdt_ops = +{ + .init = spa_wdt_init, + .control = spa_wdt_control, +}; + +static rt_err_t spa_wdt_restart_handler(struct rt_device *dev, char *cmd) +{ + rt_uint32_t reg; + void *mpmu_arsr, *mpmu_aprr; + rt_watchdog_t *wdt = rt_container_of(dev, rt_watchdog_t, parent); + struct spa_wdt *swdt = raw_to_spa_wdt(wdt); + + rt_hw_spin_lock(&swdt->wdt_lock.lock); + + mpmu_arsr = swdt->mpmu_base + MPMU_ARSR; + reg = HWREG32(mpmu_arsr); + reg &= ~MPMU_ARSR_SWR_MASK; + + if (!cmd) + { + reg |= MPMU_ARSR_REBOOT_CMD(REBOOT_CMD_NORMAL); + } + else + { + reg |= MPMU_ARSR_REBOOT_CMD(REBOOT_CMD_VALID); + } + + HWREG32(mpmu_arsr) = reg; + + spa_enable_wdt_clk(swdt); + + spa_wdt_write(swdt, WDT_WSR, 0x0); + spa_wdt_write(swdt, WDT_WMR, 0x1); + spa_wdt_write(swdt, WDT_WMER, 0x3); + spa_wdt_write(swdt, WDT_WCR, 0x1); + + mpmu_aprr = swdt->mpmu_base + MPMU_APRR; + reg = HWREG32(mpmu_aprr); + reg |= MPMU_APRR_WDTR; + HWREG32(mpmu_aprr) = reg; + + rt_thread_mdelay(5000); + + rt_hw_spin_unlock(&swdt->wdt_lock.lock); + + return RT_EOK; +} + +#ifdef RT_USING_PM +static rt_err_t spa_wdt_pm_suspend(const struct rt_device *device, rt_uint8_t mode) +{ + rt_watchdog_t *wdt = rt_container_of(device, rt_watchdog_t, parent); + struct spa_wdt *swdt = raw_to_spa_wdt(wdt); + + if (swdt->ctrl) + { + spa_wdt_stop(swdt); + } + + return RT_EOK; +} + +static void spa_wdt_pm_resume(const struct rt_device *device, rt_uint8_t mode) +{ + rt_watchdog_t *wdt = rt_container_of(device, rt_watchdog_t, parent); + struct spa_wdt *swdt = raw_to_spa_wdt(wdt); + + if (swdt->ctrl) + { + spa_wdt_start(swdt); + } +} + +static const struct rt_device_pm_ops spa_wdt_pm_ops = +{ + .suspend = spa_wdt_pm_suspend, + .resume = spa_wdt_pm_resume, +}; +#endif /* RT_USING_PM */ + +static void spa_wdt_free(struct spa_wdt *swdt) +{ + if (swdt->ctrl) + { + spa_wdt_stop(swdt); + } + + spa_disable_wdt_clk(swdt); + + if (!rt_is_err_or_null(swdt->clk)) + { + rt_clk_put(swdt->clk); + } + + if (!rt_is_err_or_null(swdt->rstc)) + { + rt_reset_control_put(swdt->rstc); + } +} + +static rt_err_t spa_wdt_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + void *mpmu_arsr; + const char *dev_name; + struct rt_device *dev = &pdev->parent; + struct spa_wdt *swdt = rt_calloc(1, sizeof(*swdt)); + + if (!swdt) + { + return -RT_ENOMEM; + } + + if (!(swdt->wdt_base = rt_dm_dev_iomap(dev, 0))) + { + err = -RT_EIO; + goto _fail; + } + + if (!(swdt->mpmu_base = rt_dm_dev_iomap(dev, 1))) + { + err = -RT_EIO; + goto _fail; + } + + mpmu_arsr = swdt->mpmu_base + MPMU_ARSR; + HWREG32(mpmu_arsr) = HWREG32(mpmu_arsr) & ~MPMU_ARSR_SWR_MASK; + + swdt->clk = rt_clk_get_by_index(dev, 0); + if (rt_is_err(swdt->clk)) + { + err = rt_ptr_err(swdt->clk); + goto _fail; + } + + swdt->rstc = rt_reset_control_get_by_index(dev, 0); + if (rt_is_err(swdt->rstc)) + { + err = rt_ptr_err(swdt->rstc); + goto _fail; + } + + swdt->enable_restart_handler = rt_dm_dev_prop_read_bool(dev, "spa,wdt-enable-restart-handler"); + + /* + * The writing of some WDT registers must be + * under the condition of that WDT clock is on + */ + spa_enable_wdt_clk(swdt); + + rt_spin_lock_init(&swdt->wdt_lock); + + dev->user_data = swdt; + + swdt->parent.ops = &spa_wdt_ops; + + rt_dm_dev_set_name_auto(&swdt->parent.parent, "wdt"); + dev_name = rt_dm_dev_get_name(&swdt->parent.parent); + + if ((err = rt_hw_watchdog_register(&swdt->parent, dev_name, 0, swdt))) + { + goto _fail; + } + +#ifdef RT_USING_PM + rt_pm_device_register(&swdt->parent.parent, &spa_wdt_pm_ops); +#endif + + if (swdt->enable_restart_handler) + { + rt_dm_reboot_mode_register(&swdt->parent.parent, spa_wdt_restart_handler); + } + + return RT_EOK; + +_fail: + spa_wdt_free(swdt); + + return err; +} + +static rt_err_t spa_wdt_remove(struct rt_platform_device *pdev) +{ + struct spa_wdt *swdt = pdev->parent.user_data; + +#ifdef RT_USING_PM + rt_pm_device_unregister(&swdt->parent.parent); +#endif + + rt_device_unregister(&swdt->parent.parent); + + spa_wdt_free(swdt); + + return RT_EOK; +} + +static rt_err_t spa_wdt_shutdown(struct rt_platform_device *pdev) +{ + struct spa_wdt *swdt = pdev->parent.user_data; + + spa_wdt_stop(swdt); + + /* No need to disable clk if enable restart_handler */ + if (swdt->enable_restart_handler) + { + spa_enable_wdt_clk(swdt); + } + + return RT_EOK; +} + +static const struct rt_ofw_node_id spa_wdt_ofw_ids[] = +{ + { .compatible = "spacemit,soc-wdt" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver spa_wdt_driver = +{ + .name = "spa-wdt", + .ids = spa_wdt_ofw_ids, + + .probe = spa_wdt_probe, + .remove = spa_wdt_remove, + .shutdown = spa_wdt_shutdown, +}; +RT_PLATFORM_DRIVER_EXPORT(spa_wdt_driver); diff --git a/bsp/spacemit/k1/.config b/bsp/spacemit/k1/.config new file mode 100644 index 000000000000..7ea65bc39455 --- /dev/null +++ b/bsp/spacemit/k1/.config @@ -0,0 +1,1927 @@ + +# +# RT-Thread Kernel +# + +# +# klibc options +# + +# +# rt_vsnprintf options +# +# CONFIG_RT_KLIBC_USING_LIBC_VSNPRINTF is not set +# CONFIG_RT_KLIBC_USING_VSNPRINTF_LONGLONG is not set +# CONFIG_RT_KLIBC_USING_VSNPRINTF_STANDARD is not set +# end of rt_vsnprintf options + +# +# rt_vsscanf options +# +# CONFIG_RT_KLIBC_USING_LIBC_VSSCANF is not set +# end of rt_vsscanf options + +# +# rt_memset options +# +# CONFIG_RT_KLIBC_USING_USER_MEMSET is not set +# CONFIG_RT_KLIBC_USING_LIBC_MEMSET is not set +# CONFIG_RT_KLIBC_USING_TINY_MEMSET is not set +# end of rt_memset options + +# +# rt_memcpy options +# +# CONFIG_RT_KLIBC_USING_USER_MEMCPY is not set +# CONFIG_RT_KLIBC_USING_LIBC_MEMCPY is not set +# CONFIG_RT_KLIBC_USING_TINY_MEMCPY is not set +# end of rt_memcpy options + +# +# rt_memmove options +# +# CONFIG_RT_KLIBC_USING_USER_MEMMOVE is not set +# CONFIG_RT_KLIBC_USING_LIBC_MEMMOVE is not set +# end of rt_memmove options + +# +# rt_memcmp options +# +# CONFIG_RT_KLIBC_USING_USER_MEMCMP is not set +# CONFIG_RT_KLIBC_USING_LIBC_MEMCMP is not set +# end of rt_memcmp options + +# +# rt_strstr options +# +# CONFIG_RT_KLIBC_USING_USER_STRSTR is not set +# CONFIG_RT_KLIBC_USING_LIBC_STRSTR is not set +# end of rt_strstr options + +# +# rt_strcasecmp options +# +# CONFIG_RT_KLIBC_USING_USER_STRCASECMP is not set +# end of rt_strcasecmp options + +# +# rt_strncpy options +# +# CONFIG_RT_KLIBC_USING_USER_STRNCPY is not set +# CONFIG_RT_KLIBC_USING_LIBC_STRNCPY is not set +# end of rt_strncpy options + +# +# rt_strcpy options +# +# CONFIG_RT_KLIBC_USING_USER_STRCPY is not set +# CONFIG_RT_KLIBC_USING_LIBC_STRCPY is not set +# end of rt_strcpy options + +# +# rt_strncmp options +# +# CONFIG_RT_KLIBC_USING_USER_STRNCMP is not set +# CONFIG_RT_KLIBC_USING_LIBC_STRNCMP is not set +# end of rt_strncmp options + +# +# rt_strcmp options +# +# CONFIG_RT_KLIBC_USING_USER_STRCMP is not set +# CONFIG_RT_KLIBC_USING_LIBC_STRCMP is not set +# end of rt_strcmp options + +# +# rt_strlen options +# +# CONFIG_RT_KLIBC_USING_USER_STRLEN is not set +# CONFIG_RT_KLIBC_USING_LIBC_STRLEN is not set +# end of rt_strlen options + +# +# rt_strnlen options +# +# CONFIG_RT_KLIBC_USING_USER_STRNLEN is not set +# end of rt_strnlen options +# end of klibc options + +CONFIG_RT_NAME_MAX=24 +# CONFIG_RT_USING_ARCH_DATA_TYPE is not set +# CONFIG_RT_USING_NANO is not set +# CONFIG_RT_USING_SMART is not set +# CONFIG_RT_USING_AMP is not set +CONFIG_RT_USING_SMP=y +CONFIG_RT_CPUS_NR=4 +CONFIG_RT_ALIGN_SIZE=8 +# CONFIG_RT_THREAD_PRIORITY_8 is not set +CONFIG_RT_THREAD_PRIORITY_32=y +# CONFIG_RT_THREAD_PRIORITY_256 is not set +CONFIG_RT_THREAD_PRIORITY_MAX=32 +CONFIG_RT_TICK_PER_SECOND=100 +CONFIG_RT_USING_OVERFLOW_CHECK=y +CONFIG_RT_USING_HOOK=y +CONFIG_RT_HOOK_USING_FUNC_PTR=y +# CONFIG_RT_USING_HOOKLIST is not set +CONFIG_RT_USING_IDLE_HOOK=y +CONFIG_RT_IDLE_HOOK_LIST_SIZE=4 +CONFIG_IDLE_THREAD_STACK_SIZE=16384 +CONFIG_SYSTEM_THREAD_STACK_SIZE=16384 +CONFIG_RT_USING_TIMER_SOFT=y +CONFIG_RT_TIMER_THREAD_PRIO=4 +CONFIG_RT_TIMER_THREAD_STACK_SIZE=16384 +# CONFIG_RT_USING_TIMER_ALL_SOFT is not set +CONFIG_RT_USING_CPU_USAGE_TRACER=y +CONFIG_RT_CPU_USAGE_CALC_INTERVAL_MS=200 + +# +# kservice options +# +# CONFIG_RT_USING_TINY_FFS is not set +# end of kservice options + +CONFIG_RT_USING_DEBUG=y +CONFIG_RT_DEBUGING_ASSERT=y +CONFIG_RT_DEBUGING_COLOR=y +CONFIG_RT_DEBUGING_CONTEXT=y +# CONFIG_RT_DEBUGING_AUTO_INIT is not set +# CONFIG_RT_DEBUGING_SPINLOCK is not set +# CONFIG_RT_DEBUGING_CRITICAL is not set +# CONFIG_RT_USING_CI_ACTION is not set + +# +# Inter-Thread communication +# +CONFIG_RT_USING_SEMAPHORE=y +CONFIG_RT_USING_MUTEX=y +CONFIG_RT_USING_EVENT=y +CONFIG_RT_USING_MAILBOX=y +CONFIG_RT_USING_MESSAGEQUEUE=y +# CONFIG_RT_USING_MESSAGEQUEUE_PRIORITY is not set +CONFIG_RT_USING_SIGNALS=y +# end of Inter-Thread communication + +# +# Memory Management +# +CONFIG_RT_USING_MEMPOOL=y +# CONFIG_RT_USING_SMALL_MEM is not set +CONFIG_RT_USING_SLAB=y +CONFIG_RT_USING_MEMHEAP=y +CONFIG_RT_MEMHEAP_FAST_MODE=y +# CONFIG_RT_MEMHEAP_BEST_MODE is not set +# CONFIG_RT_USING_SMALL_MEM_AS_HEAP is not set +# CONFIG_RT_USING_MEMHEAP_AS_HEAP is not set +CONFIG_RT_USING_SLAB_AS_HEAP=y +# CONFIG_RT_USING_USERHEAP is not set +# CONFIG_RT_USING_NOHEAP is not set +CONFIG_RT_USING_MEMTRACE=y +# CONFIG_RT_USING_HEAP_ISR is not set +CONFIG_RT_USING_HEAP=y +# end of Memory Management + +CONFIG_RT_USING_DEVICE=y +CONFIG_RT_USING_DEVICE_OPS=y +CONFIG_RT_USING_INTERRUPT_INFO=y +# CONFIG_RT_USING_THREADSAFE_PRINTF is not set +CONFIG_RT_USING_CONSOLE=y +CONFIG_RT_CONSOLEBUF_SIZE=256 +CONFIG_RT_CONSOLE_DEVICE_NAME="uart0" +CONFIG_RT_USING_CONSOLE_OUTPUT_CTL=y +CONFIG_RT_VER_NUM=0x50300 +CONFIG_RT_USING_STDC_ATOMIC=y +CONFIG_RT_BACKTRACE_LEVEL_MAX_NR=32 +# end of RT-Thread Kernel + +CONFIG_ARCH_TEXT_OFFSET=0x200000 +CONFIG_ARCH_RAM_OFFSET=0 +CONFIG_ARCH_SECONDARY_CPU_STACK_SIZE=4096 +CONFIG_ARCH_HEAP_SIZE=0x4000000 +CONFIG_ARCH_INIT_PAGE_SIZE=0x200000 +CONFIG_ARCH_CPU_64BIT=y +CONFIG_RT_USING_CACHE=y +CONFIG_RT_USING_HW_ATOMIC=y +CONFIG_RT_USING_CPU_FFS=y +CONFIG_ARCH_MM_MMU=y +CONFIG_ARCH_RISCV=y +CONFIG_ARCH_RISCV_FPU=y +CONFIG_ARCH_RISCV_FPU_D=y +CONFIG_ARCH_RISCV64=y + +# +# RISC-V Architecture Configuration +# +CONFIG_RT_USING_RISCV_NEW_COMMON=y +# CONFIG_ARCH_RISCV_USING_IRQ_STACK is not set +# CONFIG_RT_USING_USERSPACE_32BIT_LIMIT is not set +# end of RISC-V Architecture Configuration + +CONFIG_ARCH_USING_NEW_CTX_SWITCH=y + +# +# RT-Thread Components +# +CONFIG_RT_USING_COMPONENTS_INIT=y +CONFIG_RT_USING_USER_MAIN=y +CONFIG_RT_MAIN_THREAD_STACK_SIZE=16384 +CONFIG_RT_MAIN_THREAD_PRIORITY=10 +# CONFIG_RT_USING_LEGACY is not set +CONFIG_RT_USING_MSH=y +CONFIG_RT_USING_FINSH=y +CONFIG_FINSH_USING_MSH=y +CONFIG_FINSH_THREAD_NAME="tshell" +CONFIG_FINSH_THREAD_PRIORITY=20 +CONFIG_FINSH_THREAD_STACK_SIZE=16384 +CONFIG_FINSH_USING_HISTORY=y +CONFIG_FINSH_HISTORY_LINES=10 +# CONFIG_FINSH_USING_WORD_OPERATION is not set +# CONFIG_FINSH_USING_FUNC_EXT is not set +CONFIG_FINSH_USING_SYMTAB=y +CONFIG_FINSH_CMD_SIZE=80 +CONFIG_MSH_USING_BUILT_IN_COMMANDS=y +CONFIG_FINSH_USING_DESCRIPTION=y +# CONFIG_FINSH_ECHO_DISABLE_DEFAULT is not set +# CONFIG_FINSH_USING_AUTH is not set +CONFIG_FINSH_ARG_MAX=10 +CONFIG_FINSH_USING_OPTION_COMPLETION=y + +# +# DFS: device virtual file system +# +CONFIG_RT_USING_DFS=y +CONFIG_DFS_USING_POSIX=y +CONFIG_DFS_USING_WORKDIR=y +CONFIG_DFS_FD_MAX=32 +# CONFIG_RT_USING_DFS_V1 is not set +CONFIG_RT_USING_DFS_V2=y +CONFIG_RT_USING_DFS_ELMFAT=y + +# +# elm-chan's FatFs, Generic FAT Filesystem Module +# +CONFIG_RT_DFS_ELM_CODE_PAGE=437 +CONFIG_RT_DFS_ELM_WORD_ACCESS=y +# CONFIG_RT_DFS_ELM_USE_LFN_0 is not set +# CONFIG_RT_DFS_ELM_USE_LFN_1 is not set +# CONFIG_RT_DFS_ELM_USE_LFN_2 is not set +CONFIG_RT_DFS_ELM_USE_LFN_3=y +CONFIG_RT_DFS_ELM_USE_LFN=3 +CONFIG_RT_DFS_ELM_LFN_UNICODE_0=y +# CONFIG_RT_DFS_ELM_LFN_UNICODE_1 is not set +# CONFIG_RT_DFS_ELM_LFN_UNICODE_2 is not set +# CONFIG_RT_DFS_ELM_LFN_UNICODE_3 is not set +CONFIG_RT_DFS_ELM_LFN_UNICODE=0 +CONFIG_RT_DFS_ELM_MAX_LFN=255 +CONFIG_RT_DFS_ELM_DRIVES=2 +CONFIG_RT_DFS_ELM_MAX_SECTOR_SIZE=512 +# CONFIG_RT_DFS_ELM_USE_ERASE is not set +CONFIG_RT_DFS_ELM_REENTRANT=y +CONFIG_RT_DFS_ELM_MUTEX_TIMEOUT=3000 +CONFIG_RT_DFS_ELM_USE_EXFAT=y +# end of elm-chan's FatFs, Generic FAT Filesystem Module + +CONFIG_RT_USING_DFS_DEVFS=y +CONFIG_RT_USING_DFS_ROMFS=y +# CONFIG_RT_USING_DFS_CROMFS is not set +# CONFIG_RT_USING_DFS_TMPFS is not set +# CONFIG_RT_USING_DFS_MQUEUE is not set +# end of DFS: device virtual file system + +# CONFIG_RT_USING_FAL is not set + +# +# Device Drivers +# +CONFIG_RT_USING_DM=y +# CONFIG_RT_USING_DEV_BUS is not set +CONFIG_RT_USING_DEVICE_IPC=y +CONFIG_RT_UNAMED_PIPE_NUMBER=64 +CONFIG_RT_USING_SYSTEM_WORKQUEUE=y +CONFIG_RT_SYSTEM_WORKQUEUE_STACKSIZE=8192 +CONFIG_RT_SYSTEM_WORKQUEUE_PRIORITY=23 +CONFIG_RT_USING_SERIAL=y +CONFIG_RT_USING_SERIAL_V1=y +# CONFIG_RT_USING_SERIAL_V2 is not set +CONFIG_RT_SERIAL_USING_DMA=y +CONFIG_RT_SERIAL_RB_BUFSZ=64 +CONFIG_RT_USING_SERIAL_BYPASS=y +# CONFIG_RT_SERIAL_EARLY_HVC is not set +# CONFIG_RT_SERIAL_PL011 is not set +CONFIG_RT_SERIAL_8250=y +# CONFIG_RT_SERIAL_8250_DW is not set +# CONFIG_RT_SERIAL_8250_PCI is not set +CONFIG_RT_SERIAL_PXA=y +CONFIG_RT_SERIAL_EARLY_SBI=y +# CONFIG_RT_USING_CAN is not set +CONFIG_RT_USING_ADC=y +# CONFIG_RT_USING_ADC_V2 is not set +CONFIG_RT_USING_ADC_V1=y +CONFIG_RT_ADC_SPACEMIT_PMIC=y +CONFIG_RT_USING_CLOCK_TIME=y +# CONFIG_RT_USING_CLOCK_TIMER_TRIGGER is not set +CONFIG_CLOCK_TIMER_FREQ=0 +CONFIG_RT_CLOCK_TIME_SPACEMIT_K1X=y +CONFIG_RT_USING_ETHERNET=y +# CONFIG_RT_ETHERNET_CADENCE is not set +# CONFIG_RT_ETHERNET_DWMAC is not set +CONFIG_RT_ETHERNET_K1X_EMAC=y +CONFIG_RT_ETHERNET_K1X_EMAC_PTP=y +CONFIG_RT_USING_I2C=y +# CONFIG_RT_I2C_DEBUG is not set +CONFIG_RT_USING_I2C_BITOPS=y +# CONFIG_RT_I2C_BITOPS_DEBUG is not set +# CONFIG_RT_USING_SOFT_I2C is not set +CONFIG_RT_I2C_SPACEMIT_K1X=y +# CONFIG_RT_USING_PHY is not set +CONFIG_RT_USING_PHY_V2=y +CONFIG_RT_PHY_V2_REALTEK=y +# CONFIG_RT_USING_DAC is not set +CONFIG_RT_USING_NULL=y +CONFIG_RT_USING_ZERO=y +CONFIG_RT_USING_RANDOM=y +CONFIG_RT_USING_PWM=y +CONFIG_RT_PWM_PXA=y +# CONFIG_RT_USING_PULSE_ENCODER is not set +# CONFIG_RT_USING_INPUT_CAPTURE is not set +CONFIG_RT_USING_MTD_NOR=y +# CONFIG_RT_USING_MTD_NOR_CFI is not set +CONFIG_RT_USING_MTD_NOR_SPI=y +# CONFIG_RT_USING_MTD_NAND is not set +# CONFIG_RT_USING_PM is not set +CONFIG_RT_USING_RTC=y +CONFIG_RT_USING_ALARM=y +CONFIG_RT_ALARM_STACK_SIZE=16384 +CONFIG_RT_ALARM_TIMESLICE=5 +CONFIG_RT_ALARM_PRIORITY=10 +# CONFIG_RT_ALARM_USING_LOCAL_TIME is not set +# CONFIG_RT_USING_SOFT_RTC is not set +# CONFIG_RT_RTC_DS1302 is not set +# CONFIG_RT_RTC_DS1307 is not set +# CONFIG_RT_RTC_GOLDFISH is not set +# CONFIG_RT_RTC_HYM8563 is not set +# CONFIG_RT_RTC_PCF8523 is not set +# CONFIG_RT_RTC_PCF8563 is not set +# CONFIG_RT_RTC_PL031 is not set +# CONFIG_RT_RTC_RX8010 is not set +CONFIG_RT_RTC_SPACEMIT_PMIC=y +CONFIG_RT_USING_SDIO=y +CONFIG_RT_SDIO_STACK_SIZE=16384 +CONFIG_RT_SDIO_THREAD_PRIORITY=15 +CONFIG_RT_MMCSD_STACK_SIZE=16384 +CONFIG_RT_MMCSD_THREAD_PRIORITY=22 +CONFIG_RT_MMCSD_MAX_PARTITION=16 +# CONFIG_RT_SDIO_DEBUG is not set +CONFIG_RT_USING_SDHCI=y +# CONFIG_RT_SDIO_SDHCI_PCI is not set +# CONFIG_RT_SDIO_DW_MMC is not set +# CONFIG_RT_SDIO_SDHCI_DWCMSHC is not set +CONFIG_RT_SDIO_SDHCI_SPACEMIT_K1X=y +CONFIG_RT_USING_SPI=y +# CONFIG_RT_USING_SPI_ISR is not set +# CONFIG_RT_USING_SPI_BITOPS is not set +# CONFIG_RT_USING_SOFT_SPI is not set +CONFIG_RT_USING_QSPI=y +# CONFIG_RT_USING_SPI_MSD is not set +CONFIG_RT_USING_SFUD=y +CONFIG_RT_SFUD_USING_SFDP=y +CONFIG_RT_SFUD_USING_FLASH_INFO_TABLE=y +CONFIG_RT_SFUD_USING_QSPI=y +CONFIG_RT_SFUD_SPI_MAX_HZ=50000000 +CONFIG_RT_DEBUG_SFUD=y +# CONFIG_RT_USING_ENC28J60 is not set +# CONFIG_RT_USING_SPI_WIFI is not set +CONFIG_RT_SPI_K1X_QSPI=y +CONFIG_RT_SPI_K1X=y +CONFIG_RT_USING_WDT=y +# CONFIG_RT_WDT_DW is not set +# CONFIG_RT_WDT_I6300ESB is not set +CONFIG_RT_WDT_SPACEMIT_WATCHDOG=y +CONFIG_RT_USING_AUDIO=y +CONFIG_RT_AUDIO_REPLAY_MP_BLOCK_SIZE=4096 +CONFIG_RT_AUDIO_REPLAY_MP_BLOCK_COUNT=4 +CONFIG_RT_AUDIO_RECORD_PIPE_SIZE=8192 +# CONFIG_RT_AUDIO_INTEL_HDA is not set +CONFIG_RT_AUDIO_SPACEMIT=y +CONFIG_RT_AUDIO_SPACEMIT_CODEC=y +CONFIG_RT_AUDIO_SPACEMIT_CODEC_ES8326=y +# CONFIG_RT_USING_SENSOR is not set +# CONFIG_RT_USING_TOUCH is not set +CONFIG_RT_USING_LCD=y +CONFIG_RT_USING_GRAPHIC=y +CONFIG_RT_GRAPHIC_BACKLIGHT=y +# CONFIG_RT_GRAPHIC_BACKLIGHT_GPIO is not set +CONFIG_RT_GRAPHIC_BACKLIGHT_PWM=y +CONFIG_RT_GRAPHIC_FB=y +# CONFIG_RT_GRAPHIC_FB_ILI9486 is not set +# CONFIG_RT_GRAPHIC_FB_SIMPLE is not set +CONFIG_RT_GRAPHIC_FB_SPACEMIT=y +CONFIG_RT_GRAPHIC_LOGO=y +# CONFIG_RT_GRAPHIC_LOGO_NONE is not set +# CONFIG_RT_GRAPHIC_LOGO_RT_THREAD_CLUT224 is not set +# CONFIG_RT_GRAPHIC_LOGO_RT_THREAD_WHITE_CLUT224 is not set +# CONFIG_RT_GRAPHIC_LOGO_BIANBU_CLUT224 is not set +CONFIG_RT_GRAPHIC_LOGO_SPACEMIT_CLUT224=y +CONFIG_RT_GRAPHIC_LOGO_SPACEMIT_CLUT224_PATH="../dm/graphic/logo/logo-spacemit-clut224.ppm" +CONFIG_RT_USING_HWCRYPTO=y +CONFIG_RT_HWCRYPTO_DEFAULT_NAME="hwcryto" +CONFIG_RT_HWCRYPTO_IV_MAX_SIZE=16 +CONFIG_RT_HWCRYPTO_KEYBIT_MAX_SIZE=256 +# CONFIG_RT_HWCRYPTO_USING_GCM is not set +CONFIG_RT_HWCRYPTO_USING_AES=y +CONFIG_RT_HWCRYPTO_USING_AES_ECB=y +CONFIG_RT_HWCRYPTO_USING_AES_CBC=y +# CONFIG_RT_HWCRYPTO_USING_AES_CFB is not set +# CONFIG_RT_HWCRYPTO_USING_AES_CTR is not set +# CONFIG_RT_HWCRYPTO_USING_AES_OFB is not set +# CONFIG_RT_HWCRYPTO_USING_DES is not set +# CONFIG_RT_HWCRYPTO_USING_3DES is not set +# CONFIG_RT_HWCRYPTO_USING_RC4 is not set +# CONFIG_RT_HWCRYPTO_USING_MD5 is not set +# CONFIG_RT_HWCRYPTO_USING_SHA1 is not set +# CONFIG_RT_HWCRYPTO_USING_SHA2 is not set +CONFIG_RT_HWCRYPTO_USING_RNG=y +# CONFIG_RT_HWCRYPTO_USING_CRC is not set +# CONFIG_RT_HWCRYPTO_USING_BIGNUM is not set +CONFIG_RT_HWCRYPTO_SPACEMIT=y +CONFIG_RT_HWCRYPTO_RNG_SPACEMIT=y +# CONFIG_RT_USING_WIFI is not set +CONFIG_RT_USING_PTP=y +CONFIG_RT_USING_LED=y +CONFIG_RT_LED_GPIO=y +# CONFIG_RT_LED_PWM is not set +# CONFIG_RT_LED_SYSCON is not set +CONFIG_RT_USING_INPUT=y +CONFIG_RT_INPUT_POWER=y +# CONFIG_RT_INPUT_UAPI is not set +# CONFIG_RT_INPUT_JOYSTICK is not set +# CONFIG_RT_INPUT_KEYBOARD is not set +CONFIG_RT_INPUT_MISC=y +# CONFIG_RT_INPUT_MISC_BUTTON_E3X0 is not set +CONFIG_RT_INPUT_MISC_PWRKEY_SPACEMIT_PMIC=y +# CONFIG_RT_INPUT_TOUCHSCREEN is not set +CONFIG_RT_USING_MBOX=y +# CONFIG_RT_MBOX_PIC is not set +CONFIG_RT_MBOX_K1X=y +# CONFIG_RT_USING_HWSPINLOCK is not set +CONFIG_RT_USING_RPMSG=y +CONFIG_RT_RPMSG_CHAR_MSG_MAX=64 +CONFIG_RT_RPMSG_CHAR_MSG_SIZE_MAX=256 +# CONFIG_RT_RPMSG_RT_THREAD_VIRTIO is not set +# CONFIG_RT_USING_PHYE is not set +CONFIG_RT_USING_ATA=y +CONFIG_RT_ATA_AHCI=y +CONFIG_RT_ATA_AHCI_PCI=y +CONFIG_RT_USING_NVME=y +CONFIG_RT_USING_NVME_IO_QUEUE=4 +CONFIG_RT_NVME_PCI=y +CONFIG_RT_USING_BLK=y + +# +# Partition Types +# +CONFIG_RT_BLK_PARTITION_DFS=y +CONFIG_RT_BLK_PARTITION_EFI=y +# end of Partition Types + +CONFIG_RT_USING_SCSI=y +CONFIG_RT_SCSI_SD=y +# CONFIG_RT_SCSI_CDROM is not set +# CONFIG_RT_USING_UFS is not set +# CONFIG_RT_USING_FIRMWARE is not set +# CONFIG_RT_USING_TEE is not set +# CONFIG_RT_USING_HWCACHE is not set +CONFIG_RT_USING_DVFS=y +CONFIG_RT_USING_DVFS_EVENT=y +CONFIG_RT_USING_DVFS_OPP_RETRY_MAX=10 + +# +# DVFS Event Drivers +# + +# +# DVFS CPUfreq Drivers +# +CONFIG_RT_DVFS_SPACEMIT_CPUFREQ=y + +# +# DVFS Devfreq Drivers +# +CONFIG_RT_USING_REGULATOR=y +# CONFIG_RT_REGULATOR_FAN53555 is not set +CONFIG_RT_REGULATOR_FIXED=y +CONFIG_RT_REGULATOR_GPIO=y +# CONFIG_RT_REGULATOR_PWM is not set +CONFIG_RT_REGULATOR_SPACEMIT_PMIC=y +CONFIG_RT_USING_RESET=y +# CONFIG_RT_RESET_SIMPLE is not set +CONFIG_RT_RESET_SPACEMIT_K1=y + +# +# Power Management (PM) Domains device drivers +# +CONFIG_RT_PMDOMAIN_K1X=y +# end of Power Management (PM) Domains device drivers + +CONFIG_RT_USING_POWER_RESET=y +# CONFIG_RT_POWER_RESET_GPIO_POWEROFF is not set +# CONFIG_RT_POWER_RESET_GPIO_RESTART is not set +# CONFIG_RT_POWER_RESET_SYSCON_POWEROFF is not set +# CONFIG_RT_POWER_RESET_SYSCON_REBOOT_MODE is not set +# CONFIG_RT_POWER_RESET_SYSCON_REBOOT is not set +CONFIG_RT_POWER_RESET_REBOOT_SPACEMIT=y +# CONFIG_RT_USING_POWER_SUPPLY is not set +CONFIG_RT_USING_THERMAL=y + +# +# Thermal Sensors Drivers +# +CONFIG_RT_THERMAL_K1X=y + +# +# Thermal Cool Drivers +# +CONFIG_RT_THERMAL_COOL_DVFS=y +# CONFIG_RT_THERMAL_COOL_GPIO_FAN is not set +CONFIG_RT_THERMAL_COOL_PWM_FAN=y +CONFIG_RT_USING_VIRTIO=y +# CONFIG_RT_VIRTIO_TRANSPORT_MMIO is not set +# CONFIG_RT_VIRTIO_TRANSPORT_PCI is not set +CONFIG_RT_VIRTIO_NET=y +# CONFIG_RT_VIRTIO_BLK is not set +# CONFIG_RT_VIRTIO_CONSOLE is not set +# CONFIG_RT_VIRTIO_RNG is not set +CONFIG_RT_VIRTIO_RPMSG=y +# CONFIG_RT_VIRTIO_SCSI is not set +# CONFIG_RT_VIRTIO_9P is not set +# CONFIG_RT_VIRTIO_RPROC_SERIAL is not set +# CONFIG_RT_VIRTIO_GPU is not set +# CONFIG_RT_VIRTIO_SOUND is not set +CONFIG_RT_USING_NVMEM=y +CONFIG_RT_NVMEM_SPACEMIT_EFUSE=y +CONFIG_RT_USING_DMA=y +# CONFIG_RT_DMA_PL330 is not set +# CONFIG_RT_DMA_DW_AXI_DMAC is not set +CONFIG_RT_DMA_MMP_PDMA=y +CONFIG_RT_DMA_MMP_PDMA_SUPPORT_64BIT=y +CONFIG_RT_USING_MFD=y +# CONFIG_RT_MFD_EDU is not set +CONFIG_RT_MFD_SYSCON=y +CONFIG_RT_MFD_SPACEMIT_PMIC=y +# CONFIG_RT_USING_IVSHMEM is not set +CONFIG_RT_USING_OFW=y +# CONFIG_RT_USING_BUILTIN_FDT is not set +CONFIG_RT_FDT_EARLYCON_MSG_SIZE=128 +CONFIG_RT_USING_OFW_BUS_RANGES_NUMBER=8 +CONFIG_RT_USING_PCI=y +CONFIG_RT_PCI_MSI=y +CONFIG_RT_PCI_ENDPOINT=y +CONFIG_RT_PCI_SYS_64BIT=y +CONFIG_RT_PCI_CACHE_LINE_SIZE=8 +# CONFIG_RT_PCI_LOCKLESS is not set + +# +# PCI Device Drivers +# +# CONFIG_RT_PCI_ECAM is not set +CONFIG_RT_PCI_DW=y +CONFIG_RT_PCI_DW_HOST=y +CONFIG_RT_PCI_DW_EP=y +CONFIG_RT_PCI_DW_SPACEMIT_K1X=y +CONFIG_RT_USING_PIC=y +# CONFIG_RT_USING_PIC_STATISTICS is not set +CONFIG_MAX_HANDLERS=1024 +# CONFIG_RT_PIC_ARM_GIC is not set +# CONFIG_RT_PIC_ARM_GIC_V3 is not set +# CONFIG_RT_PIC_RISCV_AIA is not set +# CONFIG_RT_PIC_RISCV_CLIC is not set +CONFIG_RT_PIC_RISCV_INTC=y +CONFIG_RT_PIC_SIFIVE_PLIC=y +CONFIG_RT_USING_PIN=y +# CONFIG_RT_PIN_PL061 is not set +CONFIG_RT_PIN_K1X=y +CONFIG_RT_USING_PINCTRL=y +CONFIG_RT_PINCTRL_SINGLE=y +CONFIG_RT_PINCTRL_SPACEMIT_PMIC=y +CONFIG_RT_USING_CLK=y +CONFIG_RT_CLK_SPACEMIT=y +CONFIG_RT_CLK_SPACEMIT_K1X=y +# CONFIG_RT_USING_CHERRYUSB is not set + +# +# SoC (System on Chip) Drivers +# +CONFIG_RT_SOC_SPACEMIT_K1X_RPROC=y +CONFIG_RT_SOC_CHIP_MEDIA_JPU=y +CONFIG_RT_SOC_SPACEMIT_V2D=y +CONFIG_RT_SOC_SPACEMIT_K1X_TCM=y +CONFIG_RT_SOC_SPACEMIT_SOCINFO=y +# end of SoC (System on Chip) Drivers +# end of Device Drivers + +# +# C/C++ and POSIX layer +# + +# +# ISO-ANSI C layer +# + +# +# Timezone and Daylight Saving Time +# +# CONFIG_RT_LIBC_USING_FULL_TZ_DST is not set +CONFIG_RT_LIBC_USING_LIGHT_TZ_DST=y +CONFIG_RT_LIBC_TZ_DEFAULT_HOUR=8 +CONFIG_RT_LIBC_TZ_DEFAULT_MIN=0 +CONFIG_RT_LIBC_TZ_DEFAULT_SEC=0 +# end of Timezone and Daylight Saving Time +# end of ISO-ANSI C layer + +# +# POSIX (Portable Operating System Interface) layer +# +CONFIG_RT_USING_POSIX_FS=y +CONFIG_RT_USING_POSIX_DEVIO=y +CONFIG_RT_USING_POSIX_STDIO=y +CONFIG_RT_USING_POSIX_POLL=y +CONFIG_RT_USING_POSIX_SELECT=y +# CONFIG_RT_USING_POSIX_EVENTFD is not set +# CONFIG_RT_USING_POSIX_TIMERFD is not set +# CONFIG_RT_USING_POSIX_SOCKET is not set +CONFIG_RT_USING_POSIX_TERMIOS=y +CONFIG_RT_USING_POSIX_AIO=y +# CONFIG_RT_USING_POSIX_MMAN is not set +CONFIG_RT_USING_POSIX_DELAY=y +CONFIG_RT_USING_POSIX_CLOCK=y +CONFIG_RT_USING_POSIX_TIMER=y +# CONFIG_RT_USING_PTHREADS is not set +# CONFIG_RT_USING_MODULE is not set + +# +# Interprocess Communication (IPC) +# +CONFIG_RT_USING_POSIX_PIPE=y +CONFIG_RT_USING_POSIX_PIPE_SIZE=512 +# CONFIG_RT_USING_POSIX_MESSAGE_QUEUE is not set +# CONFIG_RT_USING_POSIX_MESSAGE_SEMAPHORE is not set + +# +# Socket is in the 'Network' category +# +# end of Interprocess Communication (IPC) +# end of POSIX (Portable Operating System Interface) layer + +# CONFIG_RT_USING_CPLUSPLUS is not set +# end of C/C++ and POSIX layer + +# +# Network +# +CONFIG_RT_USING_SAL=y +CONFIG_SAL_INTERNET_CHECK=y +CONFIG_SOCKET_TABLE_STEP_LEN=4 + +# +# Docking with protocol stacks +# +CONFIG_SAL_USING_LWIP=y +# CONFIG_SAL_USING_AT is not set +# CONFIG_SAL_USING_TLS is not set +# end of Docking with protocol stacks + +CONFIG_SAL_USING_POSIX=y +# CONFIG_RT_USING_AF_UNIX is not set +CONFIG_RT_USING_NETDEV=y +CONFIG_NETDEV_USING_IFCONFIG=y +CONFIG_NETDEV_USING_PING=y +CONFIG_NETDEV_USING_NETSTAT=y +CONFIG_NETDEV_USING_AUTO_DEFAULT=y +# CONFIG_NETDEV_USING_LINK_STATUS_CALLBACK is not set +# CONFIG_NETDEV_USING_IPV6 is not set +CONFIG_NETDEV_IPV4=1 +CONFIG_NETDEV_IPV6=0 +CONFIG_RT_USING_LWIP=y +# CONFIG_RT_USING_LWIP_LOCAL_VERSION is not set +# CONFIG_RT_USING_LWIP141 is not set +CONFIG_RT_USING_LWIP203=y +# CONFIG_RT_USING_LWIP212 is not set +# CONFIG_RT_USING_LWIP_LATEST is not set +CONFIG_RT_USING_LWIP_VER_NUM=0x20003 +# CONFIG_RT_USING_LWIP_IPV6 is not set +CONFIG_RT_LWIP_MEM_ALIGNMENT=4 +CONFIG_RT_LWIP_IGMP=y +CONFIG_RT_LWIP_ICMP=y +# CONFIG_RT_LWIP_SNMP is not set +CONFIG_RT_LWIP_DNS=y +CONFIG_RT_LWIP_DHCP=y +CONFIG_IP_SOF_BROADCAST=1 +CONFIG_IP_SOF_BROADCAST_RECV=1 + +# +# Static IPv4 Address +# +CONFIG_RT_LWIP_IPADDR="192.168.1.30" +CONFIG_RT_LWIP_GWADDR="192.168.1.1" +CONFIG_RT_LWIP_MSKADDR="255.255.255.0" +# end of Static IPv4 Address + +CONFIG_RT_LWIP_UDP=y +CONFIG_RT_LWIP_TCP=y +CONFIG_RT_LWIP_RAW=y +# CONFIG_RT_LWIP_PPP is not set +CONFIG_RT_MEMP_NUM_NETCONN=8 +CONFIG_RT_LWIP_PBUF_NUM=16 +CONFIG_RT_LWIP_RAW_PCB_NUM=4 +CONFIG_RT_LWIP_UDP_PCB_NUM=4 +CONFIG_RT_LWIP_TCP_PCB_NUM=4 +CONFIG_RT_LWIP_TCP_SEG_NUM=40 +CONFIG_RT_LWIP_TCP_SND_BUF=8196 +CONFIG_RT_LWIP_TCP_WND=8196 +CONFIG_RT_LWIP_TCPTHREAD_PRIORITY=10 +CONFIG_RT_LWIP_TCPTHREAD_MBOX_SIZE=8 +CONFIG_RT_LWIP_TCPTHREAD_STACKSIZE=8192 +# CONFIG_LWIP_NO_RX_THREAD is not set +# CONFIG_LWIP_NO_TX_THREAD is not set +CONFIG_RT_LWIP_ETHTHREAD_PRIORITY=12 +CONFIG_RT_LWIP_ETHTHREAD_STACKSIZE=8192 +CONFIG_RT_LWIP_ETHTHREAD_MBOX_SIZE=8 +# CONFIG_RT_LWIP_REASSEMBLY_FRAG is not set +CONFIG_LWIP_NETIF_STATUS_CALLBACK=1 +CONFIG_LWIP_NETIF_LINK_CALLBACK=1 +CONFIG_RT_LWIP_NETIF_NAMESIZE=6 +CONFIG_SO_REUSE=1 +CONFIG_LWIP_SO_RCVTIMEO=1 +CONFIG_LWIP_SO_SNDTIMEO=1 +CONFIG_LWIP_SO_RCVBUF=1 +CONFIG_LWIP_SO_LINGER=0 +# CONFIG_RT_LWIP_NETIF_LOOPBACK is not set +CONFIG_LWIP_NETIF_LOOPBACK=0 +# CONFIG_RT_LWIP_STATS is not set +# CONFIG_RT_LWIP_USING_HW_CHECKSUM is not set +CONFIG_RT_LWIP_USING_PING=y +# CONFIG_LWIP_USING_DHCPD is not set +# CONFIG_RT_LWIP_ENABLE_USER_HOOKS is not set +# CONFIG_RT_LWIP_DEBUG is not set +# CONFIG_RT_USING_AT is not set +# end of Network + +# +# Memory protection +# +# CONFIG_RT_USING_MEM_PROTECTION is not set +# CONFIG_RT_USING_HW_STACK_GUARD is not set +# end of Memory protection + +# +# Utilities +# +# CONFIG_RT_USING_RYM is not set +# CONFIG_RT_USING_ULOG is not set +# CONFIG_RT_USING_UTEST is not set +# CONFIG_RT_USING_VAR_EXPORT is not set +CONFIG_RT_USING_RESOURCE_ID=y +CONFIG_RT_USING_ADT=y +CONFIG_RT_USING_ADT_AVL=y +CONFIG_RT_USING_ADT_BITMAP=y +CONFIG_RT_USING_ADT_HASHMAP=y +CONFIG_RT_USING_ADT_REF=y +# CONFIG_RT_USING_RT_LINK is not set +# end of Utilities + +# +# Memory management +# +CONFIG_RT_PAGE_MPR_SIZE_DYNAMIC=y +CONFIG_RT_PAGE_AFFINITY_BLOCK_SIZE=0x1000 +CONFIG_RT_PAGE_MAX_ORDER=11 +CONFIG_RT_USING_MEMBLOCK=y +CONFIG_RT_INIT_MEMORY_REGIONS=128 + +# +# Debugging +# +# CONFIG_RT_DEBUGGING_ALIASING is not set +# CONFIG_RT_DEBUGING_PAGE_LEAK is not set +# CONFIG_RT_DEBUGGING_PAGE_POISON is not set +# end of Debugging +# end of Memory management + +# +# Using USB legacy version +# +# CONFIG_RT_USING_USB_HOST is not set +# CONFIG_RT_USING_USB_DEVICE is not set +# end of Using USB legacy version + +# CONFIG_RT_USING_FDT is not set +# CONFIG_RT_USING_LEGACY_VIRTIO is not set +# CONFIG_RT_USING_RUST is not set +# end of RT-Thread Components + +# +# RT-Thread Utestcases +# +# CONFIG_RT_USING_UTESTCASES is not set +# end of RT-Thread Utestcases + +# +# RT-Thread online packages +# + +# +# IoT - internet of things +# +# CONFIG_PKG_USING_LORAWAN_DRIVER is not set +# CONFIG_PKG_USING_PAHOMQTT is not set +# CONFIG_PKG_USING_UMQTT is not set +# CONFIG_PKG_USING_WEBCLIENT is not set +# CONFIG_PKG_USING_WEBNET is not set +# CONFIG_PKG_USING_MONGOOSE is not set +# CONFIG_PKG_USING_MYMQTT is not set +# CONFIG_PKG_USING_KAWAII_MQTT is not set +# CONFIG_PKG_USING_BC28_MQTT is not set +# CONFIG_PKG_USING_WEBTERMINAL is not set +# CONFIG_PKG_USING_FREEMODBUS is not set +# CONFIG_PKG_USING_NANOPB is not set +# CONFIG_PKG_USING_WIFI_HOST_DRIVER is not set +# CONFIG_PKG_USING_ESP_HOSTED is not set + +# +# Wi-Fi +# + +# +# Marvell WiFi +# +# CONFIG_PKG_USING_WLANMARVELL is not set +# end of Marvell WiFi + +# +# Wiced WiFi +# +# CONFIG_PKG_USING_WLAN_WICED is not set +# end of Wiced WiFi + +# CONFIG_PKG_USING_RW007 is not set + +# +# CYW43012 WiFi +# +# CONFIG_PKG_USING_WLAN_CYW43012 is not set +# end of CYW43012 WiFi + +# +# BL808 WiFi +# +# CONFIG_PKG_USING_WLAN_BL808 is not set +# end of BL808 WiFi + +# +# CYW43439 WiFi +# +# CONFIG_PKG_USING_WLAN_CYW43439 is not set +# end of CYW43439 WiFi +# end of Wi-Fi + +# CONFIG_PKG_USING_COAP is not set +# CONFIG_PKG_USING_NOPOLL is not set +# CONFIG_PKG_USING_NETUTILS is not set +# CONFIG_PKG_USING_CMUX is not set +# CONFIG_PKG_USING_PPP_DEVICE is not set +# CONFIG_PKG_USING_AT_DEVICE is not set +# CONFIG_PKG_USING_ATSRV_SOCKET is not set +# CONFIG_PKG_USING_WIZNET is not set +# CONFIG_PKG_USING_ZB_COORDINATOR is not set + +# +# IoT Cloud +# +# CONFIG_PKG_USING_ONENET is not set +# CONFIG_PKG_USING_GAGENT_CLOUD is not set +# CONFIG_PKG_USING_ALI_IOTKIT is not set +# CONFIG_PKG_USING_AZURE is not set +# CONFIG_PKG_USING_TENCENT_IOT_EXPLORER is not set +# CONFIG_PKG_USING_JIOT-C-SDK is not set +# CONFIG_PKG_USING_UCLOUD_IOT_SDK is not set +# CONFIG_PKG_USING_JOYLINK is not set +# CONFIG_PKG_USING_IOTSHARP_SDK is not set +# end of IoT Cloud + +# CONFIG_PKG_USING_NIMBLE is not set +# CONFIG_PKG_USING_LLSYNC_SDK_ADAPTER is not set +# CONFIG_PKG_USING_OTA_DOWNLOADER is not set +# CONFIG_PKG_USING_IPMSG is not set +# CONFIG_PKG_USING_LSSDP is not set +# CONFIG_PKG_USING_AIRKISS_OPEN is not set +# CONFIG_PKG_USING_LIBRWS is not set +# CONFIG_PKG_USING_TCPSERVER is not set +# CONFIG_PKG_USING_PROTOBUF_C is not set +# CONFIG_PKG_USING_DLT645 is not set +# CONFIG_PKG_USING_QXWZ is not set +# CONFIG_PKG_USING_SMTP_CLIENT is not set +# CONFIG_PKG_USING_ABUP_FOTA is not set +# CONFIG_PKG_USING_LIBCURL2RTT is not set +# CONFIG_PKG_USING_CAPNP is not set +# CONFIG_PKG_USING_ERPC is not set +# CONFIG_PKG_USING_AGILE_TELNET is not set +# CONFIG_PKG_USING_NMEALIB is not set +# CONFIG_PKG_USING_PDULIB is not set +# CONFIG_PKG_USING_BTSTACK is not set +# CONFIG_PKG_USING_BT_CYW43012 is not set +# CONFIG_PKG_USING_CYW43XX is not set +# CONFIG_PKG_USING_LORAWAN_ED_STACK is not set +# CONFIG_PKG_USING_WAYZ_IOTKIT is not set +# CONFIG_PKG_USING_MAVLINK is not set +# CONFIG_PKG_USING_BSAL is not set +# CONFIG_PKG_USING_AGILE_MODBUS is not set +# CONFIG_PKG_USING_AGILE_FTP is not set +# CONFIG_PKG_USING_EMBEDDEDPROTO is not set +# CONFIG_PKG_USING_RT_LINK_HW is not set +# CONFIG_PKG_USING_RYANMQTT is not set +# CONFIG_PKG_USING_RYANW5500 is not set +# CONFIG_PKG_USING_LORA_PKT_FWD is not set +# CONFIG_PKG_USING_LORA_GW_DRIVER_LIB is not set +# CONFIG_PKG_USING_LORA_PKT_SNIFFER is not set +# CONFIG_PKG_USING_HM is not set +# CONFIG_PKG_USING_SMALL_MODBUS is not set +# CONFIG_PKG_USING_NET_SERVER is not set +# CONFIG_PKG_USING_ZFTP is not set +# CONFIG_PKG_USING_WOL is not set +# CONFIG_PKG_USING_ZEPHYR_POLLING is not set +# CONFIG_PKG_USING_MATTER_ADAPTATION_LAYER is not set +# CONFIG_PKG_USING_LHC_MODBUS is not set +# CONFIG_PKG_USING_QMODBUS is not set +# CONFIG_PKG_USING_PNET is not set +# CONFIG_PKG_USING_OPENER is not set +# CONFIG_PKG_USING_FREEMQTT is not set +# end of IoT - internet of things + +# +# security packages +# +# CONFIG_PKG_USING_MBEDTLS is not set +# CONFIG_PKG_USING_LIBSODIUM is not set +# CONFIG_PKG_USING_LIBHYDROGEN is not set +# CONFIG_PKG_USING_TINYCRYPT is not set +# CONFIG_PKG_USING_TFM is not set +# CONFIG_PKG_USING_YD_CRYPTO is not set +# end of security packages + +# +# language packages +# + +# +# JSON: JavaScript Object Notation, a lightweight data-interchange format +# +# CONFIG_PKG_USING_CJSON is not set +# CONFIG_PKG_USING_LJSON is not set +# CONFIG_PKG_USING_RT_CJSON_TOOLS is not set +# CONFIG_PKG_USING_RAPIDJSON is not set +# CONFIG_PKG_USING_JSMN is not set +# CONFIG_PKG_USING_AGILE_JSMN is not set +# CONFIG_PKG_USING_PARSON is not set +# CONFIG_PKG_USING_RYAN_JSON is not set +# end of JSON: JavaScript Object Notation, a lightweight data-interchange format + +# +# XML: Extensible Markup Language +# +# CONFIG_PKG_USING_SIMPLE_XML is not set +# CONFIG_PKG_USING_EZXML is not set +# end of XML: Extensible Markup Language + +# CONFIG_PKG_USING_LUATOS_SOC is not set +# CONFIG_PKG_USING_LUA is not set +# CONFIG_PKG_USING_JERRYSCRIPT is not set +# CONFIG_PKG_USING_MICROPYTHON is not set +# CONFIG_PKG_USING_PIKASCRIPT is not set +# CONFIG_PKG_USING_RTT_RUST is not set +# end of language packages + +# +# multimedia packages +# + +# +# LVGL: powerful and easy-to-use embedded GUI library +# +# CONFIG_PKG_USING_LVGL is not set +# CONFIG_PKG_USING_LV_MUSIC_DEMO is not set +# CONFIG_PKG_USING_GUI_GUIDER_DEMO is not set +# end of LVGL: powerful and easy-to-use embedded GUI library + +# +# u8g2: a monochrome graphic library +# +# CONFIG_PKG_USING_U8G2_OFFICIAL is not set +# CONFIG_PKG_USING_U8G2 is not set +# end of u8g2: a monochrome graphic library + +# CONFIG_PKG_USING_NES_SIMULATOR is not set +# CONFIG_PKG_USING_OPENMV is not set +# CONFIG_PKG_USING_MUPDF is not set +# CONFIG_PKG_USING_STEMWIN is not set +# CONFIG_PKG_USING_WAVPLAYER is not set +# CONFIG_PKG_USING_TJPGD is not set +# CONFIG_PKG_USING_PDFGEN is not set +# CONFIG_PKG_USING_HELIX is not set +# CONFIG_PKG_USING_AZUREGUIX is not set +# CONFIG_PKG_USING_TOUCHGFX2RTT is not set +# CONFIG_PKG_USING_NUEMWIN is not set +# CONFIG_PKG_USING_MP3PLAYER is not set +# CONFIG_PKG_USING_TINYJPEG is not set +# CONFIG_PKG_USING_UGUI is not set +# CONFIG_PKG_USING_MCURSES is not set +# CONFIG_PKG_USING_TERMBOX is not set +# CONFIG_PKG_USING_VT100 is not set +# CONFIG_PKG_USING_QRCODE is not set +# CONFIG_PKG_USING_GUIENGINE is not set +# CONFIG_PKG_USING_3GPP_AMRNB is not set +# end of multimedia packages + +# +# tools packages +# +# CONFIG_PKG_USING_VECTOR is not set +# CONFIG_PKG_USING_SORCH is not set +# CONFIG_PKG_USING_DICT is not set +# CONFIG_PKG_USING_CMBACKTRACE is not set +# CONFIG_PKG_USING_MCOREDUMP is not set +# CONFIG_PKG_USING_EASYFLASH is not set +# CONFIG_PKG_USING_EASYLOGGER is not set +# CONFIG_PKG_USING_SYSTEMVIEW is not set +# CONFIG_PKG_USING_SEGGER_RTT is not set +# CONFIG_PKG_USING_RTT_AUTO_EXE_CMD is not set +# CONFIG_PKG_USING_RDB is not set +# CONFIG_PKG_USING_ULOG_EASYFLASH is not set +# CONFIG_PKG_USING_LOGMGR is not set +# CONFIG_PKG_USING_ADBD is not set +# CONFIG_PKG_USING_COREMARK is not set +# CONFIG_PKG_USING_DHRYSTONE is not set +# CONFIG_PKG_USING_MEMORYPERF is not set +# CONFIG_PKG_USING_NR_MICRO_SHELL is not set +# CONFIG_PKG_USING_CHINESE_FONT_LIBRARY is not set +# CONFIG_PKG_USING_LUNAR_CALENDAR is not set +# CONFIG_PKG_USING_BS8116A is not set +# CONFIG_PKG_USING_GPS_RMC is not set +# CONFIG_PKG_USING_URLENCODE is not set +# CONFIG_PKG_USING_UMCN is not set +# CONFIG_PKG_USING_LWRB2RTT is not set +# CONFIG_PKG_USING_CPU_USAGE is not set +# CONFIG_PKG_USING_GBK2UTF8 is not set +# CONFIG_PKG_USING_VCONSOLE is not set +# CONFIG_PKG_USING_KDB is not set +# CONFIG_PKG_USING_WAMR is not set +# CONFIG_PKG_USING_MICRO_XRCE_DDS_CLIENT is not set +# CONFIG_PKG_USING_LWLOG is not set +# CONFIG_PKG_USING_ANV_TRACE is not set +# CONFIG_PKG_USING_ANV_MEMLEAK is not set +# CONFIG_PKG_USING_ANV_TESTSUIT is not set +# CONFIG_PKG_USING_ANV_BENCH is not set +# CONFIG_PKG_USING_DEVMEM is not set +# CONFIG_PKG_USING_REGEX is not set +# CONFIG_PKG_USING_MEM_SANDBOX is not set +# CONFIG_PKG_USING_SOLAR_TERMS is not set +# CONFIG_PKG_USING_GAN_ZHI is not set +# CONFIG_PKG_USING_FDT is not set +# CONFIG_PKG_USING_CBOX is not set +# CONFIG_PKG_USING_SNOWFLAKE is not set +# CONFIG_PKG_USING_HASH_MATCH is not set +# CONFIG_PKG_USING_ARMV7M_DWT_TOOL is not set +# CONFIG_PKG_USING_VOFA_PLUS is not set +# CONFIG_PKG_USING_ZDEBUG is not set +# CONFIG_PKG_USING_RVBACKTRACE is not set +# CONFIG_PKG_USING_HPATCHLITE is not set +# CONFIG_PKG_USING_THREAD_METRIC is not set +# CONFIG_PKG_USING_UORB is not set +# CONFIG_PKG_USING_RT_TUNNEL is not set +# CONFIG_PKG_USING_VIRTUAL_TERMINAL is not set +# CONFIG_PKG_USING_FEE is not set +# end of tools packages + +# +# system packages +# + +# +# enhanced kernel services +# +# CONFIG_PKG_USING_RT_MEMCPY_CM is not set +# CONFIG_PKG_USING_RT_KPRINTF_THREADSAFE is not set +# end of enhanced kernel services + +# CONFIG_PKG_USING_AUNITY is not set + +# +# acceleration: Assembly language or algorithmic acceleration packages +# +# CONFIG_PKG_USING_QFPLIB_M0_FULL is not set +# CONFIG_PKG_USING_QFPLIB_M0_TINY is not set +# CONFIG_PKG_USING_QFPLIB_M3 is not set +# end of acceleration: Assembly language or algorithmic acceleration packages + +# +# CMSIS: ARM Cortex-M Microcontroller Software Interface Standard +# +# CONFIG_PKG_USING_CMSIS_5 is not set +# CONFIG_PKG_USING_CMSIS_CORE is not set +# CONFIG_PKG_USING_CMSIS_NN is not set +# CONFIG_PKG_USING_CMSIS_RTOS1 is not set +# CONFIG_PKG_USING_CMSIS_RTOS2 is not set +# end of CMSIS: ARM Cortex-M Microcontroller Software Interface Standard + +# +# Micrium: Micrium software products porting for RT-Thread +# +# CONFIG_PKG_USING_UCOSIII_WRAPPER is not set +# CONFIG_PKG_USING_UCOSII_WRAPPER is not set +# CONFIG_PKG_USING_UC_CRC is not set +# CONFIG_PKG_USING_UC_CLK is not set +# CONFIG_PKG_USING_UC_COMMON is not set +# CONFIG_PKG_USING_UC_MODBUS is not set +# end of Micrium: Micrium software products porting for RT-Thread + +# CONFIG_PKG_USING_FREERTOS_WRAPPER is not set +# CONFIG_PKG_USING_LITEOS_SDK is not set +# CONFIG_PKG_USING_TZ_DATABASE is not set +# CONFIG_PKG_USING_CAIRO is not set +# CONFIG_PKG_USING_PIXMAN is not set +# CONFIG_PKG_USING_PARTITION is not set +# CONFIG_PKG_USING_PERF_COUNTER is not set +# CONFIG_PKG_USING_FILEX is not set +# CONFIG_PKG_USING_LEVELX is not set +# CONFIG_PKG_USING_FLASHDB is not set +# CONFIG_PKG_USING_SQLITE is not set +# CONFIG_PKG_USING_RTI is not set +# CONFIG_PKG_USING_DFS_YAFFS is not set +# CONFIG_PKG_USING_LITTLEFS is not set +# CONFIG_PKG_USING_DFS_JFFS2 is not set +# CONFIG_PKG_USING_DFS_UFFS is not set +# CONFIG_PKG_USING_LWEXT4 is not set +# CONFIG_PKG_USING_THREAD_POOL is not set +# CONFIG_PKG_USING_ROBOTS is not set +# CONFIG_PKG_USING_EV is not set +# CONFIG_PKG_USING_SYSWATCH is not set +# CONFIG_PKG_USING_SYS_LOAD_MONITOR is not set +# CONFIG_PKG_USING_PLCCORE is not set +# CONFIG_PKG_USING_RAMDISK is not set +# CONFIG_PKG_USING_MININI is not set +# CONFIG_PKG_USING_QBOOT is not set +# CONFIG_PKG_USING_PPOOL is not set +# CONFIG_PKG_USING_OPENAMP is not set +# CONFIG_PKG_USING_RPMSG_LITE is not set +# CONFIG_PKG_USING_LPM is not set +# CONFIG_PKG_USING_TLSF is not set +# CONFIG_PKG_USING_EVENT_RECORDER is not set +# CONFIG_PKG_USING_ARM_2D is not set +# CONFIG_PKG_USING_MCUBOOT is not set +# CONFIG_PKG_USING_TINYUSB is not set +# CONFIG_PKG_USING_KMULTI_RTIMER is not set +# CONFIG_PKG_USING_TFDB is not set +# CONFIG_PKG_USING_QPC is not set +# CONFIG_PKG_USING_AGILE_UPGRADE is not set +# CONFIG_PKG_USING_FLASH_BLOB is not set +# CONFIG_PKG_USING_MLIBC is not set +# CONFIG_PKG_USING_TASK_MSG_BUS is not set +# CONFIG_PKG_USING_UART_FRAMEWORK is not set +# CONFIG_PKG_USING_SFDB is not set +# CONFIG_PKG_USING_RTP is not set +# CONFIG_PKG_USING_REB is not set +# CONFIG_PKG_USING_RMP is not set +# CONFIG_PKG_USING_R_RHEALSTONE is not set +# CONFIG_PKG_USING_HEARTBEAT is not set +# CONFIG_PKG_USING_MICRO_ROS_RTTHREAD_PACKAGE is not set +# CONFIG_PKG_USING_CHERRYECAT is not set +# CONFIG_PKG_USING_EVENT_LOOP is not set +# CONFIG_PKG_USING_THREAD_MANAGER is not set +# end of system packages + +# +# peripheral libraries and drivers +# + +# +# HAL & SDK Drivers +# + +# +# STM32 HAL & SDK Drivers +# +# CONFIG_PKG_USING_STM32F0_HAL_DRIVER is not set +# CONFIG_PKG_USING_STM32F0_CMSIS_DRIVER is not set +# CONFIG_PKG_USING_STM32F1_HAL_DRIVER is not set +# CONFIG_PKG_USING_STM32F1_CMSIS_DRIVER is not set +# CONFIG_PKG_USING_STM32F2_HAL_DRIVER is not set +# CONFIG_PKG_USING_STM32F2_CMSIS_DRIVER is not set +# CONFIG_PKG_USING_STM32F3_HAL_DRIVER is not set +# CONFIG_PKG_USING_STM32F3_CMSIS_DRIVER is not set +# CONFIG_PKG_USING_STM32F4_HAL_DRIVER is not set +# CONFIG_PKG_USING_STM32F4_CMSIS_DRIVER is not set +# CONFIG_PKG_USING_STM32F7_HAL_DRIVER is not set +# CONFIG_PKG_USING_STM32F7_CMSIS_DRIVER is not set +# CONFIG_PKG_USING_STM32G0_HAL_DRIVER is not set +# CONFIG_PKG_USING_STM32G0_CMSIS_DRIVER is not set +# CONFIG_PKG_USING_STM32G4_HAL_DRIVER is not set +# CONFIG_PKG_USING_STM32G4_CMSIS_DRIVER is not set +# CONFIG_PKG_USING_STM32H5_HAL_DRIVER is not set +# CONFIG_PKG_USING_STM32H5_CMSIS_DRIVER is not set +# CONFIG_PKG_USING_STM32H7_HAL_DRIVER is not set +# CONFIG_PKG_USING_STM32H7_CMSIS_DRIVER is not set +# CONFIG_PKG_USING_STM32H7RS_HAL_DRIVER is not set +# CONFIG_PKG_USING_STM32H7RS_CMSIS_DRIVER is not set +# CONFIG_PKG_USING_STM32L0_HAL_DRIVER is not set +# CONFIG_PKG_USING_STM32L0_CMSIS_DRIVER is not set +# CONFIG_PKG_USING_STM32L4_HAL_DRIVER is not set +# CONFIG_PKG_USING_STM32L4_CMSIS_DRIVER is not set +# CONFIG_PKG_USING_STM32L5_HAL_DRIVER is not set +# CONFIG_PKG_USING_STM32L5_CMSIS_DRIVER is not set +# CONFIG_PKG_USING_STM32U5_HAL_DRIVER is not set +# CONFIG_PKG_USING_STM32U5_CMSIS_DRIVER is not set +# CONFIG_PKG_USING_STM32WB55_SDK is not set +# CONFIG_PKG_USING_STM32_SDIO is not set +# CONFIG_PKG_USING_STM32WL_HAL_DRIVER is not set +# CONFIG_PKG_USING_STM32WL_CMSIS_DRIVER is not set +# CONFIG_PKG_USING_STM32WB_HAL_DRIVER is not set +# CONFIG_PKG_USING_STM32WB_CMSIS_DRIVER is not set +# CONFIG_PKG_USING_STM32MP1_M4_HAL_DRIVER is not set +# CONFIG_PKG_USING_STM32MP1_M4_CMSIS_DRIVER is not set +# end of STM32 HAL & SDK Drivers + +# +# Infineon HAL Packages +# +# CONFIG_PKG_USING_INFINEON_CAT1CM0P is not set +# CONFIG_PKG_USING_INFINEON_CMSIS is not set +# CONFIG_PKG_USING_INFINEON_CORE_LIB is not set +# CONFIG_PKG_USING_INFINEON_MTB_HAL_CAT1 is not set +# CONFIG_PKG_USING_INFINEON_MTB_PDL_CAT1 is not set +# CONFIG_PKG_USING_INFINEON_RETARGET_IO is not set +# CONFIG_PKG_USING_INFINEON_CAPSENSE is not set +# CONFIG_PKG_USING_INFINEON_CSDIDAC is not set +# CONFIG_PKG_USING_INFINEON_SERIAL_FLASH is not set +# CONFIG_PKG_USING_INFINEON_USBDEV is not set +# end of Infineon HAL Packages + +# CONFIG_PKG_USING_BLUETRUM_SDK is not set +# CONFIG_PKG_USING_EMBARC_BSP is not set +# CONFIG_PKG_USING_ESP_IDF is not set + +# +# Kendryte SDK +# +# CONFIG_PKG_USING_K210_SDK is not set +# CONFIG_PKG_USING_KENDRYTE_SDK is not set +# end of Kendryte SDK + +# CONFIG_PKG_USING_NRF5X_SDK is not set +# CONFIG_PKG_USING_NRFX is not set +# CONFIG_PKG_USING_NUCLEI_SDK is not set +# CONFIG_PKG_USING_RASPBERRYPI_PICO_RP2350_SDK is not set +# CONFIG_PKG_USING_RASPBERRYPI_PICO_SDK is not set + +# +# MM32 HAL & SDK Drivers +# +# CONFIG_PKG_USING_MM32F103XX_CMSIS is not set +# CONFIG_PKG_USING_MM32F3270X_CMSIS is not set +# CONFIG_PKG_USING_MM32F5260X_CMSIS is not set +# CONFIG_PKG_USING_MM32L0XX_CMSIS is not set +# CONFIG_PKG_USING_MM32L3XX_CMSIS is not set +# CONFIG_PKG_USING_MM32F103XX_HAL_DRIVER is not set +# CONFIG_PKG_USING_MM32F3270X_HAL_DRIVER is not set +# CONFIG_PKG_USING_MM32F5260X_HAL_DRIVER is not set +# CONFIG_PKG_USING_MM32L0XX_HAL_DRIVER is not set +# CONFIG_PKG_USING_MM32L3XX_HAL_DRIVER is not set +# end of MM32 HAL & SDK Drivers + +# +# WCH HAL & SDK Drivers +# +# CONFIG_PKG_USING_CH32V20x_SDK is not set +# CONFIG_PKG_USING_CH32V307_SDK is not set +# end of WCH HAL & SDK Drivers + +# +# AT32 HAL & SDK Drivers +# +# CONFIG_PKG_USING_AT32A403A_HAL_DRIVER is not set +# CONFIG_PKG_USING_AT32A403A_CMSIS_DRIVER is not set +# CONFIG_PKG_USING_AT32A423_HAL_DRIVER is not set +# CONFIG_PKG_USING_AT32A423_CMSIS_DRIVER is not set +# CONFIG_PKG_USING_AT32F45x_HAL_DRIVER is not set +# CONFIG_PKG_USING_AT32F45x_CMSIS_DRIVER is not set +# CONFIG_PKG_USING_AT32F402_405_HAL_DRIVER is not set +# CONFIG_PKG_USING_AT32F402_405_CMSIS_DRIVER is not set +# CONFIG_PKG_USING_AT32F403A_407_HAL_DRIVER is not set +# CONFIG_PKG_USING_AT32F403A_407_CMSIS_DRIVER is not set +# CONFIG_PKG_USING_AT32F413_HAL_DRIVER is not set +# CONFIG_PKG_USING_AT32F413_CMSIS_DRIVER is not set +# CONFIG_PKG_USING_AT32F415_HAL_DRIVER is not set +# CONFIG_PKG_USING_AT32F415_CMSIS_DRIVER is not set +# CONFIG_PKG_USING_AT32F421_HAL_DRIVER is not set +# CONFIG_PKG_USING_AT32F421_CMSIS_DRIVER is not set +# CONFIG_PKG_USING_AT32F423_HAL_DRIVER is not set +# CONFIG_PKG_USING_AT32F423_CMSIS_DRIVER is not set +# CONFIG_PKG_USING_AT32F425_HAL_DRIVER is not set +# CONFIG_PKG_USING_AT32F425_CMSIS_DRIVER is not set +# CONFIG_PKG_USING_AT32F435_437_HAL_DRIVER is not set +# CONFIG_PKG_USING_AT32F435_437_CMSIS_DRIVER is not set +# CONFIG_PKG_USING_AT32M412_416_HAL_DRIVER is not set +# CONFIG_PKG_USING_AT32M412_416_CMSIS_DRIVER is not set +# end of AT32 HAL & SDK Drivers + +# +# HC32 DDL Drivers +# +# CONFIG_PKG_USING_HC32F3_CMSIS_DRIVER is not set +# CONFIG_PKG_USING_HC32F3_SERIES_DRIVER is not set +# CONFIG_PKG_USING_HC32F4_CMSIS_DRIVER is not set +# CONFIG_PKG_USING_HC32F4_SERIES_DRIVER is not set +# end of HC32 DDL Drivers + +# +# NXP HAL & SDK Drivers +# +# CONFIG_PKG_USING_NXP_MCX_CMSIS_DRIVER is not set +# CONFIG_PKG_USING_NXP_MCX_SERIES_DRIVER is not set +# CONFIG_PKG_USING_NXP_LPC_DRIVER is not set +# CONFIG_PKG_USING_NXP_LPC55S_DRIVER is not set +# CONFIG_PKG_USING_NXP_IMX6SX_DRIVER is not set +# CONFIG_PKG_USING_NXP_IMX6UL_DRIVER is not set +# CONFIG_PKG_USING_NXP_IMXRT_DRIVER is not set +# end of NXP HAL & SDK Drivers + +# +# NUVOTON Drivers +# +# CONFIG_PKG_USING_NUVOTON_SERIES_DRIVER is not set +# end of NUVOTON Drivers + +# +# GD32 Drivers +# +# CONFIG_PKG_USING_GD32_ARM_CMSIS_DRIVER is not set +# CONFIG_PKG_USING_GD32_ARM_SERIES_DRIVER is not set +# CONFIG_PKG_USING_GD32_RISCV_SERIES_DRIVER is not set +# CONFIG_PKG_USING_GD32VW55X_WIFI is not set +# end of GD32 Drivers + +# +# HPMicro SDK +# +# CONFIG_PKG_USING_HPM_SDK is not set +# end of HPMicro SDK + +# +# FT32 HAL & SDK Drivers +# +# CONFIG_PKG_USING_FT32F0_STD_DRIVER is not set +# CONFIG_PKG_USING_FT32F0_CMSIS_DRIVER is not set +# CONFIG_PKG_USING_FT32F4_STD_DRIVER is not set +# CONFIG_PKG_USING_FT32F4_CMSIS_DRIVER is not set +# end of FT32 HAL & SDK Drivers + +# +# NOVOSNS Drivers +# +# CONFIG_PKG_USING_NOVOSNS_SERIES_DRIVER is not set +# end of NOVOSNS Drivers + +# +# N32 Drivers +# +# CONFIG_PKG_USING_N32H7XX_STD_DRIVER is not set +# CONFIG_PKG_USING_N32H7XX_CMSIS_DRIVER is not set +# CONFIG_PKG_USING_N32H49X_STD_DRIVER is not set +# CONFIG_PKG_USING_N32H49X_CMSIS_DRIVER is not set +# CONFIG_PKG_USING_N32H47X_48X_STD_DRIVER is not set +# CONFIG_PKG_USING_N32H47X_48X_CMSIS_DRIVER is not set +# end of N32 Drivers +# end of HAL & SDK Drivers + +# +# sensors drivers +# +# CONFIG_PKG_USING_LSM6DSM is not set +# CONFIG_PKG_USING_LSM6DSL is not set +# CONFIG_PKG_USING_LPS22HB is not set +# CONFIG_PKG_USING_HTS221 is not set +# CONFIG_PKG_USING_LSM303AGR is not set +# CONFIG_PKG_USING_BME280 is not set +# CONFIG_PKG_USING_BME680 is not set +# CONFIG_PKG_USING_BMA400 is not set +# CONFIG_PKG_USING_BMI160_BMX160 is not set +# CONFIG_PKG_USING_SPL0601 is not set +# CONFIG_PKG_USING_MS5805 is not set +# CONFIG_PKG_USING_DA270 is not set +# CONFIG_PKG_USING_DF220 is not set +# CONFIG_PKG_USING_HSHCAL001 is not set +# CONFIG_PKG_USING_BH1750 is not set +# CONFIG_PKG_USING_MPU6XXX is not set +# CONFIG_PKG_USING_AHT10 is not set +# CONFIG_PKG_USING_AP3216C is not set +# CONFIG_PKG_USING_TSL4531 is not set +# CONFIG_PKG_USING_DS18B20 is not set +# CONFIG_PKG_USING_DHT11 is not set +# CONFIG_PKG_USING_DHTXX is not set +# CONFIG_PKG_USING_GY271 is not set +# CONFIG_PKG_USING_GP2Y10 is not set +# CONFIG_PKG_USING_SGP30 is not set +# CONFIG_PKG_USING_HDC1000 is not set +# CONFIG_PKG_USING_BMP180 is not set +# CONFIG_PKG_USING_BMP280 is not set +# CONFIG_PKG_USING_SHTC1 is not set +# CONFIG_PKG_USING_BMI088 is not set +# CONFIG_PKG_USING_HMC5883 is not set +# CONFIG_PKG_USING_MAX6675 is not set +# CONFIG_PKG_USING_MAX31855 is not set +# CONFIG_PKG_USING_TMP1075 is not set +# CONFIG_PKG_USING_SR04 is not set +# CONFIG_PKG_USING_CCS811 is not set +# CONFIG_PKG_USING_PMSXX is not set +# CONFIG_PKG_USING_RT3020 is not set +# CONFIG_PKG_USING_MLX90632 is not set +# CONFIG_PKG_USING_MLX90382 is not set +# CONFIG_PKG_USING_MLX90384 is not set +# CONFIG_PKG_USING_MLX90393 is not set +# CONFIG_PKG_USING_MLX90392 is not set +# CONFIG_PKG_USING_MLX90394 is not set +# CONFIG_PKG_USING_MLX90396 is not set +# CONFIG_PKG_USING_MLX90397 is not set +# CONFIG_PKG_USING_MS5611 is not set +# CONFIG_PKG_USING_MAX31865 is not set +# CONFIG_PKG_USING_VL53L0X is not set +# CONFIG_PKG_USING_INA260 is not set +# CONFIG_PKG_USING_MAX30102 is not set +# CONFIG_PKG_USING_INA226 is not set +# CONFIG_PKG_USING_LIS2DH12 is not set +# CONFIG_PKG_USING_HS300X is not set +# CONFIG_PKG_USING_ZMOD4410 is not set +# CONFIG_PKG_USING_ISL29035 is not set +# CONFIG_PKG_USING_MMC3680KJ is not set +# CONFIG_PKG_USING_QMP6989 is not set +# CONFIG_PKG_USING_BALANCE is not set +# CONFIG_PKG_USING_SHT2X is not set +# CONFIG_PKG_USING_SHT3X is not set +# CONFIG_PKG_USING_SHT4X is not set +# CONFIG_PKG_USING_AD7746 is not set +# CONFIG_PKG_USING_ADT74XX is not set +# CONFIG_PKG_USING_MAX17048 is not set +# CONFIG_PKG_USING_AS7341 is not set +# CONFIG_PKG_USING_CW2015 is not set +# CONFIG_PKG_USING_ICM20608 is not set +# CONFIG_PKG_USING_PAJ7620 is not set +# CONFIG_PKG_USING_STHS34PF80 is not set +# CONFIG_PKG_USING_P3T1755 is not set +# CONFIG_PKG_USING_QMI8658 is not set +# CONFIG_PKG_USING_ICM20948 is not set +# CONFIG_PKG_USING_SCD4X is not set +# end of sensors drivers + +# +# touch drivers +# +# CONFIG_PKG_USING_GT9147 is not set +# CONFIG_PKG_USING_GT1151 is not set +# CONFIG_PKG_USING_GT917S is not set +# CONFIG_PKG_USING_GT911 is not set +# CONFIG_PKG_USING_FT6206 is not set +# CONFIG_PKG_USING_FT5426 is not set +# CONFIG_PKG_USING_FT6236 is not set +# CONFIG_PKG_USING_XPT2046_TOUCH is not set +# CONFIG_PKG_USING_CST816X is not set +# CONFIG_PKG_USING_CST812T is not set +# end of touch drivers + +# CONFIG_PKG_USING_LCD_SPI_DRIVER is not set +# CONFIG_PKG_USING_REALTEK_AMEBA is not set +# CONFIG_PKG_USING_BUTTON is not set +# CONFIG_PKG_USING_PCF8574 is not set +# CONFIG_PKG_USING_SX12XX is not set +# CONFIG_PKG_USING_SIGNAL_LED is not set +# CONFIG_PKG_USING_LEDBLINK is not set +# CONFIG_PKG_USING_LITTLED is not set +# CONFIG_PKG_USING_LKDGUI is not set +# CONFIG_PKG_USING_INFRARED is not set +# CONFIG_PKG_USING_MULTI_INFRARED is not set +# CONFIG_PKG_USING_AGILE_BUTTON is not set +# CONFIG_PKG_USING_AGILE_LED is not set +# CONFIG_PKG_USING_AT24CXX is not set +# CONFIG_PKG_USING_MOTIONDRIVER2RTT is not set +# CONFIG_PKG_USING_PCA9685 is not set +# CONFIG_PKG_USING_ILI9341 is not set +# CONFIG_PKG_USING_I2C_TOOLS is not set +# CONFIG_PKG_USING_NRF24L01 is not set +# CONFIG_PKG_USING_RPLIDAR is not set +# CONFIG_PKG_USING_AS608 is not set +# CONFIG_PKG_USING_RC522 is not set +# CONFIG_PKG_USING_WS2812B is not set +# CONFIG_PKG_USING_EXTERN_RTC_DRIVERS is not set +# CONFIG_PKG_USING_MULTI_RTIMER is not set +# CONFIG_PKG_USING_MAX7219 is not set +# CONFIG_PKG_USING_BEEP is not set +# CONFIG_PKG_USING_EASYBLINK is not set +# CONFIG_PKG_USING_PMS_SERIES is not set +# CONFIG_PKG_USING_CAN_YMODEM is not set +# CONFIG_PKG_USING_LORA_RADIO_DRIVER is not set +# CONFIG_PKG_USING_QLED is not set +# CONFIG_PKG_USING_AGILE_CONSOLE is not set +# CONFIG_PKG_USING_LD3320 is not set +# CONFIG_PKG_USING_WK2124 is not set +# CONFIG_PKG_USING_LY68L6400 is not set +# CONFIG_PKG_USING_DM9051 is not set +# CONFIG_PKG_USING_CH390 is not set +# CONFIG_PKG_USING_SSD1306 is not set +# CONFIG_PKG_USING_QKEY is not set +# CONFIG_PKG_USING_RS485 is not set +# CONFIG_PKG_USING_RS232 is not set +# CONFIG_PKG_USING_NES is not set +# CONFIG_PKG_USING_VIRTUAL_SENSOR is not set +# CONFIG_PKG_USING_VDEVICE is not set +# CONFIG_PKG_USING_SGM706 is not set +# CONFIG_PKG_USING_RDA58XX is not set +# CONFIG_PKG_USING_LIBNFC is not set +# CONFIG_PKG_USING_MFOC is not set +# CONFIG_PKG_USING_TMC51XX is not set +# CONFIG_PKG_USING_TCA9534 is not set +# CONFIG_PKG_USING_KOBUKI is not set +# CONFIG_PKG_USING_ROSSERIAL is not set +# CONFIG_PKG_USING_MICRO_ROS is not set +# CONFIG_PKG_USING_MCP23008 is not set +# CONFIG_PKG_USING_MISAKA_AT24CXX is not set +# CONFIG_PKG_USING_MISAKA_RGB_BLING is not set +# CONFIG_PKG_USING_LORA_MODEM_DRIVER is not set +# CONFIG_PKG_USING_SOFT_SERIAL is not set +# CONFIG_PKG_USING_MB85RS16 is not set +# CONFIG_PKG_USING_RFM300 is not set +# CONFIG_PKG_USING_IO_INPUT_FILTER is not set +# CONFIG_PKG_USING_LRF_NV7LIDAR is not set +# CONFIG_PKG_USING_AIP650 is not set +# CONFIG_PKG_USING_FINGERPRINT is not set +# CONFIG_PKG_USING_BT_ECB02C is not set +# CONFIG_PKG_USING_UAT is not set +# CONFIG_PKG_USING_ST7789 is not set +# CONFIG_PKG_USING_VS1003 is not set +# CONFIG_PKG_USING_X9555 is not set +# CONFIG_PKG_USING_SYSTEM_RUN_LED is not set +# CONFIG_PKG_USING_BT_MX01 is not set +# CONFIG_PKG_USING_RGPOWER is not set +# CONFIG_PKG_USING_BT_MX02 is not set +# CONFIG_PKG_USING_GC9A01 is not set +# CONFIG_PKG_USING_IK485 is not set +# CONFIG_PKG_USING_SERVO is not set +# CONFIG_PKG_USING_SEAN_WS2812B is not set +# CONFIG_PKG_USING_IC74HC165 is not set +# CONFIG_PKG_USING_IST8310 is not set +# CONFIG_PKG_USING_ST7789_SPI is not set +# CONFIG_PKG_USING_CAN_UDS is not set +# CONFIG_PKG_USING_ISOTP_C is not set +# CONFIG_PKG_USING_IKUNLED is not set +# CONFIG_PKG_USING_INS5T8025 is not set +# CONFIG_PKG_USING_IRUART is not set +# CONFIG_PKG_USING_ST7305 is not set +# CONFIG_PKG_USING_TM1668 is not set +# CONFIG_PKG_USING_TCA9548A is not set +# CONFIG_PKG_USING_SPI_TOOLS is not set +# end of peripheral libraries and drivers + +# +# AI packages +# +# CONFIG_PKG_USING_LIBANN is not set +# CONFIG_PKG_USING_NNOM is not set +# CONFIG_PKG_USING_ONNX_BACKEND is not set +# CONFIG_PKG_USING_ONNX_PARSER is not set +# CONFIG_PKG_USING_TENSORFLOWLITEMICRO is not set +# CONFIG_PKG_USING_ELAPACK is not set +# CONFIG_PKG_USING_ULAPACK is not set +# CONFIG_PKG_USING_QUEST is not set +# CONFIG_PKG_USING_NAXOS is not set +# CONFIG_PKG_USING_R_TINYMAIX is not set +# CONFIG_PKG_USING_LLMCHAT is not set +# CONFIG_PKG_USING_AIFES is not set +# CONFIG_PKG_USING_AGENT is not set +# end of AI packages + +# +# Signal Processing and Control Algorithm Packages +# +# CONFIG_PKG_USING_APID is not set +# CONFIG_PKG_USING_FIRE_PID_CURVE is not set +# CONFIG_PKG_USING_QPID is not set +# CONFIG_PKG_USING_UKAL is not set +# CONFIG_PKG_USING_DIGITALCTRL is not set +# CONFIG_PKG_USING_KISSFFT is not set +# end of Signal Processing and Control Algorithm Packages + +# +# miscellaneous packages +# + +# +# project laboratory +# +# end of project laboratory + +# +# samples: kernel and components samples +# +# CONFIG_PKG_USING_KERNEL_SAMPLES is not set +# CONFIG_PKG_USING_FILESYSTEM_SAMPLES is not set +# CONFIG_PKG_USING_NETWORK_SAMPLES is not set +# CONFIG_PKG_USING_PERIPHERAL_SAMPLES is not set +# end of samples: kernel and components samples + +# +# entertainment: terminal games and other interesting software packages +# +# CONFIG_PKG_USING_CMATRIX is not set +# CONFIG_PKG_USING_SL is not set +# CONFIG_PKG_USING_CAL is not set +# CONFIG_PKG_USING_ACLOCK is not set +# CONFIG_PKG_USING_THREES is not set +# CONFIG_PKG_USING_2048 is not set +# CONFIG_PKG_USING_SNAKE is not set +# CONFIG_PKG_USING_TETRIS is not set +# CONFIG_PKG_USING_DONUT is not set +# CONFIG_PKG_USING_COWSAY is not set +# CONFIG_PKG_USING_MORSE is not set +# end of entertainment: terminal games and other interesting software packages + +# CONFIG_PKG_USING_LIBCSV is not set +# CONFIG_PKG_USING_OPTPARSE is not set +# CONFIG_PKG_USING_FASTLZ is not set +# CONFIG_PKG_USING_MINILZO is not set +# CONFIG_PKG_USING_QUICKLZ is not set +# CONFIG_PKG_USING_LZMA is not set +# CONFIG_PKG_USING_RALARAM is not set +# CONFIG_PKG_USING_MULTIBUTTON is not set +# CONFIG_PKG_USING_FLEXIBLE_BUTTON is not set +# CONFIG_PKG_USING_CANFESTIVAL is not set +# CONFIG_PKG_USING_ZLIB is not set +# CONFIG_PKG_USING_MINIZIP is not set +# CONFIG_PKG_USING_HEATSHRINK is not set +# CONFIG_PKG_USING_DSTR is not set +# CONFIG_PKG_USING_TINYFRAME is not set +# CONFIG_PKG_USING_KENDRYTE_DEMO is not set +# CONFIG_PKG_USING_UPACKER is not set +# CONFIG_PKG_USING_UPARAM is not set +# CONFIG_PKG_USING_HELLO is not set +# CONFIG_PKG_USING_VI is not set +# CONFIG_PKG_USING_KI is not set +# CONFIG_PKG_USING_ARMv7M_DWT is not set +# CONFIG_PKG_USING_CRCLIB is not set +# CONFIG_PKG_USING_LIBCRC is not set +# CONFIG_PKG_USING_LWGPS is not set +# CONFIG_PKG_USING_STATE_MACHINE is not set +# CONFIG_PKG_USING_DESIGN_PATTERN is not set +# CONFIG_PKG_USING_CONTROLLER is not set +# CONFIG_PKG_USING_PHASE_LOCKED_LOOP is not set +# CONFIG_PKG_USING_MFBD is not set +# CONFIG_PKG_USING_SLCAN2RTT is not set +# CONFIG_PKG_USING_SOEM is not set +# CONFIG_PKG_USING_QPARAM is not set +# CONFIG_PKG_USING_CorevMCU_CLI is not set +# CONFIG_PKG_USING_DRMP is not set +# CONFIG_PKG_USING_AUTOGEN_PARAMETER_MANAGER is not set +# end of miscellaneous packages + +# +# Arduino libraries +# +# CONFIG_PKG_USING_RTDUINO is not set + +# +# Projects and Demos +# +# CONFIG_PKG_USING_ARDUINO_MSGQ_C_CPP_DEMO is not set +# CONFIG_PKG_USING_ARDUINO_SKETCH_LOADER_DEMO is not set +# CONFIG_PKG_USING_ARDUINO_ULTRASOUND_RADAR is not set +# CONFIG_PKG_USING_ARDUINO_RTDUINO_SENSORFUSION_SHIELD is not set +# CONFIG_PKG_USING_ARDUINO_NINEINONE_SENSOR_SHIELD is not set +# CONFIG_PKG_USING_ARDUINO_SENSOR_KIT is not set +# CONFIG_PKG_USING_ARDUINO_MATLAB_SUPPORT is not set +# end of Projects and Demos + +# +# Sensors +# +# CONFIG_PKG_USING_ARDUINO_SENSOR_DEVICE_DRIVERS is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_SENSOR is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_SENSORLAB is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_ADXL375 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_VL53L0X is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_VL53L1X is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_VL6180X is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MAX31855 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MAX31865 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MAX31856 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MAX6675 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MLX90614 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_LSM9DS1 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_AHTX0 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_LSM9DS0 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_BMP280 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_ADT7410 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_BMP085 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_BME680 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MCP9808 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MCP4728 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_INA219 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_LTR390 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_ADXL345 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_DHT is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MCP9600 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_LSM6DS is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_BNO055 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MAX1704X is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MMC56X3 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MLX90393 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MLX90395 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_ICM20X is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_DPS310 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_HTS221 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_SHT4X is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_SHT31 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_ADXL343 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_BME280 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_AS726X is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_AMG88XX is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_AM2320 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_AM2315 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_LTR329_LTR303 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_BMP085_UNIFIED is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_BMP183 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_BMP183_UNIFIED is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_BMP3XX is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MS8607 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_LIS3MDL is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MLX90640 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MMA8451 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MSA301 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MPL115A2 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_BNO08X is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_BNO08X_RVC is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_LIS2MDL is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_LSM303DLH_MAG is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_LC709203F is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_CAP1188 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_CCS811 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_NAU7802 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_LIS331 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_LPS2X is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_LPS35HW is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_LSM303_ACCEL is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_LIS3DH is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_PCF8591 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MPL3115A2 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MPR121 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MPRLS is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MPU6050 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_PCT2075 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_PM25AQI is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_EMC2101 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_FXAS21002C is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_SCD30 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_FXOS8700 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_HMC5883_UNIFIED is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_SGP30 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_TMP006 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_TLA202X is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_TCS34725 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_SI7021 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_SI1145 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_SGP40 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_SHTC3 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_HDC1000 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_HTU21DF is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_AS7341 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_HTU31D is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_INA260 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_TMP007_LIBRARY is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_L3GD20 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_TMP117 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_TSC2007 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_TSL2561 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_TSL2591_LIBRARY is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_VCNL4040 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_VEML6070 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_VEML6075 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_VEML7700 is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_LIS3DHTR is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_DHT is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_ADXL335 is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_ADXL345 is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_BME280 is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_BMP280 is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_H3LIS331DL is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_MMA7660 is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_TSL2561 is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_PAJ7620 is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_VL53L0X is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_ITG3200 is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_SHT31 is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_HP20X is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_DRV2605L is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_BBM150 is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_HMC5883L is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_LSM303DLH is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_TCS3414CS is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_MP503 is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_BMP085 is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_HIGHTEMP is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_VEML6070 is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_SI1145 is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_SHT35 is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_AT42QT1070 is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_LSM6DS3 is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_HDC1000 is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_HM3301 is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_MCP9600 is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_LTC2941 is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_LDC1612 is not set +# CONFIG_PKG_USING_ARDUINO_CAPACITIVESENSOR is not set +# CONFIG_PKG_USING_ARDUINO_JARZEBSKI_MPU6050 is not set +# end of Sensors + +# +# Display +# +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_GFX_LIBRARY is not set +# CONFIG_PKG_USING_ARDUINO_U8G2 is not set +# CONFIG_PKG_USING_ARDUINO_TFT_ESPI is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_ST7735 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_SSD1306 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_ILI9341 is not set +# CONFIG_PKG_USING_SEEED_TM1637 is not set +# end of Display + +# +# Timing +# +# CONFIG_PKG_USING_ARDUINO_RTCLIB is not set +# CONFIG_PKG_USING_ARDUINO_MSTIMER2 is not set +# CONFIG_PKG_USING_ARDUINO_TICKER is not set +# CONFIG_PKG_USING_ARDUINO_TASKSCHEDULER is not set +# end of Timing + +# +# Data Processing +# +# CONFIG_PKG_USING_ARDUINO_KALMANFILTER is not set +# CONFIG_PKG_USING_ARDUINO_ARDUINOJSON is not set +# CONFIG_PKG_USING_ARDUINO_TENSORFLOW_LITE_MICRO is not set +# CONFIG_PKG_USING_ARDUINO_RUNNINGMEDIAN is not set +# end of Data Processing + +# +# Data Storage +# + +# +# Communication +# +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_PN532 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_SI4713 is not set +# end of Communication + +# +# Device Control +# +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_PCF8574 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_PCA9685 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_TPA2016 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_DRV2605 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_DS1841 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_DS3502 is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_PCF85063TP is not set +# end of Device Control + +# +# Other +# +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MFRC630 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_SI5351 is not set +# end of Other + +# +# Signal IO +# +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_BUSIO is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_TCA8418 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MCP23017 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_ADS1X15 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_AW9523 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MCP3008 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MCP4725 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_BD3491FS is not set +# end of Signal IO + +# +# Uncategorized +# +# end of Arduino libraries +# end of RT-Thread online packages + +CONFIG_SOC_SPACEMIT_K1=y diff --git a/bsp/spacemit/k1/.gitignore b/bsp/spacemit/k1/.gitignore new file mode 100644 index 000000000000..d7cc9e21eb56 --- /dev/null +++ b/bsp/spacemit/k1/.gitignore @@ -0,0 +1,8 @@ +__pycache__/ +build/ +*.bin +*.elf +!drivers/esos.elf +*.map +*.old +.sconsign.dblite diff --git a/bsp/spacemit/k1/Kconfig b/bsp/spacemit/k1/Kconfig new file mode 100644 index 000000000000..3b10d0d775a9 --- /dev/null +++ b/bsp/spacemit/k1/Kconfig @@ -0,0 +1,27 @@ +mainmenu "RT-Thread Project Configuration" + +BSP_DIR := . + +RTT_DIR := ../../.. + +PKGS_DIR := packages + +SOC_DM_DIR := $BSP_DIR/../dm/ + +source "$(SOC_DM_DIR)/Kconfig" +source "$(RTT_DIR)/Kconfig" +osource "$PKGS_DIR/Kconfig" + +config SOC_SPACEMIT_K1 + bool + select ARCH_RISCV64 + select RT_USING_RISCV_NEW_COMMON + select RT_USING_COMPONENTS_INIT + select RT_USING_USER_MAIN + select RT_USING_CACHE + select ARCH_MM_MMU + select ARCH_REMAP_KERNEL if RT_USING_SMART + select ARCH_RISCV_FPU_D + select RT_USING_CPU_FFS + select RT_USING_STDC_ATOMIC + default y diff --git a/bsp/spacemit/k1/README.md b/bsp/spacemit/k1/README.md new file mode 100644 index 000000000000..125117a7daed --- /dev/null +++ b/bsp/spacemit/k1/README.md @@ -0,0 +1,185 @@ +ifconfig e0 192.168.10.2 192.168.10.1 255.255.255.0 +ping 192.168.10.1 + +[English](README_en.md) | **中文** + +# SpacemiT K1 BSP + +## 1. 简介 + +本 BSP 将 RT-Thread 标准版移植到 SpacemiT K1 64 位 RISC-V SoC。当前启动方式仅在 +**Banana Pi BPI-F3 SBC** 上验证,依赖开发板原厂 U-Boot/OpenSBI 和其动态选择的 +Device Tree。 + +默认配置使用 MMU 并启动 4 个 CPU,从 S-mode 运行 RT-Thread。早期控制台使用 +SBI,正常串口为 `ttyS0`,参数为 115200 8N1。 + +## 2. 支持情况 + +| 功能 | 状态 | 说明 | +| --- | --- | --- | +| RISC-V MMU / SMP | 支持 | 默认启动 4 个 CPU | +| UART / early console | 支持 | SBI early console,8250/PXA UART | +| Clock / reset / power domain | 支持 | K1 CCU、reset 和 PM domain | +| I2C / SPI / QSPI / PWM | 支持 | 包含 PMIC 子设备 | +| SD / eMMC | 支持 | SDHCI,eMMC HS400 | +| RTC / ADC / power key | 支持 | SpacemiT PMIC | +| PCIe / NVMe | 支持 | DesignWare PCIe host | +| Ethernet / PTP | 支持 | K1X EMAC;需启用 `RT_USING_ETHERNET` 和 `RT_ETHERNET_K1X_EMAC` | +| HDMI framebuffer | 支持 | 冷启动建立 HDMI 显示链路 | +| JPU / V2D | 支持 | JPEG 解码和 2D 加速 | +| HDMI / ES8326 audio | 支持 | 48 kHz、双声道、16-bit PCM | +| DVFS / thermal | 支持 | CPUfreq、OPP 和 4 路温度区 | +| AES / hardware RNG / eFuse | 支持 | 包含 SoC ID 和序列号 | +| MIPI DSI / camera / USB | 未移植 | 当前 BSP 不包含这些功能 | + +## 3. 构建环境 + +### 3.1 依赖 + +建议使用 64 位 Linux 主机。Ubuntu/Debian 可安装: + +```shell +sudo apt install scons python3 python3-pip +pip3 install kconfiglib +``` + +### 3.2 工具链 + +可从以下地址获取 RISC-V64 Linux musl GCC 工具链: + +- SpacemiT 官方工具链归档: +- RT-Thread RISC-V64 musl 工具链: + +以解压到 `/opt/riscv64-linux-musleabi_for_x86_64-pc-linux-gnu` 为例: + +```shell +export RTT_CC=gcc +export RTT_EXEC_PATH=/opt/riscv64-linux-musleabi_for_x86_64-pc-linux-gnu/bin +export RTT_CC_PREFIX=riscv64-unknown-linux-musl- +``` + +可使用下列命令检查工具链: + +```shell +${RTT_EXEC_PATH}/${RTT_CC_PREFIX}gcc --version +``` + +## 4. 编译 + +进入 BSP 目录: + +```shell +cd bsp/spacemit/k1 +``` + +需要调整功能时先运行: + +```shell +scons --menuconfig +``` + +编译: + +```shell +scons -j$(nproc) +``` + +编译成功后会生成: + +| 文件 | 用途 | +| --- | --- | +| `rtthread.elf` | 带调试信息的 ELF 文件 | +| `rtthread.bin` | U-Boot 加载的内核镜像 | +| `rtthread.map` | 链接 map | + +清理构建产物: + +```shell +scons -c +``` + +## 5. Banana Pi BPI-F3 启动 + +> 本节命令仅适用于 Banana Pi BPI-F3 原厂 U-Boot 环境。其他 K1 开发板的分区、 +> Device Tree 和 U-Boot 环境变量可能不同。 + +### 5.1 准备镜像 + +将 `rtthread.bin` 放到 BPI-F3 启动文件系统根目录,即与 Linux `Image` 和 +`k1-x_*.dtb` 相同的目录。U-Boot 的 `loadknl` 命令会从当前启动文件系统加载 +`knl_name` 指定的文件。 + +### 5.2 配置 U-Boot + +在 U-Boot 控制台执行以下命令: + +```shell +setenv rtt_bootargs 'earlycon=sbi console=ttyS0,115200 cma=32M coherent_pool=8M root=sd0p4 rootfstype=elm rootwait rw' +setenv boot_rtt 'setenv knl_name rtthread.bin; setenv bootargs ${rtt_bootargs}; run detect_dtb; run loadknl; run loaddtb; setenv ramdisk_combo -; run start_kernel' +saveenv +``` + +`saveenv` 只需执行一次。之后可使用以下命令启动 RT-Thread: + +```shell +run boot_rtt +``` + +主要 bootargs 说明: + +- `earlycon=sbi`:在正常 UART 驱动就绪前使用 SBI 输出。 +- `cma=32M coherent_pool=8M`:为 framebuffer、JPU、V2D、NVMe 和其他 DMA 设备预留内存。 +- `root=sd0p4 rootfstype=elm`:将 RT-Thread 设备 `sd0p4` 上的 FAT 文件系统作为根文件系统。 + +如果存储设备的枚举顺序或分区布局不同,需要相应修改 `root=`。原厂 U-Boot +必须存在 `detect_dtb`、`loadknl`、`loaddtb` 和 `start_kernel` 这几个环境命令。 + +### 5.3 启动输出 + +启动成功后串口将显示: + +```text + \ | / +- RT - Thread Operating System + / | \ + ... +msh /> +``` + +## 6. 常用验证命令 + +```shell +list_device +list_irq +list_blk +list_thermal +list_dvfs +dvfs dump cpufreq0 +core_mark +adc probe adc0 +adc read 0 +date +jpu_show /path/to/image.jpg fb0 +v2d_test fb0 +audio_test snd-hdmi 2 +ptp_test +``` + +`jpu_show` 仅从文件系统读取 baseline JPEG,BSP 不内置测试图片。 + +使用网卡前请先在 `menuconfig` 中启用 Ethernet 和 K1X EMAC,然后根据实际端口 +`e0` 或 `e1` 配置地址: + +```shell +ifconfig e1 192.168.10.2 192.168.10.1 255.255.255.0 +ping 192.168.10.1 e1 +``` + +## 7. 注意事项 + +- Device Tree 由 BPI-F3 U-Boot 的 `detect_dtb` 选择,不要使用与开发板不匹配的 DTB。 +- HDMI 显示依赖 `cma` 和 `coherent_pool`;内存过小时 framebuffer 初始化会失败。 +- HDMI ADMA 依赖嵌入镜像的 K1 RCPU `esos.elf` 和 Device Tree 中的 reserved-memory。 +- MIPI 显示未验证,当前显示驱动仅面向 HDMI。 + diff --git a/bsp/spacemit/k1/README_en.md b/bsp/spacemit/k1/README_en.md new file mode 100644 index 000000000000..b1ddcf7650be --- /dev/null +++ b/bsp/spacemit/k1/README_en.md @@ -0,0 +1,193 @@ +**English** | [中文](README.md) + +# SpacemiT K1 BSP + +## 1. Introduction + +This BSP ports the RT-Thread standard edition to the SpacemiT K1 64-bit +RISC-V SoC. The boot procedure is currently validated only on the +**Banana Pi BPI-F3 SBC**. It relies on the vendor U-Boot/OpenSBI firmware and +the Device Tree selected by U-Boot. + +The default configuration enables the MMU and starts four CPUs. RT-Thread +runs in S-mode. The early console uses SBI, while the normal console is +`ttyS0` at 115200 baud, 8 data bits, no parity, and 1 stop bit. + +## 2. Supported Features + +| Feature | Status | Notes | +| --- | --- | --- | +| RISC-V MMU / SMP | Supported | Four CPUs are enabled by default | +| UART / early console | Supported | SBI early console and 8250/PXA UART | +| Clock / reset / power domain | Supported | K1 CCU, reset, and PM domain | +| I2C / SPI / QSPI / PWM | Supported | Includes PMIC child devices | +| SD / eMMC | Supported | SDHCI and eMMC HS400 | +| RTC / ADC / power key | Supported | SpacemiT PMIC | +| PCIe / NVMe | Supported | DesignWare PCIe host | +| Ethernet / PTP | Supported | Enable `RT_USING_ETHERNET` and `RT_ETHERNET_K1X_EMAC` | +| HDMI framebuffer | Supported | Initializes the HDMI display path from a cold boot | +| JPU / V2D | Supported | JPEG decoding and 2D acceleration | +| HDMI / ES8326 audio | Supported | 48 kHz, stereo, 16-bit PCM | +| DVFS / thermal | Supported | CPUfreq, OPP, and four thermal zones | +| AES / hardware RNG / eFuse | Supported | Includes SoC ID and serial number | +| MIPI DSI / camera / USB | Not ported | These functions are not included in this BSP | + +## 3. Build Environment + +### 3.1 Dependencies + +A 64-bit Linux host is recommended. On Ubuntu or Debian, install: + +```shell +sudo apt install scons python3 python3-pip +pip3 install kconfiglib +``` + +### 3.2 Toolchain + +A RISC-V64 Linux musl GCC toolchain can be obtained from: + +- SpacemiT toolchain archive: +- RT-Thread RISC-V64 musl toolchain: + +The following example assumes that the toolchain is extracted to +`/opt/riscv64-linux-musleabi_for_x86_64-pc-linux-gnu`: + +```shell +export RTT_CC=gcc +export RTT_EXEC_PATH=/opt/riscv64-linux-musleabi_for_x86_64-pc-linux-gnu/bin +export RTT_CC_PREFIX=riscv64-unknown-linux-musl- +``` + +Verify the toolchain with: + +```shell +${RTT_EXEC_PATH}/${RTT_CC_PREFIX}gcc --version +``` + +## 4. Build + +Enter the BSP directory: + +```shell +cd bsp/spacemit/k1 +``` + +To change the configuration, run: + +```shell +scons --menuconfig +``` + +Build the BSP: + +```shell +scons -j$(nproc) +``` + +A successful build generates: + +| File | Description | +| --- | --- | +| `rtthread.elf` | ELF image with debug information | +| `rtthread.bin` | Kernel image loaded by U-Boot | +| `rtthread.map` | Linker map | + +Clean the build output with: + +```shell +scons -c +``` + +## 5. Boot on Banana Pi BPI-F3 + +> The commands in this section apply only to the vendor U-Boot environment +> on the Banana Pi BPI-F3. Other K1 boards may use different partitions, +> Device Trees, and U-Boot variables. + +### 5.1 Install the Image + +Place `rtthread.bin` in the root of the BPI-F3 boot filesystem, next to the +Linux `Image` file and the `k1-x_*.dtb` files. The U-Boot `loadknl` command +loads the file specified by `knl_name` from the active boot filesystem. + +### 5.2 Configure U-Boot + +Run the following commands from the U-Boot console: + +```shell +setenv rtt_bootargs 'earlycon=sbi console=ttyS0,115200 cma=32M coherent_pool=8M root=sd0p4 rootfstype=elm rootwait rw' +setenv boot_rtt 'setenv knl_name rtthread.bin; setenv bootargs ${rtt_bootargs}; run detect_dtb; run loadknl; run loaddtb; setenv ramdisk_combo -; run start_kernel' +saveenv +``` + +`saveenv` is only required once. Boot RT-Thread with: + +```shell +run boot_rtt +``` + +Important boot arguments: + +- `earlycon=sbi` provides output before the normal UART driver is ready. +- `cma=32M coherent_pool=8M` reserves memory for the framebuffer, JPU, V2D, + NVMe, and other DMA devices. +- `root=sd0p4 rootfstype=elm` mounts the FAT filesystem on the RT-Thread + `sd0p4` device as the root filesystem. + +Change `root=` if the storage enumeration order or partition layout differs. +The vendor U-Boot environment must provide the `detect_dtb`, `loadknl`, +`loaddtb`, and `start_kernel` commands. + +### 5.3 Expected Output + +After a successful boot, the serial console displays: + +```text + \ | / +- RT - Thread Operating System + / | \ + ... +msh /> +``` + +## 6. Validation Commands + +```shell +list_device +list_irq +list_blk +list_thermal +list_dvfs +dvfs dump cpufreq0 +core_mark +adc probe adc0 +adc read 0 +date +jpu_show /path/to/image.jpg fb0 +v2d_test fb0 +audio_test snd-hdmi 2 +ptp_test +``` + +`jpu_show` reads a baseline JPEG from the filesystem. No test image is +embedded in the BSP. + +Before using Ethernet, enable Ethernet and the K1X EMAC in `menuconfig`. +Then configure the actual interface, `e0` or `e1`, for example: + +```shell +ifconfig e1 192.168.10.2 192.168.10.1 255.255.255.0 +ping 192.168.10.1 e1 +``` + +## 7. Notes + +- The Device Tree is selected by the BPI-F3 U-Boot `detect_dtb` command. Do + not use a DTB for a different board. +- HDMI display requires the `cma` and `coherent_pool` reservations. The + framebuffer may fail to initialize if either pool is too small. +- HDMI ADMA requires the embedded K1 RCPU `esos.elf` firmware and the + reserved-memory regions in the Device Tree. +- MIPI display is not validated. The current display driver targets HDMI. + diff --git a/bsp/spacemit/k1/SConscript b/bsp/spacemit/k1/SConscript new file mode 100644 index 000000000000..40e1864cf613 --- /dev/null +++ b/bsp/spacemit/k1/SConscript @@ -0,0 +1,16 @@ +# for module compiling +import os +from building import * + +cwd = GetCurrentDir() +objs = [] +list = os.listdir(cwd) + +for d in list: + path = os.path.join(cwd, d) + if os.path.isfile(os.path.join(path, 'SConscript')): + objs = objs + SConscript(os.path.join(d, 'SConscript')) + +objs = objs + SConscript(cwd + '/../dm/SConscript', variant_dir = 'dm', duplicate = 0) + +Return('objs') diff --git a/bsp/spacemit/k1/SConstruct b/bsp/spacemit/k1/SConstruct new file mode 100644 index 000000000000..cf25bd5ecc32 --- /dev/null +++ b/bsp/spacemit/k1/SConstruct @@ -0,0 +1,29 @@ +import os +import sys +import rtconfig + +from rtconfig import RTT_ROOT + +sys.path = sys.path + [os.path.join(RTT_ROOT, 'tools')] +from building import * + +TARGET = 'rtthread.' + rtconfig.TARGET_EXT + +DefaultEnvironment(tools=[]) +env = Environment(tools = ['mingw'], + AS = rtconfig.AS, ASFLAGS = rtconfig.AFLAGS, + CC = rtconfig.CC, CCFLAGS = rtconfig.CFLAGS, + CXX = rtconfig.CXX, CXXFLAGS = rtconfig.CXXFLAGS, + AR = rtconfig.AR, ARFLAGS = '-rc', + LINK = rtconfig.LINK, LINKFLAGS = rtconfig.LFLAGS) +env.PrependENVPath('PATH', rtconfig.EXEC_PATH) +env['ASCOM'] = env['ASPPCOM'] + +Export('RTT_ROOT') +Export('rtconfig') + +# prepare building environment +objs = PrepareBuilding(env, RTT_ROOT, has_libcpu = False) + +# make a building +DoBuilding(TARGET, objs) diff --git a/bsp/spacemit/k1/applications/SConscript b/bsp/spacemit/k1/applications/SConscript new file mode 100644 index 000000000000..c0653a14cca6 --- /dev/null +++ b/bsp/spacemit/k1/applications/SConscript @@ -0,0 +1,9 @@ +from building import * + +cwd = GetCurrentDir() +src = Glob('*.c') + Glob('*.cpp') + Glob('*.S') +CPPPATH = [cwd] + +group = DefineGroup('Applications', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/spacemit/k1/applications/audio.c b/bsp/spacemit/k1/applications/audio.c new file mode 100644 index 000000000000..a92847cc6abb --- /dev/null +++ b/bsp/spacemit/k1/applications/audio.c @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#include +#include + +#if defined(RT_USING_AUDIO) && defined(RT_AUDIO_SPACEMIT) && defined(RT_USING_FINSH) +#include +#include + +#define AUDIO_TEST_RATE 48000U +#define AUDIO_TEST_CHANNELS 2U +#define AUDIO_TEST_BITS 16U +#define AUDIO_TEST_BUFFER_SIZE 4096U +#define AUDIO_TEST_DEFAULT_SECONDS 2U +#define AUDIO_TEST_MAX_SECONDS 30U + +static const rt_int16_t audio_test_sine[] = +{ + 0, 2139, 4240, 6269, 8192, 9974, 11585, 12998, + 14189, 15136, 15825, 16244, 16384, 16244, 15825, 15136, + 14189, 12998, 11585, 9974, 8192, 6269, 4240, 2139, + 0, -2139, -4240, -6269, -8192, -9974,-11585,-12998, + -14189,-15136,-15825,-16244,-16384,-16244,-15825,-15136, + -14189,-12998,-11585, -9974, -8192, -6269, -4240, -2139, +}; + +static int audio_test(int argc, char **argv) +{ + int ret = -RT_ERROR; + rt_uint32_t phase = 0; + rt_uint32_t seconds = AUDIO_TEST_DEFAULT_SECONDS; + rt_size_t remaining; + rt_device_t device; + rt_int16_t *buffer; + const char *name = "snd-es8326"; + struct rt_audio_caps caps = { 0 }; + + if (argc > 1) + { + name = argv[1]; + } + if (argc > 2) + { + seconds = strtoul(argv[2], RT_NULL, 0); + if (!seconds || seconds > AUDIO_TEST_MAX_SECONDS) + { + rt_kprintf("seconds must be 1..%u\n", AUDIO_TEST_MAX_SECONDS); + return -RT_EINVAL; + } + } + + device = rt_device_find(name); + if (!device) + { + rt_kprintf("audio device %s not found\n", name); + return -RT_ENOSYS; + } + + buffer = rt_malloc(AUDIO_TEST_BUFFER_SIZE); + if (!buffer) + { + return -RT_ENOMEM; + } + + if ((ret = rt_device_open(device, RT_DEVICE_OFLAG_WRONLY))) + { + rt_kprintf("open %s failed: %s\n", name, rt_strerror(ret)); + goto _free; + } + + caps.main_type = AUDIO_TYPE_OUTPUT; + caps.sub_type = AUDIO_DSP_PARAM; + caps.udata.config.samplerate = AUDIO_TEST_RATE; + caps.udata.config.channels = AUDIO_TEST_CHANNELS; + caps.udata.config.samplebits = AUDIO_TEST_BITS; + if ((ret = rt_device_control(device, AUDIO_CTL_CONFIGURE, &caps))) + { + rt_kprintf("configure %s failed: %s\n", name, rt_strerror(ret)); + goto _close; + } + + caps.main_type = AUDIO_TYPE_MIXER; + caps.sub_type = AUDIO_MIXER_VOLUME; + caps.udata.value = 65; + rt_device_control(device, AUDIO_CTL_CONFIGURE, &caps); + + remaining = (rt_size_t)seconds * AUDIO_TEST_RATE * + AUDIO_TEST_CHANNELS * sizeof(rt_int16_t); + rt_kprintf("playing 1 kHz tone on %s for %u second(s)\n", name, seconds); + + while (remaining) + { + rt_size_t size = rt_min_t(rt_size_t, remaining, AUDIO_TEST_BUFFER_SIZE); + rt_size_t samples = size / sizeof(*buffer); + + for (rt_size_t i = 0; i < samples; i += 2) + { + rt_int16_t sample = audio_test_sine[phase]; + + buffer[i] = sample; + buffer[i + 1] = sample; + phase = (phase + 1) % RT_ARRAY_SIZE(audio_test_sine); + } + + if (rt_device_write(device, 0, buffer, size) != size) + { + rt_kprintf("write %s failed\n", name); + ret = -RT_EIO; + goto _close; + } + remaining -= size; + } + + ret = RT_EOK; + rt_kprintf("audio_test: queued playback data, closing device\n"); + +_close: + rt_device_close(device); + rt_kprintf("audio_test: device closed\n"); +_free: + rt_free(buffer); + return ret; +} +MSH_CMD_EXPORT(audio_test, play a 1 kHz tone: audio_test [device] [seconds]); +#endif /* RT_USING_AUDIO && RT_AUDIO_SPACEMIT && RT_USING_FINSH */ diff --git a/bsp/spacemit/k1/applications/jpu.c b/bsp/spacemit/k1/applications/jpu.c new file mode 100644 index 000000000000..52d983c855fb --- /dev/null +++ b/bsp/spacemit/k1/applications/jpu.c @@ -0,0 +1,776 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#include +#include + +#include + +#if defined(RT_USING_FINSH) && defined(RT_USING_DFS) && defined(RT_USING_GRAPHIC) && defined(RT_SOC_CHIP_MEDIA_JPU) +#include +#include +#include + +#define JPU_ALIGN(value, align) (((value) + (align) - 1) & ~((align) - 1)) +#define JPU_FILE_IO_CHUNK 512U + +struct jpu_huffman +{ + rt_uint8_t bits[JPU_HUFF_BITS_NUM]; + rt_uint8_t values[JPU_HUFF_VALUES_NUM]; + rt_uint16_t count; +}; + +struct jpu_jpeg +{ + rt_uint8_t *data; + rt_size_t size; + rt_uint16_t quant[4][JPU_QUANT_VALUES_NUM]; + struct jpu_huffman huff[JPU_HUFF_TABLE_NUM]; + rt_uint8_t component_id[3]; + rt_uint8_t h[3]; + rt_uint8_t v[3]; + rt_uint8_t qsel[3]; + rt_uint8_t dcsel[3]; + rt_uint8_t acsel[3]; + rt_uint8_t components; + rt_uint8_t format; + rt_uint16_t width; + rt_uint16_t height; + rt_uint16_t aligned_width; + rt_uint16_t aligned_height; + rt_uint16_t restart_interval; + rt_uint16_t y_stride; + rt_uint16_t c_stride; + rt_uint16_t c_height; + rt_size_t entropy_offset; +}; + +static rt_uint16_t jpu_get_be16(const rt_uint8_t *p) +{ + return ((rt_uint16_t)p[0] << 8) | p[1]; +} + +static rt_err_t jpu_read_stream(int fd, void *destination, rt_size_t size) +{ + rt_uint8_t *buffer; + rt_size_t offset = 0; + rt_size_t buffer_size = rt_min(size, (rt_size_t)JPU_FILE_IO_CHUNK); + rt_err_t err = RT_EOK; + + buffer = rt_malloc(buffer_size); + if (!buffer) + { + return -RT_ENOMEM; + } + + while (offset < size) + { + rt_size_t requested = rt_min(size - offset, buffer_size); + ssize_t received = read(fd, buffer, requested); + + if (received <= 0) + { + err = -RT_EIO; + break; + } + + rt_memcpy((rt_uint8_t *)destination + offset, buffer, received); + offset += received; + } + + rt_free(buffer); + return err; +} + +static rt_err_t jpu_parse_dqt(struct jpu_jpeg *jpg, const rt_uint8_t *p, + rt_size_t length) +{ + while (length) + { + rt_uint8_t precision, table; + int i; + + precision = p[0] >> 4; + table = p[0] & 0xf; + ++p; + --length; + if (precision > 1 || table > 3 || + length < (rt_size_t)(JPU_QUANT_VALUES_NUM << precision)) + { + return -RT_EINVAL; + } + + for (i = 0; i < JPU_QUANT_VALUES_NUM; ++i) + { + jpg->quant[table][i] = precision ? jpu_get_be16(p + i * 2) : p[i]; + } + + p += JPU_QUANT_VALUES_NUM << precision; + length -= JPU_QUANT_VALUES_NUM << precision; + } + + return RT_EOK; +} + +static rt_err_t jpu_parse_dht(struct jpu_jpeg *jpg, const rt_uint8_t *p, + rt_size_t length) +{ + while (length) + { + struct jpu_huffman *huff; + rt_uint8_t type, id; + rt_uint16_t count = 0; + int i; + + if (length < 17) + { + return -RT_EINVAL; + } + + type = p[0] >> 4; + id = p[0] & 0xf; + ++p; + --length; + if (type > 1 || id > 1) + { + return -RT_ENOSYS; + } + + huff = &jpg->huff[id * 2 + type]; + for (i = 0; i < JPU_HUFF_BITS_NUM; ++i) + { + count += huff->bits[i] = p[i]; + } + p += JPU_HUFF_BITS_NUM; + length -= JPU_HUFF_BITS_NUM; + + if (count > (type ? JPU_HUFF_VALUES_NUM : 12) || length < count) + { + return -RT_EINVAL; + } + + rt_memcpy(huff->values, p, count); + huff->count = count; + p += count; + length -= count; + } + + return RT_EOK; +} + +static rt_err_t jpu_parse_sof(struct jpu_jpeg *jpg, const rt_uint8_t *p, + rt_size_t length) +{ + rt_uint8_t sample; + int i; + + if (length < 6 || p[0] != 8 || (p[5] != 1 && p[5] != 3) || + length != 6U + p[5] * 3U) + { + return -RT_ENOSYS; + } + + jpg->height = jpu_get_be16(p + 1); + jpg->width = jpu_get_be16(p + 3); + jpg->components = p[5]; + if (!jpg->width || !jpg->height) + { + return -RT_EINVAL; + } + + for (i = 0; i < jpg->components; ++i) + { + jpg->component_id[i] = p[6 + i * 3]; + jpg->h[i] = p[7 + i * 3] >> 4; + jpg->v[i] = p[7 + i * 3] & 0xf; + jpg->qsel[i] = p[8 + i * 3]; + if (!jpg->h[i] || !jpg->v[i] || jpg->qsel[i] > 3) + { + return -RT_EINVAL; + } + } + + if (jpg->components == 1) + { + jpg->format = JPU_FORMAT_400; + } + else + { + if (jpg->h[1] != 1 || jpg->v[1] != 1 || + jpg->h[2] != 1 || jpg->v[2] != 1) + { + return -RT_ENOSYS; + } + + sample = (jpg->h[0] << 2) | jpg->v[0]; + switch (sample) + { + case 0x0a: + jpg->format = JPU_FORMAT_420; + break; + case 0x09: + jpg->format = JPU_FORMAT_422; + break; + case 0x06: + jpg->format = JPU_FORMAT_440; + break; + case 0x05: + jpg->format = JPU_FORMAT_444; + break; + default: + return -RT_ENOSYS; + } + } + + return RT_EOK; +} + +static rt_err_t jpu_parse_sos(struct jpu_jpeg *jpg, const rt_uint8_t *p, + rt_size_t length) +{ + int i, component; + + if (length < 4 || p[0] != jpg->components || + length != 4U + p[0] * 2U) + { + return -RT_ENOSYS; + } + + for (i = 0; i < p[0]; ++i) + { + for (component = 0; component < jpg->components; ++component) + { + if (jpg->component_id[component] == p[1 + i * 2]) + { + break; + } + } + + if (component == jpg->components || + (p[2 + i * 2] >> 4) > 1 || (p[2 + i * 2] & 0xf) > 1) + { + return -RT_ENOSYS; + } + + jpg->dcsel[component] = p[2 + i * 2] >> 4; + jpg->acsel[component] = p[2 + i * 2] & 0xf; + } + + if (p[length - 3] != 0 || p[length - 2] != 63 || p[length - 1] != 0) + { + return -RT_ENOSYS; + } + + return RT_EOK; +} + +static rt_err_t jpu_validate_tables(struct jpu_jpeg *jpg) +{ + int i; + + for (i = 0; i < jpg->components; ++i) + { + if (!jpg->huff[jpg->dcsel[i] * 2].count || + !jpg->huff[jpg->acsel[i] * 2 + 1].count || + !jpg->quant[jpg->qsel[i]][0]) + { + return -RT_EINVAL; + } + } + + return RT_EOK; +} + +static rt_err_t jpu_parse(struct jpu_jpeg *jpg) +{ + rt_size_t pos = 2; + rt_bool_t have_sof = RT_FALSE; + + if (jpg->size < 4 || jpu_get_be16(jpg->data) != 0xffd8) + { + return -RT_EINVAL; + } + + while (pos + 1 < jpg->size) + { + rt_uint8_t marker; + rt_uint16_t section_length; + const rt_uint8_t *section; + rt_err_t err = RT_EOK; + + while (pos < jpg->size && jpg->data[pos] == 0xff) + { + ++pos; + } + if (pos >= jpg->size) + { + break; + } + + marker = jpg->data[pos++]; + if (marker == 0xd9) + { + break; + } + if (marker == 0xd8 || (marker >= 0xd0 && marker <= 0xd7)) + { + continue; + } + if (pos + 2 > jpg->size) + { + return -RT_EINVAL; + } + + section_length = jpu_get_be16(jpg->data + pos); + if (section_length < 2 || pos + section_length > jpg->size) + { + return -RT_EINVAL; + } + section = jpg->data + pos + 2; + + switch (marker) + { + case 0xc0: + err = jpu_parse_sof(jpg, section, section_length - 2); + have_sof = err == RT_EOK; + break; + case 0xc4: + err = jpu_parse_dht(jpg, section, section_length - 2); + break; + case 0xdb: + err = jpu_parse_dqt(jpg, section, section_length - 2); + break; + case 0xdd: + if (section_length != 4) + { + err = -RT_EINVAL; + } + else + { + jpg->restart_interval = jpu_get_be16(section); + } + break; + case 0xda: + if (!have_sof) + { + return -RT_EINVAL; + } + if ((err = jpu_parse_sos(jpg, section, section_length - 2)) != RT_EOK) + { + return err; + } + jpg->entropy_offset = pos + section_length; + return jpu_validate_tables(jpg); + default: + if (marker >= 0xc1 && marker <= 0xcf && + marker != 0xc4 && marker != 0xc8 && marker != 0xcc) + { + return -RT_ENOSYS; + } + break; + } + + if (err != RT_EOK) + { + return err; + } + pos += section_length; + } + + return -RT_EINVAL; +} + +static void jpu_fill_tables(struct jpu_dec_tables *tables, + const struct jpu_jpeg *jpg) +{ + const struct jpu_huffman *fallback_dc = RT_NULL; + const struct jpu_huffman *fallback_ac = RT_NULL; + int table, component; + + for (table = 0; table < JPU_HUFF_TABLE_NUM; ++table) + { + if (jpg->huff[table].count) + { + if (table & 1) + { + fallback_ac = &jpg->huff[table]; + } + else + { + fallback_dc = &jpg->huff[table]; + } + } + } + + for (table = 0; table < JPU_HUFF_TABLE_NUM; ++table) + { + const struct jpu_huffman *huff = &jpg->huff[table]; + + if (!huff->count) + { + huff = (table & 1) ? fallback_ac : fallback_dc; + } + rt_memcpy(tables->huff_bits[table], huff->bits, + sizeof(tables->huff_bits[table])); + rt_memcpy(tables->huff_values[table], huff->values, + sizeof(tables->huff_values[table])); + } + + for (component = 0; component < JPU_QUANT_COMPONENT_NUM; ++component) + { + int source = component < jpg->components ? component : 0; + + rt_memcpy(tables->quant[component], jpg->quant[jpg->qsel[source]], + sizeof(tables->quant[component])); + } +} + +static void jpu_fill_request(struct jpu_decode_request *req, + const struct jpu_jpeg *jpg) +{ + req->frame.width = jpg->width; + req->frame.height = jpg->height; + req->frame.format = jpg->format; + req->entropy_offset = jpg->entropy_offset; + req->restart_interval = jpg->restart_interval; + req->components = jpg->components; + rt_memcpy(req->dc_selector, jpg->dcsel, sizeof(req->dc_selector)); + rt_memcpy(req->ac_selector, jpg->acsel, sizeof(req->ac_selector)); + jpu_fill_tables(&req->tables, jpg); +} + +static rt_uint8_t jpu_clip(int value) +{ + if (value < 0) + { + return 0; + } + if (value > 255) + { + return 255; + } + return value; +} + +static rt_err_t jpu_store_pixel(rt_uint8_t format, rt_uint8_t *dst, + rt_uint8_t r, rt_uint8_t g, rt_uint8_t b) +{ + switch (format) + { + case RTGRAPHIC_PIXEL_FORMAT_RGB565: + *(rt_uint16_t *)dst = (r >> 3) << 11 | (g >> 2) << 5 | (b >> 3); + break; + case RTGRAPHIC_PIXEL_FORMAT_BGR565: + *(rt_uint16_t *)dst = (b >> 3) << 11 | (g >> 2) << 5 | (r >> 3); + break; + case RTGRAPHIC_PIXEL_FORMAT_RGB888: + dst[0] = r; + dst[1] = g; + dst[2] = b; + break; + case RTGRAPHIC_PIXEL_FORMAT_BGR888: + dst[0] = b; + dst[1] = g; + dst[2] = r; + break; + case RTGRAPHIC_PIXEL_FORMAT_ARGB888: + *(rt_uint32_t *)dst = 0xff000000U | (rt_uint32_t)r << 16 | + (rt_uint32_t)g << 8 | b; + break; + case RTGRAPHIC_PIXEL_FORMAT_ABGR888: + *(rt_uint32_t *)dst = 0xff000000U | (rt_uint32_t)b << 16 | + (rt_uint32_t)g << 8 | r; + break; + default: + return -RT_ENOSYS; + } + + return RT_EOK; +} + +static rt_err_t jpu_show_frame(const char *fb_name, const struct jpu_jpeg *jpg, + const rt_uint8_t *frame) +{ + struct rt_device_graphic_info info; + struct rt_graphic_device *graphic; + rt_device_t fb = rt_device_find(fb_name); + rt_bool_t restore_auto_update; + rt_uint8_t *display_buffer; + rt_size_t screen_size; + const rt_uint8_t *y_plane = frame; + const rt_uint8_t *cb_plane = y_plane + jpg->y_stride * jpg->aligned_height; + const rt_uint8_t *cr_plane = cb_plane + jpg->c_stride * jpg->c_height; + int x0, y0, copy_width, copy_height, source_x, source_y; + int bytes_per_pixel, x, y; + rt_err_t err; + + if (!fb) + { + return -RT_ENOSYS; + } + + graphic = rt_container_of(fb, struct rt_graphic_device, parent); + restore_auto_update = graphic->update_timer != RT_NULL; + if ((err = rt_device_open(fb, RT_DEVICE_OFLAG_RDWR)) != RT_EOK) + { + return err; + } + if ((err = rt_device_control(fb, RTGRAPHIC_CTRL_GET_INFO, &info)) != RT_EOK) + { + goto _out; + } + if (!info.framebuffer || !(bytes_per_pixel = info.bits_per_pixel / 8)) + { + err = -RT_EINVAL; + goto _out; + } + screen_size = (rt_size_t)info.pitch * info.height; + if (!screen_size || screen_size > info.smem_len / 2U) + { + rt_kprintf("%s needs a double framebuffer for tear-free display " + "(have %u, need %u bytes)\n", fb_name, + (unsigned int)info.smem_len, + (unsigned int)(screen_size * 2U)); + err = -RT_ENOMEM; + goto _out; + } + display_buffer = (rt_uint8_t *)info.framebuffer + screen_size; + + if ((err = rt_device_control(fb, RTGRAPHIC_CTRL_POWERON, RT_NULL)) != RT_EOK) + { + goto _out; + } + + if (restore_auto_update) + { + rt_graphic_device_update_auto(graphic, 0); + } + + if ((err = rt_device_control(fb, RTGRAPHIC_CTRL_PAN_DISPLAY, + info.framebuffer)) != RT_EOK || + (err = rt_device_control(fb, RTGRAPHIC_CTRL_WAIT_VSYNC, + RT_NULL)) != RT_EOK) + { + goto _restore; + } + + rt_memset(display_buffer, 0, screen_size); + copy_width = rt_min((int)jpg->width, (int)info.width); + copy_height = rt_min((int)jpg->height, (int)info.height); + x0 = (info.width - copy_width) / 2; + y0 = (info.height - copy_height) / 2; + source_x = (jpg->width - copy_width) / 2; + source_y = (jpg->height - copy_height) / 2; + + for (y = 0; y < copy_height; ++y) + { + rt_uint8_t *dst = display_buffer + + (y0 + y) * info.pitch + x0 * bytes_per_pixel; + int sy = source_y + y; + + for (x = 0; x < copy_width; ++x) + { + int sx = source_x + x; + int cx = sx, cy = sy; + int yy, cb = 128, cr = 128; + rt_uint8_t r, g, b; + + if (jpg->format == JPU_FORMAT_420 || jpg->format == JPU_FORMAT_422) + { + cx >>= 1; + } + if (jpg->format == JPU_FORMAT_420 || jpg->format == JPU_FORMAT_440) + { + cy >>= 1; + } + yy = y_plane[sy * jpg->y_stride + sx]; + if (jpg->format != JPU_FORMAT_400) + { + cb = cb_plane[cy * jpg->c_stride + cx]; + cr = cr_plane[cy * jpg->c_stride + cx]; + } + + cb -= 128; + cr -= 128; + r = jpu_clip(yy + ((359 * cr) >> 8)); + g = jpu_clip(yy - ((88 * cb + 183 * cr) >> 8)); + b = jpu_clip(yy + ((454 * cb) >> 8)); + if ((err = jpu_store_pixel(info.pixel_format, + dst + x * bytes_per_pixel, r, g, b)) != RT_EOK) + { + goto _restore; + } + } + } + + if ((err = rt_device_control(fb, RTGRAPHIC_CTRL_PAN_DISPLAY, + display_buffer)) != RT_EOK || + (err = rt_device_control(fb, RTGRAPHIC_CTRL_WAIT_VSYNC, + RT_NULL)) != RT_EOK) + { + goto _restore; + } + +_restore: + if (restore_auto_update) + { + rt_graphic_device_update_auto(graphic, RT_GRAPHIC_UPDATE_MS); + } +_out: + rt_device_close(fb); + return err; +} + +static int jpu_show(int argc, char **argv) +{ + const char *path; + const char *fb_name; + struct jpu_jpeg jpg = { 0 }; + struct jpu_buffer stream = { 0 }; + struct jpu_buffer frame = { 0 }; + struct jpu_decode_request *req = RT_NULL; + rt_device_t jpu = rt_device_find("jpu0"); + off_t file_size; + int fd = -1; + rt_err_t err = -RT_ERROR; + + if (argc < 2 || argc > 3) + { + rt_kprintf("Usage: jpu_show [framebuffer]\n"); + return -RT_EINVAL; + } + + path = argv[1]; + fb_name = argc > 2 ? argv[2] : "fb0"; + + if (!jpu) + { + rt_kprintf("jpu0 not found\n"); + return -RT_ENOSYS; + } + if ((err = rt_device_open(jpu, RT_DEVICE_OFLAG_RDWR)) != RT_EOK) + { + rt_kprintf("open jpu0 failed: %d\n", err); + return err; + } + + fd = open(path, O_RDONLY, 0); + if (fd < 0) + { + rt_kprintf("open %s failed\n", path); + err = -RT_EIO; + goto _out; + } + file_size = lseek(fd, 0, SEEK_END); + if (lseek(fd, 0, SEEK_SET) < 0) + { + err = -RT_EIO; + goto _out; + } + if (file_size <= 0 || file_size > JPU_BUFFER_MAX_SIZE - JPU_STREAM_PADDING) + { + err = -RT_EINVAL; + goto _out; + } + + stream.size = JPU_ALIGN((rt_size_t)file_size + JPU_STREAM_PADDING, 4096); + if ((err = rt_device_control(jpu, JPU_ALLOC_BUFFER, &stream)) != RT_EOK) + { + rt_kprintf("allocate JPU stream buffer failed: %d\n", err); + goto _out; + } + rt_memset(stream.virt_addr, 0xff, stream.size); + if ((err = jpu_read_stream(fd, stream.virt_addr, file_size)) != RT_EOK) + { + rt_kprintf("read %s into JPU stream buffer failed: %d\n", path, err); + goto _out; + } + + jpg.data = stream.virt_addr; + jpg.size = file_size; + if ((err = jpu_parse(&jpg)) != RT_EOK) + { + rt_kprintf("unsupported or invalid baseline JPEG: %d\n", err); + goto _out; + } + + req = rt_calloc(1, sizeof(*req)); + if (!req) + { + err = -RT_ENOMEM; + goto _out; + } + jpu_fill_request(req, &jpg); + if ((err = rt_device_control(jpu, JPU_QUERY_FRAME, &req->frame)) != RT_EOK) + { + rt_kprintf("unsupported JPU output layout: %d\n", err); + goto _out; + } + + jpg.aligned_width = req->frame.aligned_width; + jpg.aligned_height = req->frame.aligned_height; + jpg.y_stride = req->frame.y_stride; + jpg.c_stride = req->frame.c_stride; + jpg.c_height = req->frame.c_height; + + frame.size = JPU_ALIGN(req->frame.size, 4096); + if ((err = rt_device_control(jpu, JPU_ALLOC_BUFFER, &frame)) != RT_EOK) + { + rt_kprintf("allocate JPU frame buffer failed: %d\n", err); + goto _out; + } + rt_memset(frame.virt_addr, 0, frame.size); + + req->stream_phys = stream.phys_addr; + req->frame_phys = frame.phys_addr; + req->stream_size = jpg.size; + req->stream_capacity = stream.size; + req->frame_capacity = frame.size; + + if ((err = rt_device_control(jpu, JPU_DECODE, req)) != RT_EOK) + { + rt_kprintf("JPU decode failed: %d, irq=0x%08x status=0x%08x errmb=0x%08x\n", + err, req->irq_status, req->picture_status, req->error_mcu); + goto _out; + } + + if ((err = jpu_show_frame(fb_name, &jpg, frame.virt_addr)) != RT_EOK) + { + rt_kprintf("display on %s failed: %d\n", fb_name, err); + } + else + { + rt_kprintf("JPU decoded %s (%ux%u) on %s\n", + path, jpg.width, jpg.height, fb_name); + } + +_out: + if (req) + { + rt_free(req); + } + if (frame.virt_addr) + { + rt_device_control(jpu, JPU_FREE_BUFFER, &frame); + } + if (stream.virt_addr) + { + rt_device_control(jpu, JPU_FREE_BUFFER, &stream); + } + if (fd >= 0) + { + close(fd); + } + rt_device_close(jpu); + return err; +} +MSH_CMD_EXPORT(jpu_show, decode a baseline JPEG with K1 JPU and display it); +#endif /* RT_USING_FINSH && RT_USING_DFS && RT_USING_GRAPHIC && RT_SOC_CHIP_MEDIA_JPU */ diff --git a/bsp/spacemit/k1/applications/main.c b/bsp/spacemit/k1/applications/main.c new file mode 100644 index 000000000000..4450b5b4b0ab --- /dev/null +++ b/bsp/spacemit/k1/applications/main.c @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2017-5-30 bernard the first version + */ + +#include + +int main(int argc, char** argv) +{ + rt_kprintf("Hi, this is RT-Thread!!\n"); + + return 0; +} diff --git a/bsp/spacemit/k1/applications/v2d.c b/bsp/spacemit/k1/applications/v2d.c new file mode 100644 index 000000000000..63e5693f20f9 --- /dev/null +++ b/bsp/spacemit/k1/applications/v2d.c @@ -0,0 +1,468 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#include +#include + +#include + +#if defined(RT_USING_FINSH) && defined(RT_USING_GRAPHIC) && defined(RT_SOC_SPACEMIT_V2D) +#include +#include + +#define V2D_TEST_WIDTH 320U +#define V2D_TEST_HEIGHT 240U +#define V2D_TEST_STRIDE (V2D_TEST_WIDTH * 4U) +#define V2D_TEST_DEFAULT_FRAMES 240U +#define V2D_TEST_MAX_FRAMES 3600U +#define V2D_TEST_MAX_DEVICES 32U + +static rt_device_t v2d_test_find_device(char *name, rt_size_t name_size) +{ + rt_uint32_t id; + + for (id = 0; id < V2D_TEST_MAX_DEVICES; ++id) + { + rt_device_t device; + + rt_snprintf(name, name_size, "v2d%u", id); + device = rt_device_find(name); + if (device) + { + return device; + } + } + + name[0] = '\0'; + return RT_NULL; +} + +static void v2d_test_set_address(V2D_SURFACE_S *surface, + const V2D_BUFFER_S *buffer) +{ + surface->phyaddr_y_l = (rt_uint32_t)buffer->phys_addr; + surface->phyaddr_y_h = (rt_uint32_t)(buffer->phys_addr >> 32); +} + +static void v2d_test_fill_pattern(rt_uint32_t *pixels) +{ + static const rt_uint32_t colors[] = + { + 0xffff3030U, + 0xffffa020U, + 0xffffff30U, + 0xff30d060U, + 0xff30d8ffU, + 0xff4070ffU, + 0xffb050e0U, + 0xffffffffU, + }; + rt_uint32_t x, y; + + for (y = 0; y < V2D_TEST_HEIGHT; ++y) + { + for (x = 0; x < V2D_TEST_WIDTH; ++x) + { + rt_uint32_t color = colors[x * RT_ARRAY_SIZE(colors) / + V2D_TEST_WIDTH]; + + if (x < 3 || y < 3 || x >= V2D_TEST_WIDTH - 3 || + y >= V2D_TEST_HEIGHT - 3 || x % 40 < 2 || y % 40 < 2) + { + color = 0xff101010U; + } + if (x + y >= V2D_TEST_WIDTH - 2 && + x + y <= V2D_TEST_WIDTH + 2) + { + color = 0xffffffffU; + } + + pixels[y * V2D_TEST_WIDTH + x] = color; + } + } +} + +static rt_err_t v2d_test_get_format(const struct rt_device_graphic_info *info, + V2D_COLOR_FORMAT_E *format) +{ + switch (info->pixel_format) + { + case RTGRAPHIC_PIXEL_FORMAT_ARGB888: + *format = V2D_COLOR_FORMAT_BGRA8888; + break; + case RTGRAPHIC_PIXEL_FORMAT_ABGR888: + *format = V2D_COLOR_FORMAT_RGBA8888; + break; + case RTGRAPHIC_PIXEL_FORMAT_RGB565: + *format = V2D_COLOR_FORMAT_BGR565; + break; + case RTGRAPHIC_PIXEL_FORMAT_BGR565: + *format = V2D_COLOR_FORMAT_RGB565; + break; + default: + return -RT_ENOSYS; + } + + return RT_EOK; +} + +static rt_uint32_t v2d_test_triangle(rt_uint32_t frame, rt_uint32_t period, + rt_uint32_t amplitude) +{ + rt_uint32_t half = period / 2; + rt_uint32_t phase = frame % period; + + if (phase > half) + { + phase = period - phase; + } + + return half ? (rt_uint64_t)amplitude * phase / half : 0; +} + +static rt_uint32_t v2d_test_rgba(rt_uint8_t r, rt_uint8_t g, + rt_uint8_t b, rt_uint8_t a) +{ + return (rt_uint32_t)a << 24 | (rt_uint32_t)b << 16 | + (rt_uint32_t)g << 8 | r; +} + +static void v2d_test_fill_task(V2D_SUBMIT_TASK_S *task, + const V2D_BUFFER_S *source, const V2D_BUFFER_S *destination, + const struct rt_device_graphic_info *info, + V2D_COLOR_FORMAT_E destination_format) +{ + V2D_BLEND_LAYER_CONF_S *blend; + + rt_memset(task, 0, sizeof(*task)); + + v2d_test_set_address(&task->param.layer0, source); + task->param.layer0.w = V2D_TEST_WIDTH; + task->param.layer0.h = V2D_TEST_HEIGHT; + task->param.layer0.stride = V2D_TEST_STRIDE; + task->param.layer0.format = V2D_COLOR_FORMAT_BGRA8888; + task->param.l0_rect.w = V2D_TEST_WIDTH; + task->param.l0_rect.h = V2D_TEST_HEIGHT; + + v2d_test_set_address(&task->param.dst, destination); + task->param.dst.w = info->width; + task->param.dst.h = info->height; + task->param.dst.stride = info->pitch; + task->param.dst.format = destination_format; + task->param.dst_rect.w = info->width; + task->param.dst_rect.h = info->height; + + task->param.blendconf.blend_cmd = V2D_BLENDCMD_ALPHA; + task->param.blendconf.bgcolor.enable = true; + task->param.blendconf.bgcolor.fillcolor.format = + V2D_COLOR_FORMAT_RGBA8888; + task->param.blendconf.bgcolor.fillcolor.colorvalue = 0xff202020U; + + blend = &task->param.blendconf.blendlayer[0]; + blend->blend_alpha_source = V2D_BLENDALPHA_SOURCE_GOLBAL; + blend->blend_pre_alpha_func = V2D_BLEND_PRE_ALPHA_FUNC_DISABLE; + blend->global_alpha = 0xff; + blend->stBlendFactor.srcColorFactor = V2D_BLEND_ONE; + blend->stBlendFactor.dstColorFactor = V2D_BLEND_ZERO; + blend->stBlendFactor.srcAlphaFactor = V2D_BLEND_ONE; + blend->stBlendFactor.dstAlphaFactor = V2D_BLEND_ZERO; + blend->blend_area.w = info->width; + blend->blend_area.h = info->height; + + task->param.layer1.solidcolor.enable = true; + task->param.layer1.solidcolor.fillcolor.format = + V2D_COLOR_FORMAT_RGBA8888; + task->param.layer1.solidcolor.fillcolor.colorvalue = + v2d_test_rgba(255, 255, 255, 255); + + blend = &task->param.blendconf.blendlayer[1]; + blend->blend_alpha_source = V2D_BLENDALPHA_SOURCE_GOLBAL; + blend->blend_pre_alpha_func = V2D_BLEND_PRE_ALPHA_FUNC_DISABLE; + blend->global_alpha = 0xa0; + blend->stBlendFactor.srcColorFactor = V2D_BLEND_SRC_ALPHA; + blend->stBlendFactor.dstColorFactor = V2D_BLEND_ONE_MINUS_SRC_ALPHA; + blend->stBlendFactor.srcAlphaFactor = V2D_BLEND_ONE; + blend->stBlendFactor.dstAlphaFactor = V2D_BLEND_ONE_MINUS_SRC_ALPHA; + blend->blend_area.w = info->width / 5; + blend->blend_area.h = info->height / 5; + + task->param.l0_rt = V2D_ROT_0; + task->param.l1_rt = V2D_ROT_0; + task->param.l0_csc = V2D_CSC_MODE_BUTT; + task->param.l1_csc = V2D_CSC_MODE_BUTT; + task->param.dither = V2D_NO_DITHER; + task->acquireFencefd = -1; + task->completeFencefd = -1; +} + +static void v2d_test_animate_task(V2D_SUBMIT_TASK_S *task, + const struct rt_device_graphic_info *info, rt_uint32_t frame) +{ + static const V2D_ROTATE_ANGLE_E rotations[] = + { + V2D_ROT_0, + V2D_ROT_90, + V2D_ROT_180, + V2D_ROT_270, + V2D_ROT_MIRROR, + V2D_ROT_FLIP, + }; + V2D_BLEND_LAYER_CONF_S *layer0 = + &task->param.blendconf.blendlayer[0]; + V2D_BLEND_LAYER_CONF_S *layer1 = + &task->param.blendconf.blendlayer[1]; + rt_uint32_t min_width, max_width, min_height, max_height; + rt_uint32_t width, height; + rt_uint32_t red, green, blue; + + min_width = rt_min((rt_uint32_t)info->width, + rt_max((rt_uint32_t)96, (rt_uint32_t)info->width / 8)); + max_width = rt_max(min_width, (rt_uint32_t)info->width * 3 / 4); + min_height = rt_min((rt_uint32_t)info->height, + rt_max((rt_uint32_t)72, (rt_uint32_t)info->height / 8)); + max_height = rt_max(min_height, (rt_uint32_t)info->height * 3 / 4); + + width = min_width + v2d_test_triangle(frame, 151, + max_width - min_width); + height = min_height + v2d_test_triangle(frame + 37, 127, + max_height - min_height); + layer0->blend_area.w = width; + layer0->blend_area.h = height; + layer0->blend_area.x = v2d_test_triangle(frame, 137, + info->width - width); + layer0->blend_area.y = v2d_test_triangle(frame + 29, 103, + info->height - height); + task->param.l0_rt = rotations[(frame / 40) % RT_ARRAY_SIZE(rotations)]; + + width = rt_max((rt_uint32_t)32, (rt_uint32_t)info->width / 5); + height = rt_max((rt_uint32_t)32, (rt_uint32_t)info->height / 5); + width = rt_min(width, (rt_uint32_t)info->width); + height = rt_min(height, (rt_uint32_t)info->height); + layer1->blend_area.w = width; + layer1->blend_area.h = height; + layer1->blend_area.x = v2d_test_triangle(frame + 61, 113, + info->width - width); + layer1->blend_area.y = v2d_test_triangle(frame + 17, 89, + info->height - height); + layer1->global_alpha = 80 + v2d_test_triangle(frame + 23, 97, 144); + + red = 20 + v2d_test_triangle(frame, 181, 52); + green = 24 + v2d_test_triangle(frame + 53, 157, 48); + blue = 32 + v2d_test_triangle(frame + 101, 193, 64); + task->param.blendconf.bgcolor.fillcolor.colorvalue = + v2d_test_rgba(red, green, blue, 255); + + red = 96 + v2d_test_triangle(frame + 73, 109, 159); + green = 64 + v2d_test_triangle(frame + 7, 131, 191); + blue = 80 + v2d_test_triangle(frame + 41, 149, 175); + task->param.layer1.solidcolor.fillcolor.colorvalue = + v2d_test_rgba(red, green, blue, 255); +} + +static rt_err_t v2d_test_parse_frames(const char *text, + rt_uint32_t *frames) +{ + char *end; + unsigned long value = strtoul(text, &end, 0); + + if (!text[0] || *end || !value || value > V2D_TEST_MAX_FRAMES) + { + return -RT_EINVAL; + } + + *frames = value; + return RT_EOK; +} + +static int v2d_test(int argc, char **argv) +{ + const char *fb_name = argc > 1 ? argv[1] : "fb0"; + struct rt_device_graphic_info info; + struct rt_graphic_device *graphic; + V2D_BUFFER_S source = { 0 }; + V2D_BUFFER_S destination = { 0 }; + V2D_SUBMIT_TASK_S task; + V2D_COLOR_FORMAT_E destination_format; + rt_device_t v2d, fb; + rt_uint8_t *front_buffer, *back_buffer, *swap_buffer; + char v2d_name[RT_NAME_MAX]; + rt_size_t screen_size; + rt_uint32_t frame_count = V2D_TEST_DEFAULT_FRAMES; + rt_uint32_t frame; + rt_tick_t start_ms, elapsed_ms; + rt_bool_t v2d_opened = RT_FALSE; + rt_bool_t fb_opened = RT_FALSE; + rt_bool_t restore_auto_update = RT_FALSE; + rt_err_t err; + + if (argc > 3 || (argc > 2 && + v2d_test_parse_frames(argv[2], &frame_count) != RT_EOK)) + { + rt_kprintf("Usage: v2d_test [framebuffer] [frames: 1-%u]\n", + V2D_TEST_MAX_FRAMES); + return -RT_EINVAL; + } + + v2d = v2d_test_find_device(v2d_name, sizeof(v2d_name)); + fb = rt_device_find(fb_name); + if (!v2d || !fb) + { + rt_kprintf("V2D device or framebuffer %s not found\n", fb_name); + return -RT_ENOSYS; + } + + if ((err = rt_device_open(v2d, RT_DEVICE_OFLAG_RDWR)) != RT_EOK) + { + rt_kprintf("open %s failed: %d\n", v2d_name, err); + return err; + } + v2d_opened = RT_TRUE; + + if ((err = rt_device_open(fb, RT_DEVICE_OFLAG_RDWR)) != RT_EOK) + { + rt_kprintf("open %s failed: %d\n", fb_name, err); + goto _out; + } + fb_opened = RT_TRUE; + + if ((err = rt_device_control(fb, RTGRAPHIC_CTRL_GET_INFO, &info)) != + RT_EOK) + { + goto _out; + } + screen_size = (rt_size_t)info.pitch * info.height; + if (!info.framebuffer || !info.width || !info.height || !info.pitch || + screen_size > info.smem_len || screen_size > V2D_BUFFER_MAX_SIZE || + (err = v2d_test_get_format(&info, &destination_format)) != RT_EOK) + { + err = -RT_EINVAL; + rt_kprintf("unsupported framebuffer layout: %ux%u pitch=%u fmt=%u\n", + info.width, info.height, info.pitch, info.pixel_format); + goto _out; + } + if (screen_size > info.smem_len / 2U) + { + err = -RT_ENOMEM; + rt_kprintf("%s needs a double framebuffer for tear-free animation " + "(have %u, need %u bytes)\n", fb_name, + (unsigned int)info.smem_len, + (unsigned int)(screen_size * 2U)); + goto _out; + } + front_buffer = info.framebuffer; + back_buffer = front_buffer + screen_size; + + source.size = V2D_TEST_STRIDE * V2D_TEST_HEIGHT; + if ((err = rt_device_control(v2d, V2D_ALLOC_BUFFER, &source)) != RT_EOK) + { + rt_kprintf("allocate V2D source failed: %d\n", err); + goto _out; + } + destination.size = screen_size; + if ((err = rt_device_control(v2d, V2D_ALLOC_BUFFER, &destination)) != + RT_EOK) + { + rt_kprintf("allocate V2D destination failed: %d\n", err); + goto _out; + } + + v2d_test_fill_pattern(source.virt_addr); + rt_memset(destination.virt_addr, 0, destination.size); + v2d_test_fill_task(&task, &source, &destination, &info, + destination_format); + + if ((err = rt_device_control(fb, RTGRAPHIC_CTRL_POWERON, RT_NULL)) != + RT_EOK) + { + goto _out; + } + graphic = rt_container_of(fb, struct rt_graphic_device, parent); + restore_auto_update = graphic->update_timer != RT_NULL; + if (restore_auto_update) + { + rt_graphic_device_update_auto(graphic, 0); + } + + if ((err = rt_device_control(fb, RTGRAPHIC_CTRL_PAN_DISPLAY, + front_buffer)) != RT_EOK || + (err = rt_device_control(fb, RTGRAPHIC_CTRL_WAIT_VSYNC, + RT_NULL)) != RT_EOK) + { + rt_kprintf("framebuffer page-flip setup failed: %d\n", err); + goto _out; + } + + rt_kprintf("V2D animation: %ux%u BGRA8888 -> %ux%u format %u, %u frames\n", + V2D_TEST_WIDTH, V2D_TEST_HEIGHT, info.width, info.height, + info.pixel_format, frame_count); + start_ms = rt_tick_get_millisecond(); + + for (frame = 0; frame < frame_count; ++frame) + { + v2d_test_animate_task(&task, &info, frame * 2U); + if ((err = rt_device_control(v2d, V2D_SUBMIT, &task)) != RT_EOK) + { + rt_kprintf("V2D submit failed at frame %u: %d\n", frame, err); + goto _out; + } + + rt_memcpy(back_buffer, destination.virt_addr, screen_size); + if ((err = rt_device_control(fb, RTGRAPHIC_CTRL_PAN_DISPLAY, + back_buffer)) != RT_EOK || + (err = rt_device_control(fb, RTGRAPHIC_CTRL_WAIT_VSYNC, + RT_NULL)) != RT_EOK) + { + rt_kprintf("framebuffer update failed at frame %u: %d\n", + frame, err); + goto _out; + } + + swap_buffer = front_buffer; + front_buffer = back_buffer; + back_buffer = swap_buffer; + } + + elapsed_ms = rt_tick_get_millisecond() - start_ms; + if (!elapsed_ms) + { + elapsed_ms = 1; + } + rt_kprintf("V2D animation done on %s: %u frames in %u ms, %u.%u fps\n", + fb_name, frame_count, (unsigned int)elapsed_ms, + (unsigned int)((rt_uint64_t)frame_count * 1000 / elapsed_ms), + (unsigned int)(((rt_uint64_t)frame_count * 10000 / elapsed_ms) % 10)); + err = RT_EOK; + +_out: + if (restore_auto_update) + { + rt_graphic_device_update_auto(graphic, RT_GRAPHIC_UPDATE_MS); + } + if (destination.virt_addr) + { + rt_device_control(v2d, V2D_FREE_BUFFER, &destination); + } + if (source.virt_addr) + { + rt_device_control(v2d, V2D_FREE_BUFFER, &source); + } + if (fb_opened) + { + rt_device_close(fb); + } + if (v2d_opened) + { + rt_device_close(v2d); + } + + return err; +} +MSH_CMD_EXPORT(v2d_test, run the K1 V2D animation and framebuffer test); +#endif /* RT_USING_FINSH && RT_USING_GRAPHIC && RT_SOC_SPACEMIT_V2D */ diff --git a/bsp/spacemit/k1/coremark/LICENSE.md b/bsp/spacemit/k1/coremark/LICENSE.md new file mode 100644 index 000000000000..14e53e9eecd0 --- /dev/null +++ b/bsp/spacemit/k1/coremark/LICENSE.md @@ -0,0 +1,100 @@ +# COREMARK® ACCEPTABLE USE AGREEMENT + +This ACCEPTABLE USE AGREEMENT (this “Agreement”) is offered by Embedded Microprocessor Benchmark Consortium, a California nonprofit corporation (“Licensor”), to users of its CoreMark® software (“Licensee”) exclusively on the following terms. + +Licensor offers benchmarking software (“Software”) pursuant to an open source license, but carefully controls use of its benchmarks and their associated goodwill. Licensor has registered its trademark in one of the benchmarks available through the Software, COREMARK, Ser. No. 85/487,290; Reg. No. 4,179,307 (the “Trademark”), and promotes the use of a standard metric as a benchmark for assessing the performance of embedded systems. Solely on the terms described herein, Licensee may use and display the Trademark in connection with the generation of data regarding measurement and analysis of computer and embedded system benchmarking via the Software (the “Licensed Use”). + +## Article 1 – License Grant. +1.1. License. Subject to the terms and conditions of this Agreement, Licensor hereby grants to Licensee, and Licensee hereby accepts from Licensor, a personal, non-exclusive, royalty-free, revocable right and license to use and display the Trademark during the term of this Agreement (the “Term”), solely and exclusively in connection with the Licensed Use. During the Term, Licensee (i) shall not modify or otherwise create derivative works of the Trademark, and (ii) may use the Trademark only to the extent permitted under this License. Neither Licensee nor any affiliate or agent thereof shall otherwise use the Trademark without the prior express written consent of Licensor, which may be withheld in its sole and absolute discretion. All rights not expressly granted to Licensee hereunder shall remain the exclusive property of Licensor. + +1.2. Modifications to the Software. Licensee shall not use the Trademark in connection with any use of a modified, derivative, or otherwise altered copy of the Software. + +1.3. Licensor’s Use. Nothing in this Agreement shall preclude Licensor or any of its successors or assigns from using or permitting other entities to use the Trademark, whether or not such entity directly or indirectly competes or conflicts with Licensee’s Licensed Use in any manner. + +1.4. Term and Termination. This Agreement is perpetual unless terminated by either of the parties. Licensee may terminate this Agreement for convenience, without cause or liability, for any reason or for no reason whatsoever, upon ten (10) business days written notice. Licensor may terminate this Agreement effective immediately upon notice of breach. Upon termination, Licensee shall immediately remove all implementations of the Trademark from the Licensed Use, and delete all digitals files and records of all materials related to the Trademark. + +## Article 2 – Ownership. +2.1. Ownership. Licensee acknowledges and agrees that Licensor is the owner of all right, title, and interest in and to the Trademark, and all such right, title, and interest shall remain with Licensor. Licensee shall not contest, dispute, challenge, oppose, or seek to cancel Licensor’s right, title, and interest in and to the Trademark. Licensee shall not prosecute any application for registration of the Trademark. Licensee shall display appropriate notices regarding ownership of the Trademark in connection with the Licensed Use. + +2.2. Goodwill. Licensee acknowledges that Licensee shall not acquire any right, title, or interest in the Trademark by virtue of this Agreement other than the license granted hereunder, and disclaims any such right, title, interest, or ownership. All goodwill and reputation generated by Licensee’s use of the Trademark shall inure to the exclusive benefit of Licensor. Licensee shall not by any act or omission use the Trademark in any manner that disparages or reflects adversely on Licensor or its Licensed Use or reputation. Licensee shall not take any action that would interfere with or prejudice Licensor’s ownership or registration of the Trademark, the validity of the Trademark or the validity of the license granted by this Agreement. If Licensor determines and notifies Licensee that any act taken in connection with the Licensed Use (i) is inaccurate, unlawful or offensive to good taste; (ii) fails to provide for proper trademark notices, or (iii) otherwise violates Licensee’s obligations under this Agreement, the license granted under this Agreement shall terminate. + +## Article 3 – Indemnification. +3.1. Indemnification Generally. Licensee agrees to indemnify, defend, and hold harmless (collectively “indemnify” or “indemnification”) Licensor, including Licensor’s members, managers, officers, and employees (collectively “Related Persons”), from and against, and pay or reimburse Licensor and such Related Persons for, any and all third-party actions, claims, demands, proceedings, investigations, inquiries (collectively, “Claims”), and any and all liabilities, obligations, fines, deficiencies, costs, expenses, royalties, losses, and damages (including reasonable outside counsel fees and expenses) associated with such Claims, to the extent that such Claim arises out of (i) Licensee’s material breach of this Agreement, or (ii) any allegation(s) that Licensee’s actions infringe or violate any third-party intellectual property right, including without limitation, any U.S. copyright, patent, or trademark, or are otherwise found to be tortious or criminal (whether or not such indemnified person is a named party in a legal proceeding). + +3.2. Notice and Defense of Claims. Licensor shall promptly notify Licensee of any Claim for which indemnification is sought, following actual knowledge of such Claim, provided however that the failure to give such notice shall not relieve Licensee of its obligations hereunder except to the extent that Licensee is materially prejudiced by such failure. In the event that any third-party Claim is brought, Licensee shall have the right and option to undertake and control the defense of such action with counsel of its choice, provided however that (i) Licensor at its own expense may participate and appear on an equal footing with Licensee in the defense of any such Claim, (ii) Licensor may undertake and control such defense in the event of the material failure of Licensee to undertake and control the same; and (iii) the defense of any Claim relating to the intellectual property rights of Licensor or its licensors and any related counterclaims shall be solely controlled by Licensor with counsel of its choice. Licensee shall not consent to judgment or concede or settle or compromise any Claim without the prior written approval of Licensor (whose approval shall not be unreasonably withheld), unless such concession or settlement or compromise includes a full and unconditional release of Licensor and any applicable Related Persons from all liabilities in respect of such Claim. + +## Article 4 – Miscellaneous. +4.1. Relationship of the Parties. This Agreement does not create a partnership, franchise, joint venture, agency, fiduciary, or employment relationship between the parties. + +4.2. No Third-Party Beneficiaries. Except for the rights of Related Persons under Article 3 (Indemnification), there are no third-party beneficiaries to this Agreement. + +4.3. Assignment. Licensee’s rights hereunder are non-assignable, and may not be sublicensed. + +4.4. Equitable Relief. Licensee acknowledges that the remedies available at law for any breach of this Agreement will, by their nature, be inadequate. Accordingly, Licensor may obtain injunctive relief or other equitable relief to restrain a breach or threatened breach of this Agreement or to specifically enforce this Agreement, without proving that any monetary damages have been sustained, and without the requirement of posting of a bond prior to obtaining such equitable relief. + +4.5. Governing Law. This Agreement will be interpreted, construed, and enforced in all respects in accordance with the laws of the State of California, without reference to its conflict of law principles. + +4.6. Attorneys’ Fees. If any legal action, arbitration or other proceeding is brought for the enforcement of this Agreement, or because of an alleged dispute, breach, default, or misrepresentation in connection with any of the provisions of this Agreement, the successful or prevailing party shall be entitled to recover its reasonable attorneys’ fees and other reasonable costs incurred in that action or proceeding, in addition to any other relief to which it may be entitled. + +4.7. Amendment; Waiver. This Agreement may not be amended, nor may any rights under it be waived, except in writing by Licensor. + +4.8. Severability. If any provision of this Agreement is held by a court of competent jurisdiction to be contrary to law, the provision shall be modified by the court and interpreted so as best to accomplish the objectives of the original provision to the fullest extent +permitted by law, and the remaining provisions of this Agreement shall remain in effect. + +4.9. Entire Agreement. This Agreement constitutes the entire agreement between the parties and supersedes all prior and contemporaneous agreements, proposals or representations, written or oral, concerning its subject matter. + + +# Apache License + +Version 2.0, January 2004 + +http://www.apache.org/licenses/ + +## TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. + +"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: + + You must give any other recipients of the Work or Derivative Works a copy of this License; and + You must cause any modified files to carry prominent notices stating that You changed the files; and + You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and + If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. + + You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS diff --git a/bsp/spacemit/k1/coremark/README.md b/bsp/spacemit/k1/coremark/README.md new file mode 100644 index 000000000000..ad89246e9c7b --- /dev/null +++ b/bsp/spacemit/k1/coremark/README.md @@ -0,0 +1,533 @@ +# Coremark + +RT-Thread 上的 MCU/CPU 性能测试小工具,在 menuconfig 里选中软件包后,在 msh 中输入: + +``` +msh> core_mark +``` + +就可以看到跑分结果了,例如: + +### STM32F103RC (72MHZ) Cortex-M3 ARMCC -O3 -Otime 跑分 135: + +``` + \ | / +- RT - Thread Operating System + / | \ 4.0.2 build Oct 13 2019 + 2006 - 2019 Copyright by rt-thread team +msh > +msh >core_mark +Benchmark started, please make sure it runs for at least 10s. + +2K performance run parameters for coremark. +CoreMark Size : 666 +Total ticks : 17776 +Total time (secs): 17.776000 +Iterations/Sec : 135.013501 +Iterations : 2400 +Compiler version : Please put compiler version here (e.g. gcc 4.1) +Compiler flags : +Memory location : STACK +seedcrc : 0xe9f5 +[0]crclist : 0xe714 +[0]crcmatrix : 0x1fd7 +[0]crcstate : 0x8e3a +[0]crcfinal : 0x382f +Correct operation validated. See README.md for run and reporting rules. +CoreMark 1.0 : 135.013501 / Please put compiler version here (e.g. gcc 4.1) / STACK +``` + +### GD32VF103 (108MHz) Cortex-M3 GCC -Os 跑分 327: + +``` + \ | / +- RT - Thread Operating System + / | \ 4.0.2 build Oct 13 2019 + 2006 - 2019 Copyright by rt-thread team +msh > +msh >core_mark +Benchmark started, please make sure it runs for at least 10s. + +2K performance run parameters for coremark. +CoreMark Size : 666 +Total ticks : 1178 +Total time (secs): 11 +Iterations/Sec : 327 +Iterations : 3600 +Compiler version : GCC8.2.0 +Compiler flags : +Memory location : STACK +seedcrc : 0xe9f5 +[0]crclist : 0xe714 +[0]crcmatrix : 0x1fd7 +[0]crcstate : 0x8e3a +[0]crcfinal : 0x4bfc +Correct operation validated. See README.md for run and reporting rules. +CoreMark 1.0 : 327 / GCC8.2.0 / STACK +``` + +### ZYNQ7020 (666MHz) Cortex-A9 GCC -O3 单核跑分 2571: + +``` +\ | / +- RT - Thread Operating System + / | \ 4.0.3 build Nov 23 2020 + 2006 - 2020 Copyright by rt-thread team +msh />core_mark +Benchmark started, please make sure it runs for at least 10s. + +2K performance run parameters for coremark. +CoreMark Size : 666 +Total ticks : 14333 +Total time (secs): 14 +Iterations/Sec : 2571 +Iterations : 36000 +Compiler version : GCC5.4.1 20160919 (release) [ARM/embedded-5-branch revision 240496] +Compiler flags : +Memory location : STACK +seedcrc : 0xe9f5 +[0]crclist : 0xe714 +[0]crcmatrix : 0x1fd7 +[0]crcstate : 0x8e3a +[0]crcfinal : 0xcc42 +Correct operation validated. See README.md for run and reporting rules. +CoreMark 1.0 : 2571 / GCC5.4.1 20160919 (release) [ARM/embedded-5-branch revision 240496] / STACK +``` + +### ZYNQ7045 (800MHz) Cortex-A9 GCC -O3 单核跑分 3000: + +``` +\ | / +- RT - Thread Operating System + / | \ 4.0.3 build Nov 23 2020 + 2006 - 2020 Copyright by rt-thread team +msh />core_mark +Benchmark started, please make sure it runs for at least 10s. + +2K performance run parameters for coremark. +CoreMark Size : 666 +Total ticks : 1251 +Total time (secs): 12 +Iterations/Sec : 3000 +Iterations : 36000 +Compiler version : GCC8.2.0 +Compiler flags : +Memory location : STACK +seedcrc : 0xe9f5 +[0]crclist : 0xe714 +[0]crcmatrix : 0x1fd7 +[0]crcstate : 0x8e3a +[0]crcfinal : 0xcc42 +Correct operation validated. See README.md for run and reporting rules. +CoreMark 1.0 : 3000 / GCC8.2.0 / STACK +``` + +更多测试结果可以在这里看到: + +**https://www.eembc.org/coremark/scores.php** + +## 注意事项 + +- 如果结果希望以小数形式打印,默认会选择 libc 依赖 +- 使用编译器的不同优化等级可能会带来数倍差距的测试结果,例如 GCC O3 优化下的测试分可能会比 O0 优化下高 3-5 倍 +- 测试程序需要运行至少 10s,如果 MCU 性能太强劲一下就结束了,可以适当增加图中的迭代次数 + +![](./iteration.png) + +--------------------------- + +# Introduction + +CoreMark's primary goals are simplicity and providing a method for testing only a processor's core features. For more information about EEMBC's comprehensive embedded benchmark suites, please see www.eembc.org. + +For a more compute-intensive version of CoreMark that uses larger datasets and execution loops taken from common applications, please check out EEMBC's [CoreMark-PRO](https://www.github.com/eembc/coremark-pro) benchmark, also on GitHub. + +# Building and Running + +To build and run the benchmark, type + +`> make` + +Full results are available in the files `run1.log` and `run2.log`. CoreMark result can be found in `run1.log`. + +## Cross Compiling + +For cross compile platforms please adjust `core_portme.mak`, `core_portme.h` (and possibly `core_portme.c`) according to the specific platform used. When porting to a new platform, it is recommended to copy one of the default port folders (e.g. `mkdir && cp linux/* `), adjust the porting files, and run: +~~~ +% make PORT_DIR= +~~~ + +## Make Targets +`run` - Default target, creates `run1.log` and `run2.log`. +`run1.log` - Run the benchmark with performance parameters, and output to `run1.log` +`run2.log` - Run the benchmark with validation parameters, and output to `run2.log` +`run3.log` - Run the benchmark with profile generation parameters, and output to `run3.log` +`compile` - compile the benchmark executable +`link` - link the benchmark executable +`check` - test MD5 of sources that may not be modified +`clean` - clean temporary files + +### Make flag: `ITERATIONS` +By default, the benchmark will run between 10-100 seconds. To override, use `ITERATIONS=N` +~~~ +% make ITERATIONS=10 +~~~ +Will run the benchmark for 10 iterations. It is recommended to set a specific number of iterations in certain situations e.g.: + +* Running with a simulator +* Measuring power/energy +* Timing cannot be restarted + +Minimum required run time: **Results are only valid for reporting if the benchmark ran for at least 10 secs!** + +### Make flag: `XCFLAGS` +To add compiler flags from the command line, use `XCFLAGS` e.g.: + +~~~ +% make XCFLAGS="-g -DMULTITHREAD=4 -DUSE_FORK=1" +~~~ + +### Make flag: `CORE_DEBUG` + +Define to compile for a debug run if you get incorrect CRC. + +~~~ +% make XCFLAGS="-DCORE_DEBUG=1" +~~~ + +### Make flag: `REBUILD` + +Force a rebuild of the executable. + +## Systems Without `make` +The following files need to be compiled: +* `core_list_join.c` +* `core_main.c` +* `core_matrix.c` +* `core_state.c` +* `core_util.c` +* `PORT_DIR/core_portme.c` + +For example: +~~~ +% gcc -O2 -o coremark.exe core_list_join.c core_main.c core_matrix.c core_state.c core_util.c simple/core_portme.c -DPERFORMANCE_RUN=1 -DITERATIONS=1000 +% ./coremark.exe > run1.log +~~~ +The above will compile the benchmark for a performance run and 1000 iterations. Output is redirected to `run1.log`. + +# Parallel Execution +Use `XCFLAGS=-DMULTITHREAD=N` where N is number of threads to run in parallel. Several implementations are available to execute in multiple contexts, or you can implement your own in `core_portme.c`. + +~~~ +% make XCFLAGS="-DMULTITHREAD=4 -DUSE_PTHREAD" +~~~ + +Above will compile the benchmark for execution on 4 cores, using POSIX Threads API. + +# Run Parameters for the Benchmark Executable +CoreMark's executable takes several parameters as follows (but only if `main()` accepts arguments): +1st - A seed value used for initialization of data. +2nd - A seed value used for initialization of data. +3rd - A seed value used for initialization of data. +4th - Number of iterations (0 for auto : default value) +5th - Reserved for internal use. +6th - Reserved for internal use. +7th - For malloc users only, ovreride the size of the input data buffer. + +The run target from make will run coremark with 2 different data initialization seeds. + +## Alternative parameters: +If not using `malloc` or command line arguments are not supported, the buffer size +for the algorithms must be defined via the compiler define `TOTAL_DATA_SIZE`. +`TOTAL_DATA_SIZE` must be set to 2000 bytes (default) for standard runs. +The default for such a target when testing different configurations could be: + +~~~ +% make XCFLAGS="-DTOTAL_DATA_SIZE=6000 -DMAIN_HAS_NOARGC=1" +~~~ + +# Submitting Results + +CoreMark results can be submitted on the web. Open a web browser and go to the [submission page](https://www.eembc.org/coremark/submit.php). After registering an account you may enter a score. + +# Run Rules +What is and is not allowed. + +## Required +1. The benchmark needs to run for at least 10 seconds. +2. All validation must succeed for seeds `0,0,0x66` and `0x3415,0x3415,0x66`, buffer size of 2000 bytes total. + * If not using command line arguments to main: +~~~ + % make XCFLAGS="-DPERFORMANCE_RUN=1" REBUILD=1 run1.log + % make XCFLAGS="-DVALIDATION_RUN=1" REBUILD=1 run2.log +~~~ +3. If using profile guided optimization, profile must be generated using seeds of `8,8,8`, and buffer size of 1200 bytes total. +~~~ + % make XCFLAGS="-DTOTAL_DATA_SIZE=1200 -DPROFILE_RUN=1" REBUILD=1 run3.log +~~~ +4. All source files must be compiled with the same flags. +5. All data type sizes must match size in bits such that: + * `ee_u8` is an unsigned 8-bit datatype. + * `ee_s16` is a signed 16-bit datatype. + * `ee_u16` is an unsigned 16-bit datatype. + * `ee_s32` is a signed 32-bit datatype. + * `ee_u32` is an unsigned 32-bit datatype. + +## Allowed + +1. Changing number of iterations +2. Changing toolchain and build/load/run options +3. Changing method of acquiring a data memory block +5. Changing the method of acquiring seed values +6. Changing implementation `in core_portme.c` +7. Changing configuration values in `core_portme.h` +8. Changing `core_portme.mak` + +## NOT ALLOWED +1. Changing of source file other then `core_portme*` (use `make check` to validate) + +# Reporting rules +Use the following syntax to report results on a data sheet: + +CoreMark 1.0 : N / C [/ P] [/ M] + +N - Number of iterations per second with seeds 0,0,0x66,size=2000) + +C - Compiler version and flags + +P - Parameters such as data and code allocation specifics + +* This parameter *may* be omitted if all data was allocated on the heap in RAM. +* This parameter *may not* be omitted when reporting CoreMark/MHz + +M - Type of parallel execution (if used) and number of contexts +* This parameter may be omitted if parallel execution was not used. + +e.g.: + +~~~ +CoreMark 1.0 : 128 / GCC 4.1.2 -O2 -fprofile-use / Heap in TCRAM / FORK:2 +~~~ +or +~~~ +CoreMark 1.0 : 1400 / GCC 3.4 -O4 +~~~ + +If reporting scaling results, the results must be reported as follows: + +CoreMark/MHz 1.0 : N / C / P [/ M] + +P - When reporting scaling results, memory parameter must also indicate memory frequency:core frequency ratio. +1. If the core has cache and cache frequency to core frequency ratio is configurable, that must also be included. + +e.g.: + +~~~ +CoreMark/MHz 1.0 : 1.47 / GCC 4.1.2 -O2 / DDR3(Heap) 30:1 Memory 1:1 Cache +~~~ + +# Log File Format +The log files have the following format + +~~~ +2K performance run parameters for coremark. (Run type) +CoreMark Size : 666 (Buffer size) +Total ticks : 25875 (platform dependent value) +Total time (secs) : 25.875000 (actual time in seconds) +Iterations/Sec : 3864.734300 (Performance value to report) +Iterations : 100000 (number of iterations used) +Compiler version : GCC3.4.4 (Compiler and version) +Compiler flags : -O2 (Compiler and linker flags) +Memory location : Code in flash, data in on chip RAM +seedcrc : 0xe9f5 (identifier for the input seeds) +[0]crclist : 0xe714 (validation for list part) +[0]crcmatrix : 0x1fd7 (validation for matrix part) +[0]crcstate : 0x8e3a (validation for state part) +[0]crcfinal : 0x33ff (iteration dependent output) +Correct operation validated. See README.md for run and reporting rules. (*Only when run is successful*) +CoreMark 1.0 : 6508.490622 / GCC3.4.4 -O2 / Heap (*Only on a successful performance run*) +~~~ + +# Theory of Operation + +This section describes the initial goals of CoreMark and their implementation. + +## Small and easy to understand + +* X number of source code lines for timed portion of the benchmark. +* Meaningful names for variables and functions. +* Comments for each block of code more than 10 lines long. + +## Portability + +A thin abstraction layer will be provided for I/O and timing in a separate file. All I/O and timing of the benchmark will be done through this layer. + +### Code / data size + +* Compile with gcc on x86 and make sure all sizes are according to requirements. +* If dynamic memory allocation is used, take total memory allocated into account as well. +* Avoid recursive functions and keep track of stack usage. +* Use the same memory block as data site for all algorithms, and initialize the data before each algorithm – while this means that initialization with data happens during the timed portion, it will only happen once during the timed portion and so have negligible effect on the results. + +## Controlled output + +This may be the most difficult goal. Compilers are constantly improving and getting better at analyzing code. To create work that cannot be computed at compile time and must be computed at run time, we will rely on two assumptions: + +* Some system functions (e.g. time, scanf) and parameters cannot be computed at compile time. In most cases, marking a variable volatile means the compiler is force to read this variable every time it is read. This will be used to introduce a factor into the input that cannot be precomputed at compile time. Since the results are input dependent, that will make sure that computation has to happen at run time. + +* Either a system function or I/O (e.g. scanf) or command line parameters or volatile variables will be used before the timed portion to generate data which is not available at compile time. Specific method used is not relevant as long as it can be controlled, and that it cannot be computed or eliminated by the compiler at compile time. E.g. if the clock() functions is a compiler stub, it may not be used. The derived values will be reported on the output so that verification can be done on a different machine. + +* We cannot rely on command line parameters since some embedded systems do not have the capability to provide command line parameters. All 3 methods above will be implemented (time based, scanf and command line parameters) and all 3 are valid if the compiler cannot determine the value at compile time. + +* It is important to note that The actual values that are to be supplied at run time will be standardized. The methodology is not intended to provide random data, but simply to provide controlled data that cannot be precomputed at compile time. + +* Printed results must be valid at run time. This will be used to make sure the computation has been executed. + +* Some embedded systems do not provide “printf” or other I/O functionality. All I/O will be done through a thin abstraction interface to allow execution on such systems (e.g. allow output via JTAG). + +## Key Algorithms + +### Linked List + +The following linked list structure will be used: + +~~~ +typedef struct list_data_s { + ee_s16 data16; + ee_s16 idx; +} list_data; + +typedef struct list_head_s { + struct list_head_s *next; + struct list_data_s *info; +} list_head; +~~~ + +While adding a level of indirection accessing the data, this structure is realistic and used in many embedded applications for small to medium lists. + +The list itself will be initialized on a block of memory that will be passed in to the initialization function. While in general linked lists use malloc for new nodes, embedded applications sometime control the memory for small data structures such as arrays and lists directly to avoid the overhead of system calls, so this approach is realistic. + +The linked list will be initialized such that 1/4 of the list pointers point to sequential areas in memory, and 3/4 of the list pointers are distributed in a non sequential manner. This is done to emulate a linked list that had add/remove happen for a while disrupting the neat order, and then a series of adds that are likely to come from sequential memory locations. + +For the benchmark itself: +- Multiple find operations are going to be performed. These find operations may result in the whole list being traversed. The result of each find will become part of the output chain. +- The list will be sorted using merge sort based on the data16 value, and then derive CRC of the data16 item in order for part of the list. The CRC will become part of the output chain. +- The list will be sorted again using merge sort based on the idx value. This sort will guarantee that the list is returned to the primary state before leaving the function, so that multiple iterations of the function will have the same result. CRC of the data16 for part of the list will again be calculated and become part of the output chain. + +The actual `data16` in each cell will be pseudo random based on a single 16b input that cannot be determined at compile time. In addition, the part of the list which is used for CRC will also be passed to the function, and determined based on an input that cannot be determined at run time. + +### Matrix Multiply + +This very simple algorithm forms the basis of many more complex algorithms. The tight inner loop is the focus of many optimizations (compiler as well as hardware based) and is thus relevant for embedded processing. + +The total available data space will be divided to 3 parts: +1. NxN matrix A. +2. NxN matrix B. +3. NxN matrix C. + +E.g. for 2K we will have 3 12x12 matrices (assuming data type of 32b 12(len)*12(wid)*4(size)*3(num) =1728 bytes). + +Matrix A will be initialized with small values (upper 3/4 of the bits all zero). +Matrix B will be initialized with medium values (upper half of the bits all zero). +Matrix C will be used for the result. + +For the benchmark itself: +- Multiple A by a constant into C, add the upper bits of each of the values in the result matrix. The result will become part of the output chain. +- Multiple A by column X of B into C, add the upper bits of each of the values in the result matrix. The result will become part of the output chain. +- Multiple A by B into C, add the upper bits of each of the values in the result matrix. The result will become part of the output chain. + +The actual values for A and B must be derived based on input that is not available at compile time. + +### State Machine + +This part of the code needs to exercise switch and if statements. As such, we will use a small Moore state machine. In particular, this will be a state machine that identifies string input as numbers and divides them according to format. + +The state machine will parse the input string until either a “,” separator or end of input is encountered. An invalid number will cause the state machine to return invalid state and a valid number will cause the state machine to return with type of number format (int/float/scientific). + +This code will perform a realistic task, be small enough to easily understand, and exercise the required functionality. The other option used in embedded systems is a mealy based state machine, which is driven by a table. The table then determines the number of states and complexity of transitions. This approach, however, tests mainly the load/store and function call mechanisms and less the handling of branches. If analysis of the final results shows that the load/store functionality of the processor is not exercised thoroughly, it may be a good addition to the benchmark (codesize allowing). + +For input, the memory block will be initialized with comma separated values of mixed formats, as well as invalid inputs. + +For the benchmark itself: +- Invoke the state machine on all of the input and count final states and state transitions. CRC of all final states and transitions will become part of the output chain. +- Modify the input at intervals (inject errors) and repeat the state machine operation. +- Modify the input back to original form. + +The actual input must be initialized based on data that cannot be determined at compile time. In addition the intervals for modification of the input and the actual modification must be based on input that cannot be determined at compile time. + +# Validation + +This release was tested on the following platforms: +* x86 cygwin and gcc 3.4 (Quad, dual and single core systems) +* x86 linux (Ubuntu/Fedora) and gcc (4.2/4.1) (Quad and single core systems) +* MIPS64 BE linux and gcc 3.4 16 cores system +* MIPS32 BE linux with CodeSourcery compiler 4.2-177 on Malta/Linux with a 1004K 3-core system +* PPC simulator with gcc 4.2.2 (No OS) +* PPC 64b BE linux (yellowdog) with gcc 3.4 and 4.1 (Dual core system) +* BF533 with VDSP50 +* Renesas R8C/H8 MCU with HEW 4.05 +* NXP LPC1700 armcc v4.0.0.524 +* NEC 78K with IAR v4.61 +* ARM simulator with armcc v4 + +# Memory Analysis + +Valgrind 3.4.0 used and no errors reported. + +# Balance Analysis + +Number of instructions executed for each function tested with cachegrind and found balanced with gcc and -O0. + +# Statistics + +Lines: +~~~ +Lines Blank Cmnts Source AESL +===== ===== ===== ===== ========== ======================================= + 469 66 170 251 627.5 core_list_join.c (C) + 330 18 54 268 670.0 core_main.c (C) + 256 32 80 146 365.0 core_matrix.c (C) + 240 16 51 186 465.0 core_state.c (C) + 165 11 20 134 335.0 core_util.c (C) + 150 23 36 98 245.0 coremark.h (C) + 1610 166 411 1083 2707.5 ----- Benchmark ----- (6 files) + 293 15 74 212 530.0 linux/core_portme.c (C) + 235 30 104 104 260.0 linux/core_portme.h (C) + 528 45 178 316 790.0 ----- Porting ----- (2 files) + +* For comparison, here are the stats for Dhrystone +Lines Blank Cmnts Source AESL +===== ===== ===== ===== ========== ======================================= + 311 15 242 54 135.0 dhry.h (C) + 789 132 119 553 1382.5 dhry_1.c (C) + 186 26 68 107 267.5 dhry_2.c (C) + 1286 173 429 714 1785.0 ----- C ----- (3 files) +~~~ + +# Credits +Many thanks to all of the individuals who helped with the development or testing of CoreMark including (Sorted by company name; note that company names may no longer be accurate as this was written in 2009). +* Alan Anderson, ADI +* Adhikary Rajiv, ADI +* Elena Stohr, ARM +* Ian Rickards, ARM +* Andrew Pickard, ARM +* Trent Parker, CAVIUM +* Shay Gal-On, EEMBC +* Markus Levy, EEMBC +* Peter Torelli, EEMBC +* Ron Olson, IBM +* Eyal Barzilay, MIPS +* Jens Eltze, NEC +* Hirohiko Ono, NEC +* Ulrich Drees, NEC +* Frank Roscheda, NEC +* Rob Cosaro, NXP +* Shumpei Kawasaki, RENESAS + +# Legal +Please refer to LICENSE.md in this reposity for a description of your rights to use this code. + +# Copyright +Copyright © 2009 EEMBC All rights reserved. +CoreMark is a trademark of EEMBC and EEMBC is a registered trademark of the Embedded Microprocessor Benchmark Consortium. + diff --git a/bsp/spacemit/k1/coremark/SConscript b/bsp/spacemit/k1/coremark/SConscript new file mode 100644 index 000000000000..68a4a01ee3c5 --- /dev/null +++ b/bsp/spacemit/k1/coremark/SConscript @@ -0,0 +1,15 @@ +from building import * +import rtconfig + +# get current directory +cwd = GetCurrentDir() +# The set of source files associated with this SConscript file. +src = Glob('*.c') + +path = [cwd + '/'] + +LOCAL_CCFLAGS = '' + +group = DefineGroup('coremark', src, depend = [''], CPPPATH = path, LOCAL_CCFLAGS = LOCAL_CCFLAGS) + +Return('group') diff --git a/bsp/spacemit/k1/coremark/core_list_join.c b/bsp/spacemit/k1/coremark/core_list_join.c new file mode 100644 index 000000000000..a5154284a375 --- /dev/null +++ b/bsp/spacemit/k1/coremark/core_list_join.c @@ -0,0 +1,495 @@ +/* +Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +Original Author: Shay Gal-on +*/ + +#include "coremark.h" +/* +Topic: Description + Benchmark using a linked list. + + Linked list is a common data structure used in many applications. + + For our purposes, this will excercise the memory units of the processor. + In particular, usage of the list pointers to find and alter data. + + We are not using Malloc since some platforms do not support this library. + + Instead, the memory block being passed in is used to create a list, + and the benchmark takes care not to add more items then can be + accomodated by the memory block. The porting layer will make sure + that we have a valid memory block. + + All operations are done in place, without using any extra memory. + + The list itself contains list pointers and pointers to data items. + Data items contain the following: + + idx - An index that captures the initial order of the list. + data - Variable data initialized based on the input parameters. The 16b are divided as follows: + o Upper 8b are backup of original data. + o Bit 7 indicates if the lower 7 bits are to be used as is or calculated. + o Bits 0-2 indicate type of operation to perform to get a 7b value. + o Bits 3-6 provide input for the operation. + +*/ + +/* local functions */ + +list_head *core_list_find(list_head *list,list_data *info); +list_head *core_list_reverse(list_head *list); +list_head *core_list_remove(list_head *item); +list_head *core_list_undo_remove(list_head *item_removed, list_head *item_modified); +list_head *core_list_insert_new(list_head *insert_point + , list_data *info, list_head **memblock, list_data **datablock + , list_head *memblock_end, list_data *datablock_end); +typedef ee_s32(*list_cmp)(list_data *a, list_data *b, core_results *res); +list_head *core_list_mergesort(list_head *list, list_cmp cmp, core_results *res); + +ee_s16 calc_func(ee_s16 *pdata, core_results *res) { + ee_s16 data=*pdata; + ee_s16 retval; + ee_u8 optype=(data>>7) & 1; /* bit 7 indicates if the function result has been cached */ + if (optype) /* if cached, use cache */ + return (data & 0x007f); + else { /* otherwise calculate and cache the result */ + ee_s16 flag=data & 0x7; /* bits 0-2 is type of function to perform */ + ee_s16 dtype=((data>>3) & 0xf); /* bits 3-6 is specific data for the operation */ + dtype |= dtype << 4; /* replicate the lower 4 bits to get an 8b value */ + switch (flag) { + case 0: + if (dtype<0x22) /* set min period for bit corruption */ + dtype=0x22; + retval=core_bench_state(res->size,res->memblock[3],res->seed1,res->seed2,dtype,res->crc); + if (res->crcstate==0) + res->crcstate=retval; + break; + case 1: + retval=core_bench_matrix(&(res->mat),dtype,res->crc); + if (res->crcmatrix==0) + res->crcmatrix=retval; + break; + default: + retval=data; + break; + } + res->crc=crcu16(retval,res->crc); + retval &= 0x007f; + *pdata = (data & 0xff00) | 0x0080 | retval; /* cache the result */ + return retval; + } +} +/* Function: cmp_complex + Compare the data item in a list cell. + + Can be used by mergesort. +*/ +ee_s32 cmp_complex(list_data *a, list_data *b, core_results *res) { + ee_s16 val1=calc_func(&(a->data16),res); + ee_s16 val2=calc_func(&(b->data16),res); + return val1 - val2; +} + +/* Function: cmp_idx + Compare the idx item in a list cell, and regen the data. + + Can be used by mergesort. +*/ +ee_s32 cmp_idx(list_data *a, list_data *b, core_results *res) { + if (res==NULL) { + a->data16 = (a->data16 & 0xff00) | (0x00ff & (a->data16>>8)); + b->data16 = (b->data16 & 0xff00) | (0x00ff & (b->data16>>8)); + } + return a->idx - b->idx; +} + +void copy_info(list_data *to,list_data *from) { + to->data16=from->data16; + to->idx=from->idx; +} + +/* Benchmark for linked list: + - Try to find multiple data items. + - List sort + - Operate on data from list (crc) + - Single remove/reinsert + * At the end of this function, the list is back to original state +*/ +ee_u16 core_bench_list(core_results *res, ee_s16 finder_idx) { + ee_u16 retval=0; + ee_u16 found=0,missed=0; + list_head *list=res->list; + ee_s16 find_num=res->seed3; + list_head *this_find; + list_head *finder, *remover; + list_data info; + ee_s16 i; + + info.idx=finder_idx; + /* find values in the list, and change the list each time (reverse and cache if value found) */ + for (i=0; inext->info->data16 >> 8) & 1; + } + else { + found++; + if (this_find->info->data16 & 0x1) /* use found value */ + retval+=(this_find->info->data16 >> 9) & 1; + /* and cache next item at the head of the list (if any) */ + if (this_find->next != NULL) { + finder = this_find->next; + this_find->next = finder->next; + finder->next=list->next; + list->next=finder; + } + } + if (info.idx>=0) + info.idx++; +#if CORE_DEBUG + ee_printf("List find %d: [%d,%d,%d]\n",i,retval,missed,found); +#endif + } + retval+=found*4-missed; + /* sort the list by data content and remove one item*/ + if (finder_idx>0) + list=core_list_mergesort(list,cmp_complex,res); + remover=core_list_remove(list->next); + /* CRC data content of list from location of index N forward, and then undo remove */ + finder=core_list_find(list,&info); + if (!finder) + finder=list->next; + while (finder) { + retval=crc16(list->info->data16,retval); + finder=finder->next; + } +#if CORE_DEBUG + ee_printf("List sort 1: %04x\n",retval); +#endif + remover=core_list_undo_remove(remover,list->next); + /* sort the list by index, in effect returning the list to original state */ + list=core_list_mergesort(list,cmp_idx,NULL); + /* CRC data content of list */ + finder=list->next; + while (finder) { + retval=crc16(list->info->data16,retval); + finder=finder->next; + } +#if CORE_DEBUG + ee_printf("List sort 2: %04x\n",retval); +#endif + return retval; +} +/* Function: core_list_init + Initialize list with data. + + Parameters: + blksize - Size of memory to be initialized. + memblock - Pointer to memory block. + seed - Actual values chosen depend on the seed parameter. + The seed parameter MUST be supplied from a source that cannot be determined at compile time + + Returns: + Pointer to the head of the list. + +*/ +list_head *core_list_init(ee_u32 blksize, list_head *memblock, ee_s16 seed) { + /* calculated pointers for the list */ + ee_u32 per_item=16+sizeof(struct list_data_s); + ee_u32 size=(blksize/per_item)-2; /* to accomodate systems with 64b pointers, and make sure same code is executed, set max list elements */ + list_head *memblock_end=memblock+size; + list_data *datablock=(list_data *)(memblock_end); + list_data *datablock_end=datablock+size; + /* some useful variables */ + ee_u32 i; + list_head *finder,*list=memblock; + list_data info; + + /* create a fake items for the list head and tail */ + list->next=NULL; + list->info=datablock; + list->info->idx=0x0000; + list->info->data16=(ee_s16)0x8080; + memblock++; + datablock++; + info.idx=0x7fff; + info.data16=(ee_s16)0xffff; + core_list_insert_new(list,&info,&memblock,&datablock,memblock_end,datablock_end); + + /* then insert size items */ + for (i=0; inext; + i=1; + while (finder->next!=NULL) { + if (iinfo->idx=i++; + else { + ee_u16 pat=(ee_u16)(i++ ^ seed); /* get a pseudo random number */ + finder->info->idx=0x3fff & (((i & 0x07) << 8) | pat); /* make sure the mixed items end up after the ones in sequence */ + } + finder=finder->next; + } + list = core_list_mergesort(list,cmp_idx,NULL); +#if CORE_DEBUG + ee_printf("Initialized list:\n"); + finder=list; + while (finder) { + ee_printf("[%04x,%04x]",finder->info->idx,(ee_u16)finder->info->data16); + finder=finder->next; + } + ee_printf("\n"); +#endif + return list; +} + +/* Function: core_list_insert + Insert an item to the list + + Parameters: + insert_point - where to insert the item. + info - data for the cell. + memblock - pointer for the list header + datablock - pointer for the list data + memblock_end - end of region for list headers + datablock_end - end of region for list data + + Returns: + Pointer to new item. +*/ +list_head *core_list_insert_new(list_head *insert_point, list_data *info, list_head **memblock, list_data **datablock + , list_head *memblock_end, list_data *datablock_end) { + list_head *newitem; + + if ((*memblock+1) >= memblock_end) + return NULL; + if ((*datablock+1) >= datablock_end) + return NULL; + + newitem=*memblock; + (*memblock)++; + newitem->next=insert_point->next; + insert_point->next=newitem; + + newitem->info=*datablock; + (*datablock)++; + copy_info(newitem->info,info); + + return newitem; +} + +/* Function: core_list_remove + Remove an item from the list. + + Operation: + For a singly linked list, remove by copying the data from the next item + over to the current cell, and unlinking the next item. + + Note: + since there is always a fake item at the end of the list, no need to check for NULL. + + Returns: + Removed item. +*/ +list_head *core_list_remove(list_head *item) { + list_data *tmp; + list_head *ret=item->next; + /* swap data pointers */ + tmp=item->info; + item->info=ret->info; + ret->info=tmp; + /* and eliminate item */ + item->next=item->next->next; + ret->next=NULL; + return ret; +} + +/* Function: core_list_undo_remove + Undo a remove operation. + + Operation: + Since we want each iteration of the benchmark to be exactly the same, + we need to be able to undo a remove. + Link the removed item back into the list, and switch the info items. + + Parameters: + item_removed - Return value from the + item_modified - List item that was modified during + + Returns: + The item that was linked back to the list. + +*/ +list_head *core_list_undo_remove(list_head *item_removed, list_head *item_modified) { + list_data *tmp; + /* swap data pointers */ + tmp=item_removed->info; + item_removed->info=item_modified->info; + item_modified->info=tmp; + /* and insert item */ + item_removed->next=item_modified->next; + item_modified->next=item_removed; + return item_removed; +} + +/* Function: core_list_find + Find an item in the list + + Operation: + Find an item by idx (if not 0) or specific data value + + Parameters: + list - list head + info - idx or data to find + + Returns: + Found item, or NULL if not found. +*/ +list_head *core_list_find(list_head *list,list_data *info) { + if (info->idx>=0) { + while (list && (list->info->idx != info->idx)) + list=list->next; + return list; + } else { + while (list && ((list->info->data16 & 0xff) != info->data16)) + list=list->next; + return list; + } +} +/* Function: core_list_reverse + Reverse a list + + Operation: + Rearrange the pointers so the list is reversed. + + Parameters: + list - list head + info - idx or data to find + + Returns: + Found item, or NULL if not found. +*/ + +list_head *core_list_reverse(list_head *list) { + list_head *next=NULL, *tmp; + while (list) { + tmp=list->next; + list->next=next; + next=list; + list=tmp; + } + return next; +} +/* Function: core_list_mergesort + Sort the list in place without recursion. + + Description: + Use mergesort, as for linked list this is a realistic solution. + Also, since this is aimed at embedded, care was taken to use iterative rather then recursive algorithm. + The sort can either return the list to original order (by idx) , + or use the data item to invoke other other algorithms and change the order of the list. + + Parameters: + list - list to be sorted. + cmp - cmp function to use + + Returns: + New head of the list. + + Note: + We have a special header for the list that will always be first, + but the algorithm could theoretically modify where the list starts. + + */ +list_head *core_list_mergesort(list_head *list, list_cmp cmp, core_results *res) { + list_head *p, *q, *e, *tail; + ee_s32 insize, nmerges, psize, qsize, i; + + insize = 1; + + while (1) { + p = list; + list = NULL; + tail = NULL; + + nmerges = 0; /* count number of merges we do in this pass */ + + while (p) { + nmerges++; /* there exists a merge to be done */ + /* step `insize' places along from p */ + q = p; + psize = 0; + for (i = 0; i < insize; i++) { + psize++; + q = q->next; + if (!q) break; + } + + /* if q hasn't fallen off end, we have two lists to merge */ + qsize = insize; + + /* now we have two lists; merge them */ + while (psize > 0 || (qsize > 0 && q)) { + + /* decide whether next element of merge comes from p or q */ + if (psize == 0) { + /* p is empty; e must come from q. */ + e = q; q = q->next; qsize--; + } else if (qsize == 0 || !q) { + /* q is empty; e must come from p. */ + e = p; p = p->next; psize--; + } else if (cmp(p->info,q->info,res) <= 0) { + /* First element of p is lower (or same); e must come from p. */ + e = p; p = p->next; psize--; + } else { + /* First element of q is lower; e must come from q. */ + e = q; q = q->next; qsize--; + } + + /* add the next element to the merged list */ + if (tail) { + tail->next = e; + } else { + list = e; + } + tail = e; + } + + /* now p has stepped `insize' places along, and q has too */ + p = q; + } + + tail->next = NULL; + + /* If we have done only one merge, we're finished. */ + if (nmerges <= 1) /* allow for nmerges==0, the empty list case */ + return list; + + /* Otherwise repeat, merging lists twice the size */ + insize *= 2; + } +#if COMPILER_REQUIRES_SORT_RETURN + return list; +#endif +} diff --git a/bsp/spacemit/k1/coremark/core_main.c b/bsp/spacemit/k1/coremark/core_main.c new file mode 100644 index 000000000000..fb6afe089934 --- /dev/null +++ b/bsp/spacemit/k1/coremark/core_main.c @@ -0,0 +1,369 @@ +/* +Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +Original Author: Shay Gal-on +*/ + +/* File: core_main.c + This file contains the framework to acquire a block of memory, seed initial parameters, tun t he benchmark and report the results. +*/ +#include "coremark.h" +#include +/* Function: iterate + Run the benchmark for a specified number of iterations. + + Operation: + For each type of benchmarked algorithm: + a - Initialize the data block for the algorithm. + b - Execute the algorithm N times. + + Returns: + NULL. +*/ +static ee_u16 list_known_crc[] = {(ee_u16)0xd4b0,(ee_u16)0x3340,(ee_u16)0x6a79,(ee_u16)0xe714,(ee_u16)0xe3c1}; +static ee_u16 matrix_known_crc[] = {(ee_u16)0xbe52,(ee_u16)0x1199,(ee_u16)0x5608,(ee_u16)0x1fd7,(ee_u16)0x0747}; +static ee_u16 state_known_crc[] = {(ee_u16)0x5e47,(ee_u16)0x39bf,(ee_u16)0xe5a4,(ee_u16)0x8e3a,(ee_u16)0x8d84}; +void *iterate(void *pres) { + ee_u32 i; + ee_u16 crc; + core_results *res=(core_results *)pres; + ee_u32 iterations=res->iterations; + res->crc=0; + res->crclist=0; + res->crcmatrix=0; + res->crcstate=0; + + for (i=0; icrc=crcu16(crc,res->crc); + crc=core_bench_list(res,-1); + res->crc=crcu16(crc,res->crc); + if (i==0) res->crclist=res->crc; + } + return NULL; +} + +#if (SEED_METHOD==SEED_ARG) +ee_s32 get_seed_args(int i, int argc, char *argv[]); +#define get_seed(x) (ee_s16)get_seed_args(x,argc,argv) +#define get_seed_32(x) get_seed_args(x,argc,argv) +#else /* via function or volatile */ +ee_s32 get_seed_32(int i); +#define get_seed(x) (ee_s16)get_seed_32(x) +#endif + +#if (MEM_METHOD==MEM_STATIC) +ee_u8 static_memblk[TOTAL_DATA_SIZE]; +#endif +char *mem_name[3] = {"Static","Heap","Stack"}; +/* Function: main + Main entry routine for the benchmark. + This function is responsible for the following steps: + + 1 - Initialize input seeds from a source that cannot be determined at compile time. + 2 - Initialize memory block for use. + 3 - Run and time the benchmark. + 4 - Report results, testing the validity of the output if the seeds are known. + + Arguments: + 1 - first seed : Any value + 2 - second seed : Must be identical to first for iterations to be identical + 3 - third seed : Any value, should be at least an order of magnitude less then the input size, but bigger then 32. + 4 - Iterations : Special, if set to 0, iterations will be automatically determined such that the benchmark will run between 10 to 100 secs + +*/ + +#if MAIN_HAS_NOARGC +MAIN_RETURN_TYPE core_mark(void) { + int argc=0; + char *argv[1]; +#else +MAIN_RETURN_TYPE core_mark(int argc, char *argv[]) { +#endif + ee_u16 i,j=0,num_algorithms=0; + ee_s16 known_id=-1,total_errors=0; + ee_u16 seedcrc=0; + CORE_TICKS total_time; + core_results results[MULTITHREAD]; +#if (MEM_METHOD==MEM_STACK) + ee_u8 stack_memblock[TOTAL_DATA_SIZE*MULTITHREAD]; +#endif + /* first call any initializations needed */ + portable_init(&(results[0].port), &argc, argv); + /* First some checks to make sure benchmark will run ok */ + if (sizeof(struct list_head_s)>128) { + ee_printf("list_head structure too big for comparable data!\n"); + return MAIN_RETURN_VAL; + } + results[0].seed1=get_seed(1); + results[0].seed2=get_seed(2); + results[0].seed3=get_seed(3); + results[0].iterations=get_seed_32(4); +#if CORE_DEBUG + results[0].iterations=1; +#endif + results[0].execs=get_seed_32(5); + if (results[0].execs==0) { /* if not supplied, execute all algorithms */ + results[0].execs=ALL_ALGORITHMS_MASK; + } + /* put in some default values based on one seed only for easy testing */ + if ((results[0].seed1==0) && (results[0].seed2==0) && (results[0].seed3==0)) { /* validation run */ + results[0].seed1=0; + results[0].seed2=0; + results[0].seed3=0x66; + } + if ((results[0].seed1==1) && (results[0].seed2==0) && (results[0].seed3==0)) { /* perfromance run */ + results[0].seed1=0x3415; + results[0].seed2=0x3415; + results[0].seed3=0x66; + } +#if (MEM_METHOD==MEM_STATIC) + results[0].memblock[0]=(void *)static_memblk; + results[0].size=TOTAL_DATA_SIZE; + results[0].err=0; + #if (MULTITHREAD>1) + #error "Cannot use a static data area with multiple contexts!" + #endif +#elif (MEM_METHOD==MEM_MALLOC) + for (i=0 ; i1) + if (default_num_contexts>MULTITHREAD) { + default_num_contexts=MULTITHREAD; + } + for (i=0 ; i=0) { + for (i=0 ; i 0) + ee_printf("Iterations/Sec : %f\n",default_num_contexts*results[0].iterations/time_in_secs(total_time)); +#else + ee_printf("Total time (secs): %d\n",time_in_secs(total_time)); + if (time_in_secs(total_time) > 0) + ee_printf("Iterations/Sec : %d\n",default_num_contexts*results[0].iterations/time_in_secs(total_time)); +#endif + if (time_in_secs(total_time) < 10) { + ee_printf("ERROR! Must execute for at least 10 secs for a valid result!\n"); + total_errors++; + } + + ee_printf("Iterations : %lu\n", (long unsigned) default_num_contexts*results[0].iterations); + ee_printf("Compiler version : %s\n",COMPILER_VERSION); + ee_printf("Compiler flags : %s\n",COMPILER_FLAGS); +#if (MULTITHREAD>1) + ee_printf("Parallel %s : %d\n",PARALLEL_METHOD,default_num_contexts); +#endif + ee_printf("Memory location : %s\n",MEM_LOCATION); + /* output for verification */ + ee_printf("seedcrc : 0x%04x\n",seedcrc); + if (results[0].execs & ID_LIST) + for (i=0 ; i1) + ee_printf(" / %d:%s",default_num_contexts,PARALLEL_METHOD); +#endif + ee_printf("\n"); + } +#else + if (known_id==3) { + ee_printf("CoreMark 1.0 : %d / %s %s",default_num_contexts*results[0].iterations/time_in_secs(total_time),COMPILER_VERSION,COMPILER_FLAGS); +#if defined(MEM_LOCATION) && !defined(MEM_LOCATION_UNSPEC) + ee_printf(" / %s",MEM_LOCATION); +#else + ee_printf(" / %s",mem_name[MEM_METHOD]); +#endif + +#if (MULTITHREAD>1) + ee_printf(" / %d:%s",default_num_contexts,PARALLEL_METHOD); +#endif + ee_printf("\n"); + } +#endif + } + if (total_errors>0) + ee_printf("Errors detected\n"); + if (total_errors<0) + ee_printf("Cannot validate operation for these seed values, please compare with results on a known platform.\n"); + +#if (MEM_METHOD==MEM_MALLOC) + for (i=0 ; i>(from)) & (~(0xffffffff << (to)))) + +#if CORE_DEBUG +void printmat(MATDAT *A, ee_u32 N, char *name) { + ee_u32 i,j; + ee_printf("Matrix %s [%dx%d]:\n",name,N,N); + for (i=0; i N times, + changing the matrix values slightly by a constant amount each time. +*/ +ee_u16 core_bench_matrix(mat_params *p, ee_s16 seed, ee_u16 crc) { + ee_u32 N=p->N; + MATRES *C=p->C; + MATDAT *A=p->A; + MATDAT *B=p->B; + MATDAT val=(MATDAT)seed; + + crc=crc16(matrix_test(N,C,A,B,val),crc); + + return crc; +} + +/* Function: matrix_test + Perform matrix manipulation. + + Parameters: + N - Dimensions of the matrix. + C - memory for result matrix. + A - input matrix + B - operator matrix (not changed during operations) + + Returns: + A CRC value that captures all results calculated in the function. + In particular, crc of the value calculated on the result matrix + after each step by . + + Operation: + + 1 - Add a constant value to all elements of a matrix. + 2 - Multiply a matrix by a constant. + 3 - Multiply a matrix by a vector. + 4 - Multiply a matrix by a matrix. + 5 - Add a constant value to all elements of a matrix. + + After the last step, matrix A is back to original contents. +*/ +ee_s16 matrix_test(ee_u32 N, MATRES *C, MATDAT *A, MATDAT *B, MATDAT val) { + ee_u16 crc=0; + MATDAT clipval=matrix_big(val); + + matrix_add_const(N,A,val); /* make sure data changes */ +#if CORE_DEBUG + printmat(A,N,"matrix_add_const"); +#endif + matrix_mul_const(N,C,A,val); + crc=crc16(matrix_sum(N,C,clipval),crc); +#if CORE_DEBUG + printmatC(C,N,"matrix_mul_const"); +#endif + matrix_mul_vect(N,C,A,B); + crc=crc16(matrix_sum(N,C,clipval),crc); +#if CORE_DEBUG + printmatC(C,N,"matrix_mul_vect"); +#endif + matrix_mul_matrix(N,C,A,B); + crc=crc16(matrix_sum(N,C,clipval),crc); +#if CORE_DEBUG + printmatC(C,N,"matrix_mul_matrix"); +#endif + matrix_mul_matrix_bitextract(N,C,A,B); + crc=crc16(matrix_sum(N,C,clipval),crc); +#if CORE_DEBUG + printmatC(C,N,"matrix_mul_matrix_bitextract"); +#endif + + matrix_add_const(N,A,-val); /* return matrix to initial value */ + return crc; +} + +/* Function : matrix_init + Initialize the memory block for matrix benchmarking. + + Parameters: + blksize - Size of memory to be initialized. + memblk - Pointer to memory block. + seed - Actual values chosen depend on the seed parameter. + p - pointers to containing initialized matrixes. + + Returns: + Matrix dimensions. + + Note: + The seed parameter MUST be supplied from a source that cannot be determined at compile time +*/ +ee_u32 core_init_matrix(ee_u32 blksize, void *memblk, ee_s32 seed, mat_params *p) { + ee_u32 N=0; + MATDAT *A; + MATDAT *B; + ee_s32 order=1; + MATDAT val; + ee_u32 i=0,j=0; + if (seed==0) + seed=1; + while (jA=A; + p->B=B; + p->C=(MATRES *)align_mem(B+N*N); + p->N=N; +#if CORE_DEBUG + printmat(A,N,"A"); + printmat(B,N,"B"); +#endif + return N; +} + +/* Function: matrix_sum + Calculate a function that depends on the values of elements in the matrix. + + For each element, accumulate into a temporary variable. + + As long as this value is under the parameter clipval, + add 1 to the result if the element is bigger then the previous. + + Otherwise, reset the accumulator and add 10 to the result. +*/ +ee_s16 matrix_sum(ee_u32 N, MATRES *C, MATDAT clipval) { + MATRES tmp=0,prev=0,cur=0; + ee_s16 ret=0; + ee_u32 i,j; + for (i=0; iclipval) { + ret+=10; + tmp=0; + } else { + ret += (cur>prev) ? 1 : 0; + } + prev=cur; + } + } + return ret; +} + +/* Function: matrix_mul_const + Multiply a matrix by a constant. + This could be used as a scaler for instance. +*/ +void matrix_mul_const(ee_u32 N, MATRES *C, MATDAT *A, MATDAT val) { + ee_u32 i,j; + for (i=0; i +#include +#include +#include +#include "coremark.h" + +#if VALIDATION_RUN + volatile ee_s32 seed1_volatile=0x3415; + volatile ee_s32 seed2_volatile=0x3415; + volatile ee_s32 seed3_volatile=0x66; +#endif +#if PERFORMANCE_RUN + volatile ee_s32 seed1_volatile=0x0; + volatile ee_s32 seed2_volatile=0x0; + volatile ee_s32 seed3_volatile=0x66; +#endif +#if PROFILE_RUN + volatile ee_s32 seed1_volatile=0x8; + volatile ee_s32 seed2_volatile=0x8; + volatile ee_s32 seed3_volatile=0x8; +#endif + volatile ee_s32 seed4_volatile=ITERATIONS; + volatile ee_s32 seed5_volatile=0; + +#define CORETIMETYPE rt_uint64_t +#define GETMYTIME(_t) (*(_t) = riscv_timer_rdtime()) +#define MYTIMEDIFF(fin, ini) ((fin) - (ini)) +#define EE_TICKS_PER_SEC riscv_timer_get_frequency() +#define TIMER_RES_DIVIDER 1 +#define SAMPLE_TIME_IMPLEMENTATION 1 + +static CORETIMETYPE start_time_val, stop_time_val; + +void start_time(void) +{ + GETMYTIME(&start_time_val); +} + +void stop_time(void) +{ + GETMYTIME(&stop_time_val); +} + +CORE_TICKS get_time(void) +{ + return (CORE_TICKS)MYTIMEDIFF(stop_time_val, start_time_val); +} + +secs_ret time_in_secs(CORE_TICKS ticks) +{ + return (secs_ret)ticks / (secs_ret)EE_TICKS_PER_SEC; +} + +ee_u32 default_num_contexts=1; + +void portable_init(core_portable *p, int *argc, char *argv[]) +{ + ee_printf("Benchmark started, please make sure it runs for at least 10s.\n\n"); + if (sizeof(ee_ptr_int) != sizeof(ee_u8 *)) { + ee_printf("ERROR! Please define ee_ptr_int to a type that holds a pointer!\n"); + } + if (sizeof(ee_u32) != 4) { + ee_printf("ERROR! Please define ee_u32 to a 32b unsigned type!\n"); + } + p->portable_id=1; +} + +void portable_fini(core_portable *p) +{ + p->portable_id=0; +} diff --git a/bsp/spacemit/k1/coremark/core_portme.h b/bsp/spacemit/k1/coremark/core_portme.h new file mode 100644 index 000000000000..46de3eed29b8 --- /dev/null +++ b/bsp/spacemit/k1/coremark/core_portme.h @@ -0,0 +1,207 @@ +/* +Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +Original Author: Shay Gal-on +*/ + +/* Topic : Description + This file contains configuration constants required to execute on different platforms +*/ +#ifndef CORE_PORTME_H +#define CORE_PORTME_H + +#define ITERATIONS 14400 + +/************************/ +/* Data types and settings */ +/************************/ +/* Configuration : HAS_FLOAT + Define to 1 if the platform supports floating point. +*/ +#ifndef HAS_FLOAT +#ifdef CORE_MARK_HAS_FLOAT +#define HAS_FLOAT CORE_MARK_HAS_FLOAT +#else +#define HAS_FLOAT 1 +#endif +#endif +/* Configuration : HAS_TIME_H + Define to 1 if platform has the time.h header file, + and implementation of functions thereof. +*/ +#ifndef HAS_TIME_H +#define HAS_TIME_H 1 +#endif +/* Configuration : USE_CLOCK + Define to 1 if platform has the time.h header file, + and implementation of functions thereof. +*/ +#ifndef USE_CLOCK +#define USE_CLOCK 1 +#endif +/* Configuration : HAS_STDIO + Define to 1 if the platform has stdio.h. +*/ +#ifndef HAS_STDIO +#define HAS_STDIO 1 +#endif +/* Configuration : HAS_PRINTF + Define to 1 if the platform has stdio.h and implements the printf function. +*/ +#ifndef HAS_PRINTF +#define HAS_PRINTF 1 +#endif + +/* Configuration : CORE_TICKS + Define type of return from the timing functions. + */ +#include +typedef unsigned long CORE_TICKS; + +/* Definitions : COMPILER_VERSION, COMPILER_FLAGS, MEM_LOCATION + Initialize these strings per platform +*/ +#ifndef COMPILER_VERSION + #ifdef __GNUC__ + #define COMPILER_VERSION "GCC"__VERSION__ + #else + #define COMPILER_VERSION "Please put compiler version here (e.g. gcc 4.1)" + #endif +#endif +#ifndef COMPILER_FLAGS +#if defined(__OPTIMIZE__) && (__OPTIMIZE__ > 0) +#define COMPILER_FLAGS "-O2 -ggdb" +#else +#define COMPILER_FLAGS "-O0 -ggdb" +#endif +#endif +#ifndef MEM_LOCATION + #define MEM_LOCATION "STACK" +#endif + +/* Data Types : + To avoid compiler issues, define the data types that need ot be used for 8b, 16b and 32b in . + + *Imprtant* : + ee_ptr_int needs to be the data type used to hold pointers, otherwise coremark may fail!!! +*/ +typedef signed short ee_s16; +typedef unsigned short ee_u16; +typedef signed int ee_s32; +typedef double ee_f32; +typedef unsigned char ee_u8; +typedef unsigned int ee_u32; +typedef unsigned long ee_ptr_int; +typedef size_t ee_size_t; +/* align_mem : + This macro is used to align an offset to point to a 32b value. It is used in the Matrix algorithm to initialize the input memory blocks. +*/ +#define align_mem(x) (void *)(4 + (((ee_ptr_int)(x) - 1) & ~3)) + +/* Configuration : SEED_METHOD + Defines method to get seed values that cannot be computed at compile time. + + Valid values : + SEED_ARG - from command line. + SEED_FUNC - from a system function. + SEED_VOLATILE - from volatile variables. +*/ +#ifndef SEED_METHOD +#define SEED_METHOD SEED_VOLATILE +#endif + +/* Configuration : MEM_METHOD + Defines method to get a block of memry. + + Valid values : + MEM_MALLOC - for platforms that implement malloc and have malloc.h. + MEM_STATIC - to use a static memory array. + MEM_STACK - to allocate the data block on the stack (NYI). +*/ +#ifndef MEM_METHOD +#define MEM_METHOD MEM_STACK +#endif + +/* Configuration : MULTITHREAD + Define for parallel execution + + Valid values : + 1 - only one context (default). + N>1 - will execute N copies in parallel. + + Note : + If this flag is defined to more then 1, an implementation for launching parallel contexts must be defined. + + Two sample implementations are provided. Use or to enable them. + + It is valid to have a different implementation of and in , + to fit a particular architecture. +*/ +#ifndef MULTITHREAD +#define MULTITHREAD 1 +#define USE_PTHREAD 0 +#define USE_FORK 0 +#define USE_SOCKET 0 +#endif + +/* Configuration : MAIN_HAS_NOARGC + Needed if platform does not support getting arguments to main. + + Valid values : + 0 - argc/argv to main is supported + 1 - argc/argv to main is not supported + + Note : + This flag only matters if MULTITHREAD has been defined to a value greater then 1. +*/ +#ifndef MAIN_HAS_NOARGC +#define MAIN_HAS_NOARGC 0 +#endif + +/* Configuration : MAIN_HAS_NORETURN + Needed if platform does not support returning a value from main. + + Valid values : + 0 - main returns an int, and return value will be 0. + 1 - platform does not support returning a value from main +*/ +#ifndef MAIN_HAS_NORETURN +#define MAIN_HAS_NORETURN 0 +#endif + +/* Variable : default_num_contexts + Not used for this simple port, must cintain the value 1. +*/ +extern ee_u32 default_num_contexts; + +typedef struct CORE_PORTABLE_S { + ee_u8 portable_id; +} core_portable; + +/* target specific init/fini */ +void portable_init(core_portable *p, int *argc, char *argv[]); +void portable_fini(core_portable *p); + +#if !defined(PROFILE_RUN) && !defined(PERFORMANCE_RUN) && !defined(VALIDATION_RUN) +#if (TOTAL_DATA_SIZE==1200) +#define PROFILE_RUN 1 +#elif (TOTAL_DATA_SIZE==2000) +#define PERFORMANCE_RUN 1 +#else +#define VALIDATION_RUN 1 +#endif +#endif + +#endif /* CORE_PORTME_H */ diff --git a/bsp/spacemit/k1/coremark/core_state.c b/bsp/spacemit/k1/coremark/core_state.c new file mode 100644 index 000000000000..bb3193308bd4 --- /dev/null +++ b/bsp/spacemit/k1/coremark/core_state.c @@ -0,0 +1,277 @@ +/* +Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +Original Author: Shay Gal-on +*/ + +#include "coremark.h" +/* local functions */ +enum CORE_STATE core_state_transition( ee_u8 **instr , ee_u32 *transition_count); + +/* +Topic: Description + Simple state machines like this one are used in many embedded products. + + For more complex state machines, sometimes a state transition table implementation is used instead, + trading speed of direct coding for ease of maintenance. + + Since the main goal of using a state machine in CoreMark is to excercise the switch/if behaviour, + we are using a small moore machine. + + In particular, this machine tests type of string input, + trying to determine whether the input is a number or something else. + (see core_state.png). +*/ + +/* Function: core_bench_state + Benchmark function + + Go over the input twice, once direct, and once after introducing some corruption. +*/ +ee_u16 core_bench_state(ee_u32 blksize, ee_u8 *memblock, + ee_s16 seed1, ee_s16 seed2, ee_s16 step, ee_u16 crc) +{ + ee_u32 final_counts[NUM_CORE_STATES]; + ee_u32 track_counts[NUM_CORE_STATES]; + ee_u8 *p=memblock; + ee_u32 i; + + +#if CORE_DEBUG + ee_printf("State Bench: %d,%d,%d,%04x\n",seed1,seed2,step,crc); +#endif + for (i=0; i0) { + for(i=0;i>3) & 0x3]; + next=4; + break; + case 3: /* float */ + case 4: /* float */ + buf=floatpat[(seed>>3) & 0x3]; + next=8; + break; + case 5: /* scientific */ + case 6: /* scientific */ + buf=scipat[(seed>>3) & 0x3]; + next=8; + break; + case 7: /* invalid */ + buf=errpat[(seed>>3) & 0x3]; + next=8; + break; + default: /* Never happen, just to make some compilers happy */ + break; + } + } + size++; + while (total='0') & (c<='9')) ? 1 : 0; + return retval; +} + +/* Function: core_state_transition + Actual state machine. + + The state machine will continue scanning until either: + 1 - an invalid input is detcted. + 2 - a valid number has been detected. + + The input pointer is updated to point to the end of the token, and the end state is returned (either specific format determined or invalid). +*/ + +enum CORE_STATE core_state_transition( ee_u8 **instr , ee_u32 *transition_count) { + ee_u8 *str=*instr; + ee_u8 NEXT_SYMBOL; + enum CORE_STATE state=CORE_START; + for( ; *str && state != CORE_INVALID; str++ ) { + NEXT_SYMBOL = *str; + if (NEXT_SYMBOL==',') /* end of this input */ { + str++; + break; + } + switch(state) { + case CORE_START: + if(ee_isdigit(NEXT_SYMBOL)) { + state = CORE_INT; + } + else if( NEXT_SYMBOL == '+' || NEXT_SYMBOL == '-' ) { + state = CORE_S1; + } + else if( NEXT_SYMBOL == '.' ) { + state = CORE_FLOAT; + } + else { + state = CORE_INVALID; + transition_count[CORE_INVALID]++; + } + transition_count[CORE_START]++; + break; + case CORE_S1: + if(ee_isdigit(NEXT_SYMBOL)) { + state = CORE_INT; + transition_count[CORE_S1]++; + } + else if( NEXT_SYMBOL == '.' ) { + state = CORE_FLOAT; + transition_count[CORE_S1]++; + } + else { + state = CORE_INVALID; + transition_count[CORE_S1]++; + } + break; + case CORE_INT: + if( NEXT_SYMBOL == '.' ) { + state = CORE_FLOAT; + transition_count[CORE_INT]++; + } + else if(!ee_isdigit(NEXT_SYMBOL)) { + state = CORE_INVALID; + transition_count[CORE_INT]++; + } + break; + case CORE_FLOAT: + if( NEXT_SYMBOL == 'E' || NEXT_SYMBOL == 'e' ) { + state = CORE_S2; + transition_count[CORE_FLOAT]++; + } + else if(!ee_isdigit(NEXT_SYMBOL)) { + state = CORE_INVALID; + transition_count[CORE_FLOAT]++; + } + break; + case CORE_S2: + if( NEXT_SYMBOL == '+' || NEXT_SYMBOL == '-' ) { + state = CORE_EXPONENT; + transition_count[CORE_S2]++; + } + else { + state = CORE_INVALID; + transition_count[CORE_S2]++; + } + break; + case CORE_EXPONENT: + if(ee_isdigit(NEXT_SYMBOL)) { + state = CORE_SCIENTIFIC; + transition_count[CORE_EXPONENT]++; + } + else { + state = CORE_INVALID; + transition_count[CORE_EXPONENT]++; + } + break; + case CORE_SCIENTIFIC: + if(!ee_isdigit(NEXT_SYMBOL)) { + state = CORE_INVALID; + transition_count[CORE_INVALID]++; + } + break; + default: + break; + } + } + *instr=str; + return state; +} diff --git a/bsp/spacemit/k1/coremark/core_util.c b/bsp/spacemit/k1/coremark/core_util.c new file mode 100644 index 000000000000..581adcc24268 --- /dev/null +++ b/bsp/spacemit/k1/coremark/core_util.c @@ -0,0 +1,210 @@ +/* +Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +Original Author: Shay Gal-on +*/ + +#include "coremark.h" +/* Function: get_seed + Get a values that cannot be determined at compile time. + + Since different embedded systems and compilers are used, 3 different methods are provided: + 1 - Using a volatile variable. This method is only valid if the compiler is forced to generate code that + reads the value of a volatile variable from memory at run time. + Please note, if using this method, you would need to modify core_portme.c to generate training profile. + 2 - Command line arguments. This is the preferred method if command line arguments are supported. + 3 - System function. If none of the first 2 methods is available on the platform, + a system function which is not a stub can be used. + + e.g. read the value on GPIO pins connected to switches, or invoke special simulator functions. +*/ +#if (SEED_METHOD==SEED_VOLATILE) + extern volatile ee_s32 seed1_volatile; + extern volatile ee_s32 seed2_volatile; + extern volatile ee_s32 seed3_volatile; + extern volatile ee_s32 seed4_volatile; + extern volatile ee_s32 seed5_volatile; + ee_s32 get_seed_32(int i) { + ee_s32 retval; + switch (i) { + case 1: + retval=seed1_volatile; + break; + case 2: + retval=seed2_volatile; + break; + case 3: + retval=seed3_volatile; + break; + case 4: + retval=seed4_volatile; + break; + case 5: + retval=seed5_volatile; + break; + default: + retval=0; + break; + } + return retval; + } +#elif (SEED_METHOD==SEED_ARG) +ee_s32 parseval(char *valstring) { + ee_s32 retval=0; + ee_s32 neg=1; + int hexmode=0; + if (*valstring == '-') { + neg=-1; + valstring++; + } + if ((valstring[0] == '0') && (valstring[1] == 'x')) { + hexmode=1; + valstring+=2; + } + /* first look for digits */ + if (hexmode) { + while (((*valstring >= '0') && (*valstring <= '9')) || ((*valstring >= 'a') && (*valstring <= 'f'))) { + ee_s32 digit=*valstring-'0'; + if (digit>9) + digit=10+*valstring-'a'; + retval*=16; + retval+=digit; + valstring++; + } + } else { + while ((*valstring >= '0') && (*valstring <= '9')) { + ee_s32 digit=*valstring-'0'; + retval*=10; + retval+=digit; + valstring++; + } + } + /* now add qualifiers */ + if (*valstring=='K') + retval*=1024; + if (*valstring=='M') + retval*=1024*1024; + + retval*=neg; + return retval; +} + +ee_s32 get_seed_args(int i, int argc, char *argv[]) { + if (argc>i) + return parseval(argv[i]); + return 0; +} + +#elif (SEED_METHOD==SEED_FUNC) +/* If using OS based function, you must define and implement the functions below in core_portme.h and core_portme.c ! */ +ee_s32 get_seed_32(int i) { + ee_s32 retval; + switch (i) { + case 1: + retval=portme_sys1(); + break; + case 2: + retval=portme_sys2(); + break; + case 3: + retval=portme_sys3(); + break; + case 4: + retval=portme_sys4(); + break; + case 5: + retval=portme_sys5(); + break; + default: + retval=0; + break; + } + return retval; +} +#endif + +/* Function: crc* + Service functions to calculate 16b CRC code. + +*/ +ee_u16 crcu8(ee_u8 data, ee_u16 crc ) +{ + ee_u8 i=0,x16=0,carry=0; + + for (i = 0; i < 8; i++) + { + x16 = (ee_u8)((data & 1) ^ ((ee_u8)crc & 1)); + data >>= 1; + + if (x16 == 1) + { + crc ^= 0x4002; + carry = 1; + } + else + carry = 0; + crc >>= 1; + if (carry) + crc |= 0x8000; + else + crc &= 0x7fff; + } + return crc; +} +ee_u16 crcu16(ee_u16 newval, ee_u16 crc) { + crc=crcu8( (ee_u8) (newval) ,crc); + crc=crcu8( (ee_u8) ((newval)>>8) ,crc); + return crc; +} +ee_u16 crcu32(ee_u32 newval, ee_u16 crc) { + crc=crc16((ee_s16) newval ,crc); + crc=crc16((ee_s16) (newval>>16) ,crc); + return crc; +} +ee_u16 crc16(ee_s16 newval, ee_u16 crc) { + return crcu16((ee_u16)newval, crc); +} + +ee_u8 check_data_types() { + ee_u8 retval=0; + if (sizeof(ee_u8) != 1) { + ee_printf("ERROR: ee_u8 is not an 8b datatype!\n"); + retval++; + } + if (sizeof(ee_u16) != 2) { + ee_printf("ERROR: ee_u16 is not a 16b datatype!\n"); + retval++; + } + if (sizeof(ee_s16) != 2) { + ee_printf("ERROR: ee_s16 is not a 16b datatype!\n"); + retval++; + } + if (sizeof(ee_s32) != 4) { + ee_printf("ERROR: ee_s32 is not a 32b datatype!\n"); + retval++; + } + if (sizeof(ee_u32) != 4) { + ee_printf("ERROR: ee_u32 is not a 32b datatype!\n"); + retval++; + } + if (sizeof(ee_ptr_int) != sizeof(int *)) { + ee_printf("ERROR: ee_ptr_int is not a datatype that holds an int pointer!\n"); + retval++; + } + if (retval>0) { + ee_printf("ERROR: Please modify the datatypes in core_portme.h!\n"); + } + return retval; +} diff --git a/bsp/spacemit/k1/coremark/coremark.h b/bsp/spacemit/k1/coremark/coremark.h new file mode 100644 index 000000000000..831b0e7f73da --- /dev/null +++ b/bsp/spacemit/k1/coremark/coremark.h @@ -0,0 +1,179 @@ +/* +Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +Original Author: Shay Gal-on +*/ + +/* Topic: Description + This file contains declarations of the various benchmark functions. +*/ + +/* Configuration: TOTAL_DATA_SIZE + Define total size for data algorithms will operate on +*/ +#ifndef TOTAL_DATA_SIZE +#define TOTAL_DATA_SIZE 2*1000 +#endif + +#define SEED_ARG 0 +#define SEED_FUNC 1 +#define SEED_VOLATILE 2 + +#define MEM_STATIC 0 +#define MEM_MALLOC 1 +#define MEM_STACK 2 + +#include "core_portme.h" +#include + +#if HAS_STDIO +#include +#endif +#if HAS_PRINTF +#if(HAS_FLOAT) +#define ee_printf printf +#else +#define ee_printf rt_kprintf +#endif +#endif + +/* Actual benchmark execution in iterate */ +void *iterate(void *pres); + +/* Typedef: secs_ret + For machines that have floating point support, get number of seconds as a double. + Otherwise an unsigned int. +*/ +#if HAS_FLOAT +typedef double secs_ret; +#else +typedef ee_u32 secs_ret; +#endif + +#if MAIN_HAS_NORETURN +#define MAIN_RETURN_VAL +#define MAIN_RETURN_TYPE void +#else +#define MAIN_RETURN_VAL 0 +#define MAIN_RETURN_TYPE int +#endif + +void start_time(void); +void stop_time(void); +CORE_TICKS get_time(void); +secs_ret time_in_secs(CORE_TICKS ticks); + +/* Misc useful functions */ +ee_u16 crcu8(ee_u8 data, ee_u16 crc); +ee_u16 crc16(ee_s16 newval, ee_u16 crc); +ee_u16 crcu16(ee_u16 newval, ee_u16 crc); +ee_u16 crcu32(ee_u32 newval, ee_u16 crc); +ee_u8 check_data_types(void); +void *portable_malloc(ee_size_t size); +void portable_free(void *p); +ee_s32 parseval(char *valstring); + +/* Algorithm IDS */ +#define ID_LIST (1<<0) +#define ID_MATRIX (1<<1) +#define ID_STATE (1<<2) +#define ALL_ALGORITHMS_MASK (ID_LIST|ID_MATRIX|ID_STATE) +#define NUM_ALGORITHMS 3 + +/* list data structures */ +typedef struct list_data_s { + ee_s16 data16; + ee_s16 idx; +} list_data; + +typedef struct list_head_s { + struct list_head_s *next; + struct list_data_s *info; +} list_head; + + +/*matrix benchmark related stuff */ +#define MATDAT_INT 1 +#if MATDAT_INT +typedef ee_s16 MATDAT; +typedef ee_s32 MATRES; +#else +typedef ee_f16 MATDAT; +typedef ee_f32 MATRES; +#endif + +typedef struct MAT_PARAMS_S { + int N; + MATDAT *A; + MATDAT *B; + MATRES *C; +} mat_params; + +/* state machine related stuff */ +/* List of all the possible states for the FSM */ +typedef enum CORE_STATE { + CORE_START=0, + CORE_INVALID, + CORE_S1, + CORE_S2, + CORE_INT, + CORE_FLOAT, + CORE_EXPONENT, + CORE_SCIENTIFIC, + NUM_CORE_STATES +} core_state_e ; + + +/* Helper structure to hold results */ +typedef struct RESULTS_S { + /* inputs */ + ee_s16 seed1; /* Initializing seed */ + ee_s16 seed2; /* Initializing seed */ + ee_s16 seed3; /* Initializing seed */ + void *memblock[4]; /* Pointer to safe memory location */ + ee_u32 size; /* Size of the data */ + ee_u32 iterations; /* Number of iterations to execute */ + ee_u32 execs; /* Bitmask of operations to execute */ + struct list_head_s *list; + mat_params mat; + /* outputs */ + ee_u16 crc; + ee_u16 crclist; + ee_u16 crcmatrix; + ee_u16 crcstate; + ee_s16 err; + /* ultithread specific */ + core_portable port; +} core_results; + +/* Multicore execution handling */ +#if (MULTITHREAD>1) +ee_u8 core_start_parallel(core_results *res); +ee_u8 core_stop_parallel(core_results *res); +#endif + +/* list benchmark functions */ +list_head *core_list_init(ee_u32 blksize, list_head *memblock, ee_s16 seed); +ee_u16 core_bench_list(core_results *res, ee_s16 finder_idx); + +/* state benchmark functions */ +void core_init_state(ee_u32 size, ee_s16 seed, ee_u8 *p); +ee_u16 core_bench_state(ee_u32 blksize, ee_u8 *memblock, + ee_s16 seed1, ee_s16 seed2, ee_s16 step, ee_u16 crc); + +/* matrix benchmark functions */ +ee_u32 core_init_matrix(ee_u32 blksize, void *memblk, ee_s32 seed, mat_params *p); +ee_u16 core_bench_matrix(mat_params *p, ee_s16 seed, ee_u16 crc); + diff --git a/bsp/spacemit/k1/coremark/iteration.png b/bsp/spacemit/k1/coremark/iteration.png new file mode 100644 index 0000000000000000000000000000000000000000..bea6cb9e4b6891da660a53c5334676a161710459 GIT binary patch literal 53691 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 g(j*x_e!Ttj|B`}Ouv-9s>i_@%07*qoM6N<$f +#include +#include + +#if defined(RT_USING_PTP) && defined(FINSH_USING_MSH) +#include +#endif + +void rt_hw_board_init(void) +{ + rt_hw_common_setup(); +} + +void rt_hw_fdt_vendor_install_early(void *fdt) +{ + int node; + + node = fdt_path_offset(fdt, "/cpus"); + fdt_setprop_u32(fdt, node, "cpu-boot-delay-us", 100); +} diff --git a/bsp/spacemit/k1/drivers/board.h b/bsp/spacemit/k1/drivers/board.h new file mode 100644 index 000000000000..da2e9bfdd727 --- /dev/null +++ b/bsp/spacemit/k1/drivers/board.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#ifndef __BOARD_H__ +#define __BOARD_H__ + +void rt_hw_board_init(void); + +#endif /* __BOARD_H__ */ diff --git a/bsp/spacemit/k1/drivers/esos.elf b/bsp/spacemit/k1/drivers/esos.elf new file mode 100644 index 0000000000000000000000000000000000000000..21783ce196f70857471a1f78418fee8d30774384 GIT binary patch literal 1394124 zcmeFa3wTu3xduGRo@8?o2t>piC1jICsFxrjMGFKoVXN2@yiL_wqEpLhPkRK>TF$B*Js#mbyXP;jv8*a z8O!tGplTDeHr@jmQ8Wp|D4Up%d!p6YX8x5 zv2fn-t7XgU-$`w0-BpAk+*WdKhCdgW&#*1BmFIlA^M6k$^&)mhNb4&F#XI=aF zwU^I+b@t8IeQ@26zfpbrS>Jj5JD1OUbsq4hFS6wooWhT@DiIw{z#iKuE1s#PPQ2rl-X?i z9Q&?&Bj@mqhtGcd+izpGvQQ!mC9+T=3nj9Q2{&aKU%e~KxcI&-BhRZF`73l|++(^? z_?%9djl7!xyR8_%13u0#zRbwyZ{B6bxSIw@?6041_}AOA%9d1S*ev?HiL|(=<<*}q zYT5JCde9B%<*tWjy7RMaoFDuS;0(F*%kX+bKgy%c`x{kk7#pPcsa_LXPszHav!!RvxE z_4a>#GdBF)C6!yVcb7bzO^#T(a(?CGHbZZ+ZOCr28Ti|fg9D$$UfUbX>Q-iDys_+#rn;3yHraahl2B!J&&tYOqed^E zzOwz^-Cd70O`89lEqcR{M;-_@`4%s(^L2LS%>32Nt@oU;O>&*E?fB)^cki^h>hC$j zb@svR@|g!xb5`9m$aUU9drsM}%2MjoBIhdyGt0{kq~`qko&m1m2Qzc7`PDTkb?WXJ zFgI&oR{OAnCvrz+XVleaXSmMqwBq^!=8y8AvIR{P>S3lC6(H&ESvk)EL&EVH_MfK&~{hPq^yHTAD&g4)jr~2ECZA?Hfvp0`}qeW ze4d!KC9C}``8+dgS5|wD^*lWPRoj3j^RnVPpI&bGb$gXL-FvBHW(FV_p8aZm0J+Xd z#kpQR8g4FjGWVI1{J!~FdBsz*Y{lV@<{vg~WLaNfxT5NYux-g@S+iKX&TF1*D!L3g zra#=)lA}_6Hks;MA8uPPES{PnQ-clRww$5iijuN$Ny$W&Yi7z^ePg(-_zab*YgYSD zp#4EAHE5;!{uAvF3|BUe3fEMg7jCJUF304vhnvf1X4uq-GKOcrp8qFXj#1bUGsZm| zGx7s5cTpf#6{^!)mJIRp`A;|S{~D*))QTK2ccCYy6$E18#)ao@_D%PGRC1>y>y9Or z4=l_-Xgk}uxFKR(_-w?O5QsDdA8I}d3Ghj5wQ1ykf_5FTMK!^nX4sm7mk|55b^3Il z*F1kW^2agXW975IRi(M}i)^cQt7kLm*@tJgjyAF}gSKI|j$!=snnoVmvBwrQ>Q&SZ z8S%X1JEtzpf2R^Mts(Mpk?k_VrJ*0RA2BwC27FvpQcNf`Kq1mLGtKrOAs6FjxhI*n z08)%;c3JLerZxY}xcHL@+KY<1{?MS0i^_|Q3z_DTY3oCSGHmzUI2O1{K*G}Qjru@B zgJ+Cizf7i?gAzD#7F*>8CE@XBGA%eTKIWSHt#ZDBga-LhwD+LZ-atYF93#yvR*>AZ zusXQ@l}eOv_z3g%kx^)m)#;8;a`nnVS5#M(P4|w!9Cbck-G11)#m}7S-n*vB-w&_Y z>{}6R(u*;dzNxv$18sbKMfDD^RuK4j$w~t>g}y;chn*astTlWJ)24fOlw9oiK5%jS z!s=Jo2Py{uf}W>+8-{$+<2Ik|9cjA0-+6X!eUYuH9^B*$dbiiFDP7`A(3Ca*nZ#1q zHvCQjhc|d{M%m;k9~b3C6b9-#^}N-)z2^?ex@$WekZ?G%1V@=)QFJJj0yJ0Fk49m-eWJ$*`@FB zW|ZADL%mJ+-Z903lnTIzkIYEM;}R^W+- zZR_tLy>fKmQ}oE59yQzF2z61)-2vT}+W)EgUbhFbD@wV>c9(qrvmm)?vdXR16C)s` z>jb28C-;YHnc4nU=mgV0D!)@`h&Ufu`V^yxzBn&2lWT~#=vKY6B=^mtk|tmHCD?f{ z;a$qZoGSZfAElL=tpp^2I3&leG>rMUjm*l35#vte@Ix2JZel&(!APZ zhnGuAAx#l7&ZbsikG-H^vrYVWSS$TF`JVxq>~Wty-MedQI=a;Wt9RC<`VVZ~%ePMH z5ONx}paqNKk#PCGV%8>2jcvfJ2x{J5|FAwK2>#W5E4J5jOpaK%qIR_6U)RI>`5b4s z;`qgzeRY-=aQ#+4w=T<;omCd@D7lfg6mh*eoSVI1fY5_p{b9-X!9n5Xii?gpzp=iy zY&c3+%r!1#X^$w~lBRU!gk#PXo9nWgby5DC#srpki1Nh)`?p?Mbj(@1-WUg2BRJ(@ z9r%cDug3^2?ZZ_FaiqAHoazuIJkiVRpFaX<$a$7c1sZ=l)I;9HsLN-5AGV|5?C1A# zj4#gNDBDut(9Z}r+r}Jr-nU8BTleqA1r1UYRQrZ#g@LG$m|ovLvM+fhnt7QZML%7Z2`>DRU^~@0o|4<2R*B8n4;j6M9ET_WD42Ba+Z#9-st>zbs^(Vvz%+NJX;E2ly_2O?`qccGMdm60*l#gl~gM;`B+j_9;%uZXC zIoWTu4a`f;HFH|LBsBB%dcGNthX#4g^q4_DY<1b&$Rzv}OinYph_=xj>{jhYjLjj! zV`1&>D~(fNZ8b3>>x$ldgWG@D*_E0`xu2Ltg_-2F9Iz34f0Bibn1zj40viRJl$OGX z2DyW})Uz>(n=8C4Ab$fW9~_kH8%4f|85U*|>%GK0toEaXz$?}ZS5g|fK?TYNAU87K z4UBM2Z@{XJzsuI67JkqM>E-ZLP@zZT3`GqiJgj{ zqZ7X{e%?&QPwiCnZ{ertOX26(^v}Z2Rr*Y~QIm`x(RvDgZlC^tfuFlBKQ(?v_Mx9u zrNoA!or38J+?bz>o2n$*>Hhj>;YLbyK}9~%ZVFb)u%`dQRP()mglZJekV;|4>p3=f zer)S5OQhE#JvXaz#K^BF(rD9UlnuEI)?M6JlHeWEv84KN$C%$5<2ZtZG*x`WQsl;3 z$On7uQFmRi^JMf9%FVHqM1r?gL!;SaFS%v9l{!d+TwGGW*|#*vry(;61im2&;yG+H zSqgW5OiMJ`B1~tEM&>A~jTspMZCQEgeQXCUi?{3Vwcc`(*H&{K-(cULfw%H!CMIk; zWk+G|grM4d}Fqb0~uw9_#L80b6WZVPv^Of6&y zT6rjqe2!YHjEM2LK7gg&8-0Ujnl4|+maE$`UB3v~rV&$=_ycl7`d9c288~2aaw;iZ zq@E-6fmL>>N>%kWNJCh^cD}4lYUut= z-*zn9vSW_5GGp7MLahL6m5y)^>(IB5zE-#^*+MyIVf8!fTWuM@Ds@g5#&ZT|nN}d) zV{6Q1Zeg``VUDQJu(D-2;Dv82KS;x`Rumj8^l2A7YogpCSx#y}lrsmXlzTGK!aC9; z%Ji9!pNDLtiTSQ6Tq*0J?-=m0jV9Jr$^xd0OfGXBQwAoLF|TBbY~39EMfwTeWx#Kj z+>h^mrX=?hyn!jn{S;lr6l)YCTyA}wd=3ugEVv6CFlXHxb43I!APqA}uNqec9d}tR4SMu%eA1B5-_M-^l+Z^ASu3!gQu}k~1zh>Kf-*Sh zZEJ?~5z_x9W_|>%IeTnM5$DJE%jfrw$6UbTds4T1P59D4iIPI#4-n7P7pPCJ7qh+0 z2m8`0z3qR>uN6&Et|HFq?r`vnw>M&e+J*`623JyXkL93#*i{&%Y2ct$$o$l#Y zH7=bcYnX!-^k!e^fzR~NFO5TQ^zh^vQ5v^I!yTK8_i{iR|&|iOrg{2XH z-fc+=)ZYg_fAFSo$MP4gu?fk$f24eqa`>Y&WnYwp!=6`bN=iR#O%RnXwacHOT%PVdQU1Lf z2MYgps(&dEiHJP_t-upQ`7K6%gIH0cUPM`^uqfe^mnox!y^53u@|gn`u0D`Ct);H4 z&P+a0;vgTMeVK2HU+~jFF|v{+KW4hrBg-E*@~B7b!dIo%CsIQ=pwY~MLrmB5P$vGr ztJ6NvbS(*G;{UrlGaucXWx9S7%G4kWz4M{pDj}&MF@=_e+|^6?Hhxn)zggyw^+%oS zpk+0zsex~52Qee`gAl5?{QfP*5*6}0eg2wc`JJpw4dJ)zi`QXm1YY5Xp|?Wd1(*V7 zpP?1NKhd$+Cx3UYWgfM4^d`_v`Mcu{OV8F?en;PkaAQS5xA5z;ETr{_s=bmb2tTQU zc2Kxu?=LwUn8S>vkI>V-4pxf7`>^F{=@Gs|4Rdk){_auTN&X>)7x)i4?p{W$^Yrg&vC;exV@%pFU!Bd(^pwnpeDO z`0b*fC#h~w)V(yvs=Hp*HAmD^vx$1ZbLFK)QK!(YNHIsqmITdPwzQ)8aLLS{7ET&RwJ?cmnIH^~aMT+Ex#l zMVS;mwA=DnmmHlUy<+fE?XJ@Uk?GYIp3jo-&75aIE~0(Fe@C7%u7PwNS?cB-(^_@F z^98E5WFCBPur_4rs?n;n@U~FrM%u6Lh-6qhD85mez`(BA>;WysYRRWjqd^}rQM3#T zpn-GbpigC>vdV*Jhy5MjJ?wmcvo(g|tG><|Ma}g>@^WP|V7jkPuiWM83E3=+ofr1k z+!1yDalIGV0_Ka~{hC#)LDlm0t7V=a_7{IA>Rh;UUG<3|U?u;(ANB;0%rq`*WO8=lIRc18$?(0nV}7 z9Z|anxQ!m2%C!~Kh%1%13^Ys_b;&8!<``IZ(I(hNb>5=UI1V|MgS6B4#<=ZlF{p`nL{+ZO+xt&ioL4NBy0vD#VtLL%*`l{W8r z);Lt!q+_?K+BbANRuFc0R7afAf4>60&5uH_frj8ERo{y)?Ix8BWkzD>w;(k-wW z91Q6VPxEx|_oo<^W>TIa#*tA73cfyQ$DNox+xQU$M27hdXUx>trSoOWtwkSxS?)X8KIwNv<9DV_^v z@Y$v@eX>X|5zkpktt79~HQ?zn)AfGH_Jj$$Qs51A)>e{hKx%~BD$X$qAxVlnlpw$W zu{R!(DsAw^G99oYul-*-v45Lbt0!Y6H``VsF|lyk__DcxNxnTG{I$?&L!@7UPt&V+ z37jpX$CZ+OsLIoaPOsi4@>Wkv;4^t7l;y`+BKk($YYNXXIL;GW`p9D;<~%lKeA&P$ zvQ+mZj!@=45whe>9^}orlQ+o{_r*(iA6fCYtXW4z>xZv|63|zeb!2pBP81 zZ1O2^kZGqG#7nm(u4kZHMD{;Xw_PBAvjFLBtUJ8aT679)iXvGi{; zJ;zF)NPB`Zb%fV+oo(4aAw82A5OspiA@qU4Dhla{Xi};36RG2vDqGF7TIJhP`d8vP zwruOI5V0!)kMJS=KEVaa)EUoz&L||+1!AB6CehLW+hcnFwoYzKw3Wgq^ zliiRr5}V$?X8PRb$t@V5-roTkmSR@!vH(J;aS-Ww1d#r+Q%|Kb%ExRR}@ zZ3TzA-z>r|r(RMeY&CZ0bJf5VknlWFmJSu(mzeQ$J*A|KpAqtQsETDsH(N)3ZOs;}6zXhp*8PxDTddhW zvW6q%JbcO(NSrbT*y?=s_Wm<^WOe!(6_Fub_ym8Z&iMdUNlu~bl zW>3)Ha$_9n%M;u68_H_JJW#bvjW~kd=q@{*uN7w_NlsUp4-g}?krdr>JtyRxhP8~!+flvESB?0=hjrm+=k9D=7OpZ` z3cfOtVmz(OU%!r(3(_|UiH922Z?#MxBBY5{K)=Mv$N0PJtI6@b_btp0=D%WNr05Cm z2Nkf@%7#%2ol=Gpqe8xP#^uYi^)SwYqoo8yjyX*FRpVaE&&9N?W${|4q%YMf+i!PtU_R17_3IFIY${Y^I!TWL z5=(1zQfm+@IqR(98!F&y`+Q317Bq&Dqt!T`q&xs+{_cM^`71u2HMw64-ej0e@B4dg8hjdDl$ixD_v`Qp?&2x9fEsRx(?q zW%j}z`Aoa*i4bjH0Z)sO*8o`TDAkZ9Y$@)G0Af{Q@&2Z)$Vmyu?|#D`;NKihZ|5`T zt=N=k|FK}A{VkA37$Kyj*K~D-?5eGufBd}O*6vC4w)a=bz3o5q9QZ`&El^&!seR(d zrLC}Gn4R2$ogn%!+!%da<3`{)%_*Z^ibxJ-OsV2va;sP82;v$wZ7K4%mo&s&YLiZGCG1al-v!$c+H_zAw&X3IcoIl*GEhhvy)m{D?rRk+v1&UX$AKZOI&+oYtVx^ zR?0z{!dApsfz7HtO`)@}GSx5V{*G81qgN->i?W%%iRlylN7?2N_{<)foJ*PKn52{2 z?b34u86sNc4i4zqA^b(~G7W+ClquKWn1!TL%i1;2bJIqhZH<^-Pv6uer;r~JSSdLi zDPmPc&;4_;_O+rq`}!haqxP|Q!Hxf*bt|n}jEU>;B_W&#OF3tPC{juUo>!wZpf2IM z8*>3kdUB{+Y6rPrz^ck%WJz z?7wa2(^A7tw&V&&WR0S2#tR9VDsU`XX!{r0!deUS&}z_E9LwU>vVX<5)(CWr9IYO9 zx^g@17A%7`$VTv-;0L!@AF&5Lce)Re=7`(zSe{({BAlw6oSRiK5Oens>4x5sDo7tu zo)G2ihvt%WgSW=!b2$dr8#-lA>>OZ?c1?PD32MZeO6|<)#Tw;8@kB(cGzeN0o&!jj z4G)LTV2q6?vf*L<3{~DY(JDVIwY>3&DsMbO>hK6z{2Zi`CoIg^TaF4Za|p^vZ&)_Cz%E*%)hKES4;nr7~`jr7+Sc)*ROEL%Z352%bdy z!ON`nMqe`E;7vB`w%Uqm`SH0Y!=)V70{FG*WaaM&hTAbZJ7{geSqdS!S7S7u; zko|~NI4zhbiJ`tb-DZ>8)e0An{js71SEZh>kt>R8^`xEdU+H<+b2g4Nkr#tv_O9o60*VwYL)4drx-DgqWK}t6N?iYlcYc{#hZ8jytqxQK`f;+;fAt2~D z*s2kYUoHLX;mVGmM4dy{%XU!$y!-BL$#40t@z{Hv^ICG+%eU|i(r%zS zd2LR^uCBlMQl>*&P>LZ01_g`njKn^(K0RDnvj98Ww1Mba>J!rs)gwHobtRnK3Tp-_pDU9glZvxX%>qOGF zF7Q0DXb!OAjM{2{l6IH(lh9jg7bqdEQui#3{D9CoRiV#4GrnLVBOKyq##38DbXg`O z-Ot3S$c@3T0djx&nLLl7BB$e)WwPGB-~e>DIv;A5Xa$~VxbaAMvu{fnQc>Va|CVg~ z_zw-qXYmu1!IE%g%eSJ=i#A!k-#gxliO@?mQ0u@Mn|-c#;t>I*pqHDX&WV0mdhWtx z4oz4w%Fak0p&FI2BmDjc6y@k;)=B*A9FCuB+JX~MN`oesqCLlw_lej5 z@ifB_vL+B?T+$!OWwF-M0@HOz=b*$HbN$!yjJX?}BI253t9Cy?4TPu&)>yTBrg)S7 z)m6L23D)Q#Q|566je4`?8~sbDXT32t3wd*7-bFIcdYdfsZjgCXWuEnxA>LGf@`M@o zYchldAYk;wRt1U2Q{jQO$z0iklRZ2PzesDT@`^mM*9|?i#(V*mi$|Pqb;NF;=7z4< z3Lx2S_c)C_=(8f&F)Ds%K3C@EuOP1q4#R7pp=`Kg-`6+$GG~D>ew#KEPq>Zru*x!iT3^7mG0isnBlc$>1*c2ax^VXfiavWRjdJUtB z>%LB&_6t5Kb)Sb8OSX|uE#ru}9)jPB@D=YGm8ARD=tG-OtFAiuWO7S5nUCl!u9Yak zQ7dQSccf;rgAS-+n0EZzD(%qjrB>P&*hpL{p7i+vs$%xvr1dF_fgf}O)Bls-gTzdWYeyI!Ro`imPnQS{t#^6j*;J`(zC zGDrS%<9WV3N5>_7q2T+-hk~2km~F{bYn+V#dBWmsPv2Nh%jS%_xp&N278;i?~aezj60N`b+=PVSw*0 zD`maLnd$2lm!#Hn1AAC?2!D&i@=dpzl;OnUm{(I{d^OCffPHrNa`>E3dsip_r!Oba zD{)_Sdjj{q`f#P~8sc6>{ibpqDEk$oupt(1Ua(ksrTcOq@beO9h5h#76YwD5i4w;= zt=5fLZ-r;ro`5RB#}dzD5VMG#8*jL|184q~XXuuN)d$xfcy0gdEtR}os0-S?3*MS8 zvHIa2B-YB@UqIb%@|9K)=*AA_3&ywxrbWn68wT1V2L5E;+U?vM_L{~(Rr*MW%-Ola z$YU)B&QN{2Tkse)aQF13Ro5_8>MuqVlhUuP-d^n*d2qn%)vjNj7yw@(+Ur|tjVV2a z$u(PfqJ`K>YHiJIi+YpNT4xhqDdpzKow4M)t#bt30nUW3bwpZAf%{ndo!~n2vZ#s# zc{C__&iCtZW##w`zkJizge(0QxXp1<;avyz#{A*1^M%d0{i*_UF6B-{$h(M?jG&6& zB6^zgh_bCm$~y<;nUGOJ>e~72z=`wDVH?CVtO!cuET&_P#B@AcoX2`eeMpKpxjHG; z;^>_#LG>tYrxdk%4)g%0Y=N!Hcp?10tGf#wJyUdB)q|t%TMj-)84VmMW$S~>p|%_FmFxV|g;hPCkqDZpmSH6m9ka`w@4coe|viur9pjIt$mo z4Og}a%XeFO;f-hAQhm!^;)a?;ti3VrSxPwAQAbuld#9{?u6^s9hps<(^MOinj}^*- zz5}Fdo|b%=@O8@MZEp6h?$NiIOXkix#T;mV2u zhn@7o+Y!CHYcKcqxvOTEc4kyjJ??mlTn>JiUJbhcpI7bTcjQ6aYd+WeA!?53^oOgi z?O$(t^}%Y_hp*biZ_dHY{XSQezU z!M(9+gIKvQsKkvRyCA(`A(v8eY8z*6Ks=z&*nAXT3Z$A$K_s$F!LyVoXvJJ=x&{cH zjA!iRjp(%E%8^&fe%8#6`-M8zhBIv4>#b;LE5FrD%0E^H8PG8XGC-VaNz?v0a;GrS zw$MxeZ6wKFOEypr$LP;fkgz9~p7DOF7DE|PItc@iBhVj0Zi?~aUGOvTng*)jpEc?k zZBx|=wKQX%_YPzhcbuCWvA^Ppwwm5YUJ0@nSg;!5&B(=kfkYYVcTku zH-Lop1tc-;3;#4@TtiGl8fy2_zEJyb%7RKh$Ey_ty5I#rpiaAh3dL-ax+o*4N6|lU zi%4;4DMwegSD9}=O-v-yr7cU+r9CZO+R3M>bSW*DB)UY4q|5jW;T?48h|?wI-k4X_ z45?g2mCT(Hs4|~;8n@rztPZe74cWhaL6@pFX`VB;*3#~<1%OFOmjQ7)jC83=E4tkI zdtjN8NLUbYDi$M(V*s-Uy0p@y&IMimL!;ig?XyOG1p4KRj&n?7S`CT)?sVgv@zg0a zIjIX?7~H^f=Y!M=w9Fbyh5;*}&5Dtl zJG9pg>DVPP?&+oll@9Km>x}#c^zP^Z)mpP@?_p^T(qX%gR&uo!(`6S_=816!pLFUP z$lV{g%i4LgeShd9zIjd8e}(KAli*53O=BO(k>GDgWv$Q=Q|lIULwG^?Nba^K%FMkm zrOd|gf}C8@C*;VVcPE#vQESR)yjm z%(?Q{+$-kF-}vuo=gMFFKJ7gKXi|LrrG&zPjCO9tWLZ zos!UH6)iJ2`#3)8JW2;K1Ms~u8c&_xyxkveuEZ%SsU5k_QCf`8kQS1g#a#oAnBwN0 zRcZAGcu!D^Ra$ZLUc@R2ZnjQ4^JY2+&qi{tg}nDqB9zj?PX}dUjg*WTC$ad2urTL1Z9Xv;$a2Xu zb}_DWSh)M|oN(m~Be!tZX3lc(d{pikv{mv+Q!Z@qqK|G|R?-rE08%e$|C z@F#gc2+DV1?a_tXIlF)v*cg|*4(g&l=*2w3N5v_5|P4xY^=8S?1?e*WFqDLA6$Z zas`f_aLM%*BHwCH)i(;?1JsT#4b}*6L2^WRj>}zS?~-pKk}9Gh9chvFlcB#`lob)N zN*pop78DUYo=AIJ=)Zw;@FeeJxcQb>Z@K)|$8SCBw(8q{j63XkKSN)tpjMDkGtw8+ z*AJr!f6LuZ8~MpR3>dMmpd>nc9*{SP7>BOLAE=R5Ct!%yQZ5R6^M$7o*^L`J96j5s zr&qfRJl(S8lW$512kuGID<$x}KiAH>*u#Kc(eR|1x($-6gw(*CWJ-~e%TCE9aveRu zZA3<}I(h`nb%P#-?iKyomi(;B{ICJ|gj`Yjh|fwN;aPC0(nr5rWu)U$OCPDyN)qi| zkyc^|edLLXC_TWhZXFZy_#YnC@bhR<$Wi4lB-UR54Fyu$7k(b5_LKL$z?#Ul18ad^ z*IB$z@4@v|=8x8g8#{34p5*o~im74MhQ;-ecb4Vm0aZxNor*z(VojZFx%Z#p^VJGcj95_CBg`!wY{CeNFxJZ`;m~jDEZejurYP zAb1lpn{X!c-?+`bCqk0*0&&iRKM$POmxk!)i;m*|x%Iw`JA7{aS#aUI`cXy_VHf1t z$T_n0FT!PQ^WHrb-_YJkp`EtHN7Cwh!DXrR{|~^9k+zm@*^@K}w*2Yf26&t)-w07a z>>YFUPHslT6n9cUM;_q|ok)9+J0)V(;(K)}0Iy!mA+@#d-K zEm^{HEnfyXMp$JuH*8Pbur47I_pPVQZDsam--nQ`3Pb+@cR?b@Jyz&TLtB*2f`^cI z`*PvS!jrT}Nb4ywHtr!%bE-U7@By@)+^yEiDp&Fp@PgbiFH<^Ut$MGJOw@_}+ZSsJ zRojx`ZHpN{Nebp|*UCOdY)M+l)VB78Q`z4CE8KmyWEyQrrX;M=G8cCFDP_~i#?jK} z^#y7rq|@4`B<4;fonUQC>4eqK-j@w2ow$~2Z2OL&>tyNFQi~hgm2~oLN=T=ivB~>S z3Ckl9L8ES&hs6mFNm!>U<|AxdcQ$+13Ov}8ADfFgjD0G4fZzQ;HPVD_VhN&nej#F{ zV#jftw})|#@O;;K^(SSCgDKqi_9jLHx6ov1Za7FR(!_Fsg8<0H~ zZlU#&F^ig-Z!?E#u#=kZXQYk!Ytet(@N3lijqwqP6hr(4M%QuVf5dOj9h!l$BPZ5g zt9KBuDt2O~^<@*5rCt3``2I)v9gJ#-?@y@NAcV$+&k74na<^Dt=j_WPT&*{NJ}PZf z(%!La)fBPVR!kR1X|)19X9{nSHE+*p1&H&inOBRGT_Jao2fOyu;i2(ZI14_D=(wEY zL*g@L&8_dba7FV2QD-frv#7&TXCmfHP(!c@n8Ye?=ifmuEr@*zUoabSV6yKQ0CC5d5Msbu5d#+Qx$WPM z#$&)J+2?N7P_s@i8O*5sTzmsXM6meGmvBo7F;$9Q232Ab;?YS{xesj&2-@<^ zf1dGUxRLuu#yHXrZq-m+usvLnH$Uo}CSq)o`ir-=y?&j}STfFON%n+l_JZ4?UcxF% z!sk1YxxK#SFX_`;Z%|wm{5|kn5q0i^r>oD%>Xm4px#M-_32jn>wtC)~wEJxT6(e92x z|KfjqcO&ihGMEQn8RkKj<|@O3(oAP6pFCD;{aaAA1F>(F%KFkPeRip8;q#$D{Iu`| z(O%=TSEudrvVQw=zAY7R>#etC;thLI)(SB(W)1M}n$H-P{&|FQm-}UXm%D!+R>vdZ z^KmxBUe@Z&R1nGbBV?;}&xmj4ik(ZyR;6Oy%z(oJa z5K~^u(pQaErLkw64V+S+*JQYiaZ)y{4nx95t^3cOkuu8M6Rz-&t1`z5iOM~2HOACF zlw_BEEjcS)Uo*d*uCL(ML|<*A4?9JiB&<4E%u&e^ttM?Cc={0&lz>3R46-L;6do&S zC)8AwrpKDpT>DDyIT>1?R&vn36uv1>G`D^VZ2Lg; z#o20q?;KHL&Aer9wx&{1CW#WJs?&05^dId|_)Vg@xDyI7m*3(zSesV;9c&wtKw^MT z_Ne4}4HoRGpv?6|4h2z$R&8t*)+&MMK3!;_1v%g18}!Ej<{j6??sLbyCYc&!#2915 z2g0X|T@UD{nst|`wD^q+;zmxk2|8J@;D>A}5oeb=|E#TgFGhSa;x|Dv+*=K1YpA*1 zOKKbYbz@wEkafhV6=RlCW~Kx660#Q&@+R*8gx&KY?*#Bfj}xAbo!G-vur=P9=6qrr zjNeffuFSbAf#+k+g@jSySz*^BXij2W;W+?2%ibh*i?8BauFt2lHorJP?Y?-OOa*Tt zmmHbE?k-vcA}x+xag(1KLCwuVyI2-SoNBBUi^6N;6`&XK&5i)SG6lS1H%#DlU18jM z1huB-j=eUB;5KKcB8~j?Ut_?m$G+Oz|~|Sg-iLb#k271qUEW-;2k49YajA_?8&X zkCPkgyurO1yoLA%%0+6{mWBaAH*eCD{HpH@m)G2S*m)86w0oxeo-$p3r#C0LOmKg= zy!=~-o#%)$I2k0Pg?g5m;!Z6QuMy~8H4l(?Tl|fEbPcqIHlwsi)R|S_pt57M@>8sC zKj!>ngDOXh4R>~+M9X=GHFK^<^b5-11EDpDlj();0cXVH7#1r96TZyvs4(*SrpJ+33VHR~GSQPkl( z7%p%8+BDdn9+v85f9Myu=B??xa|GjwY_Dg3Zj8Krt^QZ!0}Gy5ds*jus3RZ^2yeWn zyQY*-WnGQ3UG74A)E)O_uU%)16Y~{03`tD9uq3Qyfg6wI@t(KM$fK0E$6U>n6AqLc zXc8lQLa*Jh=1@QJc8GGl+Z}wwcbo*}l)91n8leZ)CaQL}NMA!H2j3mYPUQ>6#6JM~@R>hbcXA-d0kQ`Bu2RC3_*bgLCO2yn@3Cy?6uk8mU;mNzD-zP$F95 z@@k=bI*zm&g|cDg>4; zcn_3~^NgZwu&qy7$P%OQS?p;BdW;DNfK6c3lB4866>H1b^j+%-fsBX$g>`cgbbd5r z7QH;sS#8BvZT9hA041L}V!5K!@U+xy|2PDQ`nTchO|-!sn9pm2JE+hTOx=$D8NnxuX;Ovm$7cX|GR-wv*tX6#Jr= zI@umgr;~XjZ#tdKbgd{5p-#3_j)9YhJzS2dy%OiHd zAtx|b?T*fm+|b&DE6_u2;pt7%z&&oPSKXKe+3(#?82Rki5&1Ld9q|UG8f6#mW~Q7` zr7mHlAgI93n_8%WQO?r9qK2o}(!lXIp@Ff-4hbv<;2Um5?XK z_3nzjn!p?86S%`jsfDOD1BONEINfYVX|$~7RDU1zonHk_LX4-@9P?Vd=G($bOQ~7; zm2>?3x`bBXh~e~t3Aj)~Q2H!4xID4uPsV{(5QySD_b}Bq*R$zMf~%=_P&#vnD$R8% z$HrcEU2gz)Zj66*k`F|GPU2jTLHGnEg7aD5>kNX}K+>H5mJE?r-~ZHd18LzEBX zkidkXd&I`2^MNGegQFx(h>_av`I+cl%pOMGw)QpEFLa{NCY!%u0Z5-$&tQiI^#A}lAQwBB8dCBS5aTi&@<&S(#3h5iE^y-jC13@QJsd^39Xt$9Pm=iT=DeO+8MU z0`yqp2DsXZAl3xC9>CK|!50>m6!oBeQ|n7Nj}tHbTd=5TCBJ?_%J&TbK4a};IzLLL zpMKnpxg5DE*SBi}$I2+^HKk&QrtRcXV_XB)6_DT-$3HlZWfJzL*KGeJ6glP1b(9@w zeRA5?$9UjRz`6x{tHNfdMhHYF=V4bh#R@|&9U;W)@zerGq9o<1XZoW_$uo_0mDJXh zVpzG%ct-8>V+R&|4Da81!ubtYLym~h5pBOap{$`5?HIjPbKXbtE?Wn0ru1y+ zy5f5@;TI5+G+h}>M{#vd-+}YHTx&(e_tQ^FbsA;_(i!Cuy%6V#8Na{7??!!S#CY1t z7t)SncHdrE3*SjjH)7C;>Py@|){nbLm8!&8eAl4l2-kbC6BDvg@R5*-u_Y_3%q-+9 z*~LC3je%}H2)+CHbVK=&t7GRu2Y1SNQz;Wb4F+h5eN&b=VowRaSPfs6U08ooqSC$> zS`6}M=d(CZ9Aux%wBrG-!XRM<7Gv$-?G$%T zDVf|)y8seG9RK5_KzD>n?VNN8 zopTD^g0(tIM}!ua79DOv3))3gY@~G_`EAJ@>>@*E1tQO5Hc{5J_Vyx)y*;Lj{Q#8) zi+MOl8lffQ>9gDS3$Do*RGv?Z0BsVw2)=oaHP_pit3cdVU5#Dt@B-VpvRs$wJ0g5C zw0}{PIONTW16WHu5+N~_KMi8a6m42qLWPO20&uHeiqE*)B29KJ)Kff5>OOgIbki1pRkoR$#$spmI0p1km8* zK_%?G24Vv|OZs22X)e~U{w%fMrPi-oi0f{SWfdsL4o?t#$9Qsxr&U3WxXao{tH{H; z-_wQty8$f4FDGIDu4VE2vJ7UaqH;8zEiLybcTKqt@Arj6_=W&^xMjh`goe+9GbAudWPRDJoCEy=N04X1`A&pM*dgZdp&?qNBi zFP2V%r(C24De)Zm4ulTs$FH9r3j8+6UwDOanqAPGSBJldeO2C~`jX%HdeGS=c380M z2z`MPEq=x|ie3$j89vCk_s<9FWE<k>7x4_$}IOA{NjM-h_V-C#)Dj;E_8`I(Hx{M@PVvbGSkQtR2~s`f=~`e#JW2EYGP2-5J3XI2+=UF; zuik??zv8|wsl3z?7moOt^qxDfBSO9Ags7~<=? z>Rta&Lw*Gmkr;2<`4w7~V{XBnX86vv1A1?aU(F=r`f{`VxAmpF;K^`t`A-fz=L+b+ z_uTo8!Y+aKk$d;UFSq<0qK7rJmxd*u>A175@m}nL;RK!=l5eTsjUL6^cg%Yx-s^wG z_dV<=zwoegJZxpmp|zIK@Fe{GJCdbiB1$L`A(V&(!i_XP;9Vwch1|y|d+A?E!~^~B z;-6CWKd3eO;tjQo_*;-Si1_eCyC5Mv(Z~(dX4h;Y-Dw2@a7M)#15$YztU36J)Lwly z^2i6{4DbXnj9XJhO2^vceB=7V6Mc4$1`gm;#|`)&tJr7iFR!PLSMpY4D=p0;T1h;M zh|R-1DG&H^>z%+XAQL`(Wy_?-0ugI#ZX@qvts_o|*ZzBQ?AYg*pSw7L=j?;|2W-5d z#)^Io#N$@GIELs7H#u8cKAvdwkt|c}t%JMe4GbRm9T=}cEdWW;u~x(qD%ex!fj&II z|E2qo(qZ-PqgZ{zVuha~-rtdAILs`SKIWazTB8F7=rrkL5#x;X8D}JUoW!$OjdvV5 zXb4FL-3V(##>QbRu*EcBigeJuT+#Dqum8S$|68czI(EMP`4Bv6eQ6oiC1q+P9oA<2 zDY56;e`h=~Lmu2wfVWs=j_bRfHu64N}77* ztf7s*x80dXx~$4<-1J&e{!N7e+78Wwr8G2u zFJ+of4;L>eqIGKBf7e|6Z&J_MW3*mji-A@ZSNjGEnr&(Pp1XkDFX;D0mXZ=&AH>n& zt)6-#^c~tE@wYoxL4K*Xjo)1*T9+j^{$Leki^?lnbSNn=^zW5{E)6s>!@ zMC$|1=fyA91lI08sO{Gw`b6lpwtbW*) zBukT24(4oIoWuQvww8<8ZYyKU%WY-l@ZzgT>H@c8G&#|Mv#_;}LMLmRg>5l_DPn?-zl-pv0n z#t~DVcznE>6E4oXFY3$^TnTBa;_}*slR6Nj+Kd@oHo$cM{fhGICyyC@DVvF%ci%1n$22RPdbDaCHX(C9ieJivRc~R^hp%(o-(Cd6^ zEzRxJaj&{@O<0b?>50DC5de?92LOz?atYP0G zHb>^*`QxPLaMJS;J_B#O=?yWkoiiR>zKdV@OiC4ZYbM_Dl`MEp@s9hh#8+JhmW6GN zaj$~9w}1H4T)z)|TuY+KT%WE>UNZ-5ujiMVwF1mhOUqZ3WQ8uiP%D5=Y$-18ql+gf z-CFSz$%}Q>sq|hWz73AL%{haiO~eVC{-s(}sm6tNBd-B-OkWAUxZM%LN~dwC)a}8S zq;3zM6)yIVKkQuHz}ZIIjl(l&w_;TAhpJk6!}`}MDLm}VzfjD~>qZr>;%ib$ zn`eiMD~!X=Kf}ikebKltJGrzir*GT(xsWG$hn+WVPS5pI#JbP-;`8DpQUCD+@<`WT zFzV>@Z>DeIStsrRgb%fIM)xnK=y|rAmY=HR!uh$np4ask&JDg?^3_w$%%1c;;VwsU zzZN|%kT9@8_!NNeC4Ko;?5H9?F5^H?8KR_5(o+?p^n@nzhT6glnlC+dE6AO8>Xvf7 zrY(KlKbh&%*Ua8gots^p6RzBcRb}d06}D0|^m?+6Pv&>Z9XGW)b{E``*l~%7-B0L- z=9$+_@TohRru$GrcuQ;P69M%Ga2MI6`#Upn{=GK@ImLHICre$DK`)+_!t#{%t!8eB z=NKF@+Lo{zq#w$X@ax>_{gBWcDBaoFDN84>ZW60)1GXOFX5_(e+?BO45gGP zvPvYzGsQ~zvg2W&v@Sf++n0;y-K3r`jBl$hcg-IBjQXJ8xHT;2N_}@5^D`S?7{_{v z90d(HOhxJRha#b;`|=<)7%h-w%dE*9#ybiP*C)8+Nv=)NQ(dQ?dGrYGED$Sl#;K`Z zrhd+eC3k^G?oV}`++h?_(+A?;zIhINjgW{1Tt&?IV`}aT$hBL!i~HqbPp}}seLB{S ze^*Xv=OM`TSh;HtrnYSP#nPOf0k4ZM?r{I4F582MRJkvR8-Jk7x!du(H{z|q-l{TJ z_<6<_I~r3lvdFJ3zYgWS8#A+Nw}u(y6QzxZG9kh>E}sICLr3_ez~UjuE0%TI3Ms@7`#A#t){R#Ow#Hs-H#vleLKmhy{@LP>dQWg9#{oL77< zPxZap@GAFph~$@Sr>qx9vY zy}|LXe9(jLHOGZZN-nhM^zNzu^&IRGTngRX3^6?z;c~`@fyU<2fSrM>tm(|8* z)rJ{wLmwZ`D~At2edWXC{N@$kAS{G9)%Cs0Awb@UouB3;G-*ZYT>0hUYj=Nh*Zy}7 zw!Zb&JBQvq_`!j{?*Ds>_!@DSaRF{36E}j(lVX@lo_Xmt@*1$0opCkKJAk)wQ?vCHrYdqMA?;C?iF7e>fPbwmW)yWEA2E^!Z-?PYw?2q&Ep zJub>#_{j-CcmlCmo#?+)LnN}h0CCc`tHy|O@iPXVUT_sHtB7@Ltay%&dcqAUkG4EL z{8nNhLTgE!BcVqXr#(6}%J##~(ePE+yHT#oHIiD{f#*OMq61;205i^7#4*@Ppj9H@ zpvJ}hVb*QV-IIJy4brK5tIyQLUAEm@t4(d|OQv@DvaNbk#*Srx9wQ8N{lNQo_}A9w z3dr-{0|XA7h3S}q)krpf**aR{E*4J72-}DKh&$Hp=x2)6Pf@&|B5mu7McU;*->TPV z?D)Cr=T7ej=qG=O>c{e5_tbqrIckq|%|S1?=SJS#z4(yKSLwBo+QP@p-Ry&X^VV5; z9^{=oKnmu!XV1On;cI?;>j$^qeA}zHUHoz@dIUNP zYbMYkX9YOP8vsi&JO2C{_NqiWyanQhQkKaXfVFz&9h?p9Z~3zS_%}WY8ul-osP=zF ztV;ALQ7X$cJfZC8pyO4!;Zyi*c=YVmC=sBSSztR5#p(mM-R-Zw+4q|Fo4ALL+74RT zx>HiN%GedGUrO1=^YF(8gfH8JeINCm7s2DutjYIqD_M@as-_!x4e?tYKV7eZw^MxB zMRG2%u52#r^XSl638JAe^k2ba5Tu;_S394r3B-m^Jb)-FEZ$ZwDy`R0<_jd2as z^48w-5YPfg;x6#eBi?w&U3gF4ac<7LRnS%=oETsL9**`MhQ}#=x~Lq9Ut=|Bb1wrRy-4I9DJc06(QbF!H%f zK=2WFD$|L;tsj*>slc(R3#u_S@3ne zT%+?@$rv#@d@Z0o{3_0DCv=%ErpOfmUWwYx>Vk=$S+?7qU-R#CsqYM4d5mb#H3^b9`Zy^W)68R5HqT!{i<2^ zIdDPm4(OCmp6DU$Mezx|eek6oCvK{ySDjBd@r*n4{p=TS@bD88gwe_uDWEIiAA>{=)#=T}$d8EA zSsh2-qui!E<`^E}w+ZdwymkYc6t+!lbx134P};p$WzNKm*h!B#N9#dk9Cjz6vzWVc zuN(BjR&uLNTgKHGHGH6;Zl1m>u)`zWmgPoCP4e{{fKg%!6zU+R1ciGd;&dr&7D@4r zSZgWy4)r_cy((zw6gv-fdT}=HRh09BFYjduNwH?0g@>s00RBR!gr)4jscrpPd0Rz! z?XA=qijU-+6uxDB_XIu+jzyk#3Pf7rsYGlb)z@soSp}X|#X(Ru8_{Uf_vcihc3p*in~f z@|BiJ;JEx+1LN+Cz83I>-(jk+P3oV;M@oJ>Nw`h5#zoOexp08-JtMY zdR>+sKA_6tj9IdD&b@4ZAe*Wz3jQ;wkoq=lPb}-_Ug2?^(#lCHpe0TNBeK2 z#r0XY0f@1Q)18n!gJJzYYFKzAhB6xD*eyNVmU9a^3u6^>>CdpN0}-wafMwHKPeCe( zdr4wn25#Rp3AaalHAz#^^=Qj)S9tV>6D{H{$1~NNz~qTg{9R$vH-nfQvRRe;BKQl= zlyC$h_#!0lkBA&H<>(MAT_Wxxh~b-Xwz)TdnO04QY8CeqA$}PWw=lpJKBO?@Lr(21 zwdQ$rPomw&QfbAm^3(|RSsY=NU!{MM5lUD@za8_IZ1zoM6rzA60Bq--N9#l8E{{{k8!){b3=c+k=m5MU+)mj5N3xyK+n7tHj2Rs})tamg)S)H&$)swY-|1M(a@!-7ZD zN@_CXE9=VDiX&E=h}v!J$WmpK)=<}ouaw6lh4pJ>ALTO>eJsdS^{hzYcps~R}T{bTlUd%S)z}&`&7NuKIjwgJC3|X zs_d!z(65ty)LfkC!+*D`m)Zw4P2WD+eyGZxx(}b#NBISbJ}SPi>ZSI2=(?vLgAiE9Q}l5=>&OV%u5D{yu7n3W4lz=JiVpjpeOAE()GgmWq{LaZ|M z7uFuP(PxY^Az#zd@XRD{$hOZMZ+*KNzO!i4DewmB$lT~d4kP3;heT2+?2(0 z_BaclcfZ&Nhc_cfV7jeTydFL}0wiIi7!ikiuG zYP>I}@Zskb&k*&Y?UiMEwD^@K)o<9}kwY4x%sM9G!1~H8b46S$Hu@hl@~AuQF_&A% zJ_f9W#++eEGOJ#AwuH>8xJ=16&cDrWS%Lw}LY<5GA9Bn&7w1m{kUMsGNjOhv(O>y5 z!jgm(W8Rul8SP$~(t>_NIHzJ@)VWl&aHx+R>AMm3ZDZw649FA>^aUET>|1N4PkkSy zgb?4Ve@J>drUYr*6`jKvO`ex=7l;*f`MPgd@SuFcTEo3DXq_!5EaEpl7T+b8Huz20 zI~Z%#6sxs0&Nz+UjM$t9qquW95!VKNs_1%*+^@*`7O3}D*@9S|M_c19_-+Z?YIp~* zSdX-lHgYPjCfut^g%wuqyG^u+G1YmC&Idlq^Uhs->HoO&bE!3pq7lwyxVQu- zc;w!fhIR~p=!yb=IH!4rQAj*s&Gt8PvC88e1OZ?l5dBx8z2w*f71c$06>D61ilp#8 zF=x5=V{f>UGsE*fohOY6??sNEM4RzdZ@N`9;1Zk$9`o z%pq9Y!f&DDjx@Q3jn!4-x$r=YH@)}kyO$?j98vC9Q(HR3i4{-?Y*jwHv1-MNBvF&! zy%jNZj@XA>DSaup2`iwySHvA8!~Gxhwg;>fjx{kZjzY#jpl54DLVBaLC#GS=#x_&O zb+k9@|6%WKz@w_J{ozT@gwa+7jEc6G5||_)*D8vYKUPUFBU7~%{7kJ?^iD0;zPDGY zZN0s>HVHG6F(Lw{G;j?iK=`Z{5s*r&fQ(MH3TRQVjRFRp`hgQZhlH8Q`}?iE_nb46 zMCq;X`@H|>|F)0h%sG3nz4qE`ueJ8tYp;!Hl)r}#pVb#%dY#Oy+>!W<7J%LS_LIrY zSuXI_5@TN)ebDhp`wy{%^UVuMCpPqhl)sXj9j(qc52FQ6l>P$?j&bP@S;5jGW(-2( zFCzteLv!{xTjvT_PU1Mm@rCZC5&C}KmF#J@*Tq}9Hgk^Po?X?^3$4e1kmTNiEDn6r zezN3{6g-rFmT$#I&w7{4Y+)ZsO*N-X8{h)eNGC1fhiF>WRk0l7b+&XZZNCe7bBVSV zZ%ep3z9upv;-5T*vdZJRV>a@=&%RR0ofqy%xVDehr2`4qfYH!amBW1F3!Hb8Qdfa* z(l}Q?h~8+CED=OGA?itueD)1?^29#^i7x&H$e?GZ+ht}4%~#Uj>C-Y}S?3$vvJ@G= zmf}7GLmdk`tG` zW|qV57UpY+cL8UDrC8-KJ7m)1o*fe%7KyxlZi{+~y`yLN@y*kz1&~kjG4N^^pAaVy zYxKA*o>FlYE-pBnS?qCh-X3q5zJlJV6wjSDdbSrX_RzoNL-vIZ*|+3wmGAg$Ky36p zDPM)_k1w3wK#20DKyGth-TrcsZAkz$+1!2Xsan4-IPdZ=kCScFS_Y1I*#9(R~3}) zh4lUg{ohMBA|}uK#lxu&HX1nOMEfgpyyELm9A9zXGFunX&iMK>$JbGgubx7F9lzd& z?6T~-kj?lyV|@XlxU^RbImzt#%v~vPH*XN?81fwL`DbLds2;Qw1_mVE&c3-Z`oMO? zzAkvV#Y^T+2i~DxaYJ5WzVV%-$8y7*P)9-BQ-~;oeolzKzVTV-EpJU-o{tas$EI}- zJ~|E}fQT$u->Jo4P~)OnuI(52f<2Cno=yD%gVk@+WAPWnwJq&l4D*EQ(VUGtO7bvO4! zG`|~OA{C*XHC@}k!F^R{4|yX|J`_ab>6vDr{Lfl?sWrDPdap54)AQm=x5e(_8!vX1 zRW>YeJFGDaa*$YS+R}Q0MM$cNZJ7#ux5K5%L{ot`X?;R2(25hP%s64Hh|EC_PQq&U zBjz8w++Ty8<(#3RG)EfPF%oS)^^myEZ>_2O5o)9dHsvVb(?&;o=)=a}9yjSuj%O8{S_+#wKg~FM)wCFkJ z=Iq`q?`AAl?}n=x-wU_pLqq?Czh}gU%p;r^$?Yv| zk<~5gJLcWlv}c^u;5`pwuYe{E)4BT@&EQ>x@3?#IEX#LTd1ZnVew@ywp-sVUNm7vg zv1KrMu)WE%2%~>|2DGN8?frr)IK<-;>yPsd&-(juW%C&i=WPxTC+#z?ux^Z={m1YA z(R-d7CnV0mZ5ZxCGhbKhRYE9(TPn(ZItL>BkR3I1yye7?))?1r)L+g$T5qY2w-i5c zNIazUy>`!b?#t$5Ga%XvF50qRn8k%2YRn998{i>tdOjZG2M&ADb&`rw^j`{VQQM`q zZ`XX2kszE=9mBk(t(@!9C$+Pw@)pd{v7G)(O;jgg;w<3k#-dS(Qw?Pjqecx?>)KET zr}i(ksiOAw&F->^rF8cCo11#=vzAn|vwbH0qv^(?4v&hl^#2}rk){#dM_$4xAm+@& zoLT(KcczC}aSw-IIn444l4F+(p3D4~axE%f>ixg3yAo^vQBPj1JWd=*=c=AuG8=wj zu|V}o$AX**LI!cAjD1&svK#Rez*)VI=DY_@@muVdGWc#vW?gDVjJL`m5?OBfjN&wO z!$<6if=kPKETp0Ntx6%v1R5D_$+{_&IiT+9MRX-<$%C-ME`kmD}7)xfeV`WsSHunA_5O9urTHizi|35?LerQyFLMkl{M^qPdDC|Nh%@ zoVmmkm9tJ=86vblOjhv+f0#@XZGPt!76XEgJdbjEH$Y;vI2DTG>I!kO-P$C-5U;LB5qeVm!gm_-FMFekpq8@Xo}( z%&q2c_|obz_X{y=_EaFAAewpb2LAhs{AmQTNn@tt?M`sRH||9#v8yA$t!tNs>;W9}em#oO69 zzsI}}Z)Lxw+pw~~!x?9A;&g&1Jrjn{74#ply(S1egCpFc^C5q^{(wgqdI51$Asw04 zjhnsfhz6%5_I%w)VyB)U{#I;?#lMCI!C19rZsV49zlv(foGiRTZ1$Ez10lj^_Li|_ zeR)g_o8iLk*YlU+PWfK4=@bV) zV%MPKXXh?Q#QAr<;5I2SY7_k3pj2h$ZBA;B?du!~qHH!qu(HQG96shN69ex355hvb zB7atZ+ui9zN$nJGDc^=99)>f)g{T|&7yYO?B9x*9=9Yaq?7617_d$3TG3gj063O1J z$c{X`wd`L$eU$H;Z*BVQxeu_QX(wZ~=Acg{a+H13tMGNwY1AF3NZXZrzUicbYPtM% z6`==R^bYHSR^L!^VaZ7Lo7CsYluPR+o2P3QqBYf9N`_hEIOp&1pL;If&b_r$#~i7d zVOo3i#{7sn!KY)$F{kB`i;uB{tl=S^Y;$E#w!IWTC5U&g#rOr%=%nOH4`9^yTqcq* zOFw+Uot0=OJr?(+VHCt_kD6JHa(Nt`p1Yf+i@aZ@1$si|+4q()4U~bjdywI-4EtAj z9xy5(oXNN>`L=tT7qlH~O77vWw@XPgXEstNoy>g^EW^=nJbXXyw+KWIyKu5CbQmk` z6)hO=ud1>7s@Ig`4YzwAWOzvucS%(wbn%3_|)@ zIU$t{y=|nj4Gfi>+SEe(pQUxFe~4!rG;aucna|YGAzhPi2?KHyUp{ZW?Zj5;ey#!< z*AJ5HNwzJawDi?~RQ_;fGe&6Lc3hBPrm^QjVk1WUTN;}#MpPqW*BWBduh5p4A?F#v z`MU3ltBPPVDt~hM^UCt}{>pP{op0#!V$>syM!?vBs7T1|kHYS>zkNrO*r>=$cB%3m zKPpzb(hcNC#3wL1wPW{@l_6s0UEXwQdH8`+WDR)eaA9L4T7a)5+n(yp0st=*dWW?t zE4V3kX`s>bCDXgW3=eKnb;Dxjehc6yyyd#&GSAnILA>x_2j z6x@TMw6DH3ZPdMYSYKI^*6v(y+D9yrWk*t2ckx_D>Ad^bH-(C@w5 zX_Xs0l4FEy8+R#QASHz^XUV>T$gEHA-5hHE9_0r0pn@t@Z7~z3;al$C(Oy)s%iWv# zYwl!)edN;HX7UNy*}$Dx72f9LN1K~9{^ zS;o6#V`rk|f)zd6Rk12K1@j*F-ru`KpFaG4qGRIQtZ8B1;zaJNc1_b7X!*57Nn%N2 z&jrzhYtN4m|GXUkbs;awPZK3i_Jhs$crHFpT|kWk4P>0N(jybI1-gJun$M?9b%{1~%k)wugZzJ+HFe8#8t+dCwqyg5IcYkA0y z0i@TgbHsjv^|tW<;v^ENiG5Dn$JQ(ns+1z5&LLE_j#3tgf~e28^odt@ym!3p=nCxv zD{t+wLSB3-))Q!zYrYkXZ5+^2!n`-o0q{IoXfp`uZ$m`VHos>k_$v`Zi@?D9yAN|-X(&8bH+7rbM3XmMsqQvMC&ubp~n7{#y2g0rz z-lk*NT$A2SZRKt%f2+1Fw9Vg-c(8Uu zY)D&GdvWrpfioYotY_JEcxS3L)#o46t zGBtoIq0Efw&wNzmXS=i*4W7ZJk&OLT&j#EU$V@DH) z-6I*dMr5Y8KN!GaJ1OnHAQr z`K(%+6En}@>0$7BZ>=i)DmIdPi^GwxL+<=~Wn{*mNg2wJO%r;ve(ch_mx(W`hi1mz zAwqkxy0nZ?Ru`^30hR38^ucbY)u1dD+_b1yDo$NR>Yk`(Z4=F^wCVqJP1yH(POatG z54B$2c*My+IeG-1{ih=Ihl0|`;at;A4_`y9$RBt(?z)>JhntM$R0MU_A(i1?dC(h# zf?3@K4+c-pa}=wsz%RHXh54h-{Rs^CN;?)Lly_S}AjN=Xy8WM$UFJFPC8_CXb@Io3 zXK7#c4|Vu(S2>oOu9#09`-HNFd0gq4?Ep`cfz!%Hx`t0!u z0vl#)n{ExkEFNu7TnV|FYoE~j1^L%s)+XuT&RBu$ zU&>Q@P!?vIcyr!W_P-A8hSIa+{B_4^oz?S~gL@Vl+_axsaSQWQGT3aPsn)uI%<}hx1`)X-O}DkxEpR7-#6dN4CVZ*&M9-Goug9zvhiimYN#z7 z*}&3j9`H_x2J!Z*-wXa4_6-*4Y@x@Sr=$l3`jh*>mG~X@Wcw}SbzuwiRLPSyM{pLI zPXlV;AN%EDS7J~1F*AO~6XIM0cuUu2Fvl#LJLKGmtAp!#;f~!=J{9>5S3vd)Wge*Z z&QyG|c&112D)Q5MGOgL#pvR2gu3@{L?C&h?oclU+Qdu;8D)?&q05f))uY@iffo^Dr zzXvO)X}-ZiOE{;^-b0=wp=~<)2TqeQ0S_fPCd#{* zUJS~VEdpcNXxgQNB=G>Ll3=UagZ_nPdMZPysx0yw~f;}*(Nx5v0KrwwZL!X2UH!YeuiA0 z&d&amG>qKYFH(=?^t?=~d3j+Asqy5vBh^C{ym1yrA2I>^Oo=@k*Y`$mwR*E>-oPub z`e!fZ0-z(;GXGU}3A2&uRjSe-)A$X$d?E$<(r=typi!E(@i{B$;l%h~Wb~a_YLd|n zry8~ao~HOc*hSk*UIxWUo!eyQgZ5Z6rEx2^4;tO$hQ*CKz6@`hK*@>B?B>IrZ|JSN zu9CKZDu>7y$Y;A;=S;3)?BA;1uHALWy&#&lWY);Hs+Y*jQC30VF`V4i&}L7UTh-FU zovoRia_oVHwJ3ZbxM5ANInW;qRB9iXJggvhl#*}Eh%ESZ?ud*P4}xB0>imIEVSiYi zfLD9Oik3?jrEg5^nYqS{6y+7NPyG{Y%Ldv@VF#8WwM=TehK!}bjFAS zXY_*KXK$(VE&Ld7QnMZJNttL$Y(ia9-ej0b4N?Vg5TofPyxG(Dg2o1(lO|VU?A+;j z9L)?R6Fv0cfipU*ZxRX^)_MUYH4>?OZR`AZ5SEUKdf5XerjURkO%q2 zmO@``fv)_5&;yo&_(C#Gpx{nMaZ7NqlMPfW);$VT<}*a#|cEm|=yb z)T+nA(|mvXYjL?D>mu1p&C?c;GmILecg!lox}l>6cN#%+h)xS-+9Yd)I_vP7KHmb4 z(77bAzBcm|HM*e%L+M875X2K7GrGj9{dPkq1j~HfquJE`SBwXI|0vB>g$wwmS8M-8 z#os82UEfz8sa$K&wv3P$%9SX&<4$FBtoG2h*(f#d_!s9YvS(j0>gZ#|hhA_J+C}!w zap70X*kfYDNTC@ryYL>n)>c^v`JHyJA%?0yp^WMeSJIT=p$z*Kl77`}MRufbE1Xon zLK)MqjelXkYQN1IPTk$pC!+e+g0(+dMSZc`q;|`VRvBi8tK$l1A9G`fkZ;Syy%WY5 zhmi-Ca#H08QM7PsEov2xyB9ID;u{1N7wqy56UxZFls=)zLaYZSCPiw?xSuH;25!)C zTcm*OzHO?A!AlTF>0|6?kxDr+(>JV!w*~1H_3iw*#BOl zBe9yZ9FbWS)N9WIGI`TN*+7lb^iP2k< zvyG5$gLOa!v*B4(?DF-VLRa9nq~4j1T#hqP5st=+ zVEbLkl!kkG@y_JSleYQSk9zQbv14Iy^<>?whr$kTzh1E-kxz~%DBHRG^=$5??CjutkGi#@VG7R3oTghC6415Mp1NLY%?Up1 z*}q(ut$-(3uxX4Wt;VDWI#1@d1EYDtw>=-U=<+p=@*b2&Y;u12`N6d3Zh;@368MS8 zA=pvSe@RbA&(aHnjgk8cpTLZ#wUr!#Qi$fshq(l$kVjmwz&P4aD^Pw@&+;n>)xw@B z=7-|l$PW_Rw>@nvWO|6knjJRmz@YUMO56sZZh##UZ0o~hbcsn9Ij(K|-a?M?$uu$)CZ`x&bzjZ>| zxK*-ZkaOSQiDsFd5kJA76dGq}uuIr}W{R>m*;$#PqQb;lHh9#RAJ ztO$F{#Y(_RmsUi2k(2Hf>%Apz;R?ke;LBb)gu5xw48kLWz$4ah)asQ#SWaaR!8(Sv zt&WmG4RVLd024^ZffAU00(cg4Tb3m^N{EZ&O6}-%%%&W zr%k?8n=k0orOlJOJDzLv)P0095|6ducPk@Bi}-7H+$w{99*KBntyL*KqR`FhM|$Cp ztld?d9K-m*b7&J`MpQKfpOW!6Ez~^a9Y$VMw(3og#v$y8x--xct_>0KR3m=Yhs+ff z*cm~4B`iBtq%b1j06pvvd?ncr6ay|?@kcXfSDhTZ2>17JR!SZ<@ce?=Xc04#@O2)^ z^gKXO{T#B=i3L6R*|I(G*m%eS9`gkc+w*OE@@-lYC$<3IDwH+OVy~We4cl_Q$yx>W z(UU_y2m*iGBF&flfuLuk;##48>IA7jIO%rI@cx}_g=678U-r~7i%*?CcZ;46l-#g3 zu|H{KH@TB`{GJ8Vg6KQ?kKO-?ub%t36Y8o%=o2u?8w1fLQRKU)ri8q>ful>__F*RB zN$-(IF0=6F?1`fz@k-M!%e3i}XkCOL%W}WsklhU_c zetuVN!bhv=>4AJ9hC*FDiaLpYJM5cgfhPa z=Y=wV@RK(~nPcEI^Nx|0yh|$Uc|aVgB`v#dOl+UHRiB_4P;x_J`vOM>RNH&Rc^G&T zIU^(%X&!A#-j_6vw`oH|_M=>(eUN=W#eQELxqlqXu0dI)nZUzZDuYhqOERMa@5@Jy z+i}7sdxY(q@RqKnt`&X{Wp-iqMrEa~xIGFC)Kf^b~sVtk z3^1`v87bI|7%M(ESI_yA`U@E8X_zY<^Jqrmei3mO%^1n#pPJaTt&QJge@37%14DL? zI<0Y*FUSHSaDzLS6)c=SZ_9ht%$|#Vn`*tEQXQ;rRrlGY3#HWyms@xf#yQ3$&M`Wm z&R3L}9kbB(2i5R1ajk+@mKBJc(YKC5#;KCnfs?&+y({Q_MAf&g3nyi=G(jDX&kC+= z1cJS=3#W_u26WZc044 z?RBhnNwW-c(}{K6c59IS?s8uySQZk`5_6EB+j2KbC*%g^-ewGCSnn;Ydd0NRJlVu~ z_uay_m-^yA(}LhSS;iMTW%+mxZ216l+{Q3}$HIaXnEPk8p*+90Os#)&(T=6Bzr20x z*4nedmnrO8B2xoek((ayHyvChv`q&W`8iwC!Nn2vwy3Z*S1D&d1;Lw^~8` z4gPj(p>+X%U(nzB&o_U%<43Q5Y5Rn&SG+Rv<@5h|(TkTvFMWR8rmYWN{ov9_zsRra z&#KRab=D$e;=5-#c2`q4-Jy0ukb4kw?0()K5i;YGwUm}o<6I%`qABEhJluJI&aA`eO zk2UD84-Kz8psZGC6wD!QE8|4JDd%}GvFU>58Qf=JH0*l?Ek1yjXIj z*2e~d^6=6b?}NR=^Q^!9ukln)=}2tg@3OJnIkVK^Csik}EpW@T{=g^j7mkr#CbUCu zAa|Ka3ue#>W#|`TJeSJb8XNcr`8HN?M5e@ILp61?d$24dC;F!~kqeEl(DbcUqF^DB2B8V@Lr{?4Mx?3vTuo?;_z>$%H)L&vTawGym{5 zl@AK^4hNBSD(6dE)f;%XxF2}mzb|!Qn}vUa{v9cvwdY@!<`;F-ImZmy7f_n<=Rto| zmy4#@o_e=0wQvIcUc4Dy%_%oC#yPN|?c_^g=K}G!JZU~gPHiE=3=l4s)}*fUcXhH- zeP4_37sGEsOt98Td(Yq3g~;wMyRTxI9XHT18;&ooi%YaAX(%z$xVy!a-&M5%{wM6w z2{umyo8f}ZhWc!TX!e^Ia7?`&RhOU_rXG7?qF;To-v`eMFtke`(-dl}e4FHY14p$F z8#LR#I>TnSZ+}}{n}tAc55^zssNo6%Ei}@TJ@Dl9!2ZTONE!#My|~Mj3nk=$V(9Rm zj`y{{^+E?-FNY2?!|UNEPWI1IBMaZAhCORxf4kdv#kbSqxx}aPG?@Hv+|7_(S&3kP zrh=4Z`M`^D$*2rZ59dglbHsQtL+SaFecAa9GdG}IKGVnj;y~(e|n+Yxo7tX~R z?m%yrx{;11XEr6AT927oZ^pzx_MFAJPigZ@S!d<(+}rUk%3N59Ww3QSYWAqV3qEA6 zyt2FF>LiTLbvt(Iuy=Tl!{GEpE9+3oKn5f7*lT8 zGWf={7p3_nM+T!bqh^ABpDyQ<%n$0__tFj-d@^c->oJZFY=mAtWiYcd1@Y;Z^&QzAzO|9?XMso7$4CoXCL`G?O?u(TUGZI%m_L$R0tQcA zw6&Jeu2^BO?SgIIWetyZh5fuK4m(r$)hoyfu!>cDr`c` zdW8&z7U}@U72@o>;?|88`)*QXf3_ zSGH?3rICQGl1Wtg4Ly~}K{tr|sL>R5_s6N{PzpQm@?7Niw!|xCH2}>DTB+55#vK-> z<}I^UnBQ*Z#a#b}`tTH3Im=?*8|sU3){4IXH#1n@vEd&+*N?G)v>(?Lo?@SIqf7>e zYOY}qd1od6-`~~I-^?GQ`Ml+=Vv`5U)M^-O5r-~P*1_k1e=^=}@IUhe@aL_A7zc^W zFxZo}h~3rR>R5&R2F-0<&ebro-Dyf6TJPZxedVI9mu$cE^>I6{Xq)iP!A(b>?}}z#yl?w^zqoJG(O=xR z{pnxaS5|WIL-5J1TK4+&_szQE=g;Hc(=UDs{|>u&TIK0iEV|;Ns^_b&zw+HHe>7p* z&8Jr{s{WU6AN+Q|YkzfZ`NXFu-gzh6yw6oKib(xW+8=bZ&{f>;#cz5`%3XsBELU;C z_=n+j?@;e2Tw@LG=laJmD`;`KuA91OXYDz-x1z&){@RZ9UxU3KzH<1(S9(j<9u1bc zkIpW_`@_Mq=#huVV}9c)bi_My?LmISU;Os*%LqQXkKnI-L9KGBbr|1DrPg7*IcSyn z4guD|K>u~P3j`2`2?UlZ5eSDBgy_NZAE~>xanNZlWKk+}A37iR*R8oL<^l!>-+;~)_5Ep*h(+4;;j2d$BB1DREEZ|hL|TTdIvd~@1B?v&F8G9`=+ z1Pq{=7x%X@$g@!UJMB4bp`J!Nbe~wL`(Oj^(3am>je?@Q5k zHQc4w3t9V@Hmyv(>g|=8{Z*~^=;0Z6;}4;~ubS#DA9$9xwC*hL zu%UyzB^M6zoYd_>S%zyk2rSN5#l!hN(eL<}fsl{*SukAuDWb!ASe1|xY97GJA%Y%wzz{GDilaJoi& zmbx}fTl3WOt~HUTAt?^JL_!?nTn|sMFxxS&x&nxs%s!uuogB>7;Ba?Wpgr!Yo6wj% z+CMPebGmvP?L-!1+!B5GnAW_Q&Cz2bVM-6ntQX4x^V?0>osdVkky&ORYsoy$lQ5XO zXf28UaITl~R|qpTDl?T|B$_)}d<*9KRaZwim%SyN>u!|t=~5v`2f#Rg-(kp%!+>xE z5RT+a7+*3gVMel)4-)9`i*O%}AJjUCejhYk-%J~TB@Y7PL3n@g>^lgE2eo87D3a|^ z@$G2$+8;$AAr7Kf9jI{tuyrXnV-gO6wjF?tZ$5kr9Z-@DPp}rF;7fchKinbXG)zi$ z$T*eo+1-J0I{)w|C{5TM!1EKp`UKC&RV05u$s4Cqz72f>`hNn7mGGAv^?jdcT6`jy zC$gI0{KFpu!;evCKd{}eO1Tqg5iRZe7?j61H@^AsEl(4Ck{zdVmWpDB`tZkSbr^s7 zJ_d}BHN8I8tr|^Gf>zJpN3X$0pqDPiRsrL@eIKHa_~yg6&_{}11vpE!Y6ixE{4_835f+wX+~LlG&{|z z(Uw?dH66-+Q}PP+p{?PsIN9k(HGV|#8RvY_+Tf(aT|s~8ar!Gtj|cr{99RB|Gmd*v znqP9X0ZKz|qnulpb024W>Rst^hrhyu+QDgZbvf!TqV$0&sw}01nBq3UW9k=ga>| z_JWMhKV&bcJvr{isr{hEMYdmFcoXNb79+X>#02MysgP&={IxX%Rx!Jaho#PH$|q* zpCm#!J;viYWtYIjQ=z)C+4$M}y*X@$>ugf1IP4#exQ@eutHuaX<0bR9sIx!~f0CI6 zOx>CLT9*C1z$GQM9}6Wb?UI|PK+dLu&~d8ddQV5U>HmE#Q)Vg<_P9cSNs$iF~{V!8$Vwn>=3aw9ygYqgk4#o zVPr&N*1}s&>3J>YY0UlqT2k!UdCA-@-f0RN@|d9P-Ww4u5;3KCFUua@%i>z>XcN1j zmFh+vdl!_x3*u{mH;bmz|A~Lk8sxHo|4$yUpar{QcXzKV}?J`(WHgly~ycjt%mbuGKMsu}VbK zJXsNUMl9s)C&TLoxaq|9jeqi%x616mX?ncT`|1semj1u}Ru(JJdMNvg>+%^2 zry(z|jJzd2G#NjX!L7579s-B$HE%iJNJiQ1H67+%V`SNvi~9{IQtyBJqJ&1<01P zYh?tH581tcKfnLFx1F5UjE)XKiEYjBvF(r?S6FQ=`|`N@4LWu}>i>6N^rpmMKLXP{ z|HNl&XQU80jt<37 z&rE2I^~+$3M{yo=5Td5JcjWxKf;Y?q8nQ#p+ACgqd!J~AzkO%Ct9PiXo*I*XZ|c1a zaAwPCVDM%BW$*N@*t3S7%r|HHy}yhXz9g|ih`1`8vrUzY6f&;9C$?FL!V`uH1%==- zk*}l~A$S|(I{qnw2*;jqoY+4y-L%yLak05>tmC{+ zmRlheil^Z24oC#^j-~6gz3~&cD^|DO~Y{!oS3g zew}8Z3my^sSELZ}F}K^)w18)k$MndS%H&_H@ozUZIsWGP^P#|jn+!ZdfdfDI`zSDE z-TcL>&xknqr(_nt;LdnSV5aAKCB^&?CuY@bH*Hz?rtxozmkj-lsz1t&+zI`hWz4h4 zu>VS4YkrT>GTN$+m(WsQ_GJ?z6+t`QFPU;|N7EJU+_WMH{tPsDu2$_K!;F=b=OzBY zkR);qxHChSJMeu0<@Fx7fyiE|{q*)%7)7OYvZh@}MN8hB+JQHJHZ=z?)cAM;9(sAA z>4m)e;4A}6C|Rp^F%gOl6VPZ`u zwxe@&7W^g%n_AhFb~$K+2;aAVH<{{e)nhp$F>7Pirs#>!ZLOsFI=`X*3O{1kPBJh# z%ex;kzi2In#af&fQ_wxr6SHxYGQ`8s?dNV4h{({4_a$zw;?>#+16ex9@-Nh;LkLS{;)e zam>zo(w5dL*6cIlIup0Dx)mMgi0zh-T|PfVForb`n-<8)TtnsX!$VwAfgkYRE~ogx zm*H$((PG})7=kB16GOxsXDw8bFF419y#Y;oj)#^pd9%@$JkGKlyY`NFmZO|w=WX(o zT=!&wYdrp2_qzhu68tv@|Aq12x+m?mfU&qiTi!ZUN%$7H9w%Qb^X-31HOYk>_6+9V z;;;uf)oPA67F7<#%@dn;Kc>%VFI8~Jxwwf~MW%x4{f{s@dxifx+^~&x+1F_O-ZgH_ zPXMXt%9)V1uX#&ht7>YDi^%E?wHw2+nK%vbWa448(y?j{XQhhwY{1#RPzK|<(P_8Z zy$hmOJn5wJkT&LJuD4g(>>0{R&IINh;du+S!ZcD_y#u5)as$a~!|cpwSAo(`|E$EU zneP)Dv+m0M9+{2rlA$#Jd!n}HH_m!y)#WYcEeu*hJerubY7cuw3)EY_FY{iKo&yt; z?OY+@!~pZFjM$NqoV?7z3mOhtM0kW?VjEx!qQA;-fE}8&Hxw7U*uoCDTKQXuSl9*o z4)j5!S?|^&_y}GKQZbZbDgJHq(<%%hUu(q0liweZvMEqjt@~4wM^9)D?*Kd;=eD2? z#5WwqNr(%k<5nv11K_;=N2r%U-VYsBKzLYXCoMp;{1I26ff&nq$UTV$WKvnqNEx=( zR;BzSW;{`YeNQ7!2Y2(jGeyA2t>b6Ji^4k`hwT#|3n{`rp!XSQch?Vbp2f5>GstiJ z!jrU&(lF=7uA5rFbI}{vkLFw8N=R(E^}^MXF_` zLJT83^LY!uk#k~?9`&ZgtcjahTe4{KWY6Ec<*kUEaA)pb$@a4uc9%uEKqt^Gv3*Dq z6cmbuaPC1<%kLc!XJuYnTswc-e1tC*j1H+CHGAM(SOS8n?%Q?|Su(_q~`1<*>5x)!av!iR)G)X8v#rRyu8ec^_#`%-XgFxn1!dcN?hr zGavAt!cEb5hxKK)tmoH|AFGGTd&Cl94@;Gg;r+~2Y`>X%2RU~zazri0>3T*Lwij{M zf{&|JS)PY?BL|tpP|KMjcY3>gbC&RB_#NkqaAs{Z&a6qD>NPj3r{DPn)~!l{g%>1d zC6;nDvfe3hNGQ`@nS38Smua8nk$L~zr1NFh(m7Yjlb9En1I%=bycdIve`{R*!YehU z7XiL}6^WL{Ei#6V_%d+;>nRu(o(Qr1%gHWE2jf#1Jhgu7qF0u_{PG_eyJq+^wup2? zCh0EZ+(lIRrO2o!{P}zEC*#WGw2CSXztdvSd#+XH1{V%_T94Thv=17&Q(69e&a3(J z2rzc?r{_5M6I>78!&xUi!yWt?()=mBh%(<|ec{H*udq)>2Ix$G3s**-i3dx4jGp2O zz5vu1@PF7YvpcT&Xc_oxIx-CP0jp+yPguBBX4bX{ z`)5YnEwU8%aB{~j)86FygcAK|<@bGW`X*e(ShL>8z_TKM3}(w1R4ndw3|4^NwU&&* z?)e)3-y~{>bUVjj@=`MfZ;3{;WrRHjyVrj980=olGwXUh*7h8O$qg$btFvQZt%xC8 zqZxrA5A~$l3r|4PahFw((#CDs5vc7xh}=!(YBbxBgF=m*=CW0Z+HTOb2eq$AaSv@kGJOC(q5F-tDMpMbTpZ z&~YV`aSIn@^6vSP_eh?H%x6jPMhbk1TD}yrWRt^DJ6Z6YJSkqk=MZu_73wUIwUS0%9n4>>;1^KoBe#B+5dWOZ5^3uSb+y@S!g$irJKcdx3Eh&_k? z{N5@HfvfL%OLO(+MD4~6PD>-P*Q+J@IlWmLm_>>0_jF)%oD9O0_ZCAVbUBr`KI5OKpa?{Ei%vg%;kl4^a6E0^ja%BML_55i?>& zQ`>Lgzs=Rb5x&g02cHtj5z-?U-U9kQVc>{vdr;E=W4G})r!GHnSXaIP{w1GfWqwF$ z`730sD21|P#l1!)@16SA6U&$Na!*FbJ<(oeeGKg_#2kXY?Y~iB?RgpfX~7)I>f4zy zGfKDhsc-wg`Ps6*|C_7XHyN>sZ-8P--)f1x3pDn@&T{J0D_;SAO?=Oc{Nd@i-B#Ir zuR=cl%B))=TNAYvbDUJun(}IqL76$nu`rwA{h`UoZen+Bq;$c-!VN#|s$#2hd5bZH47WpW9v^51e=@hS_)WihaHI}aF zxtbMgG3Kk5I`Qi9{mF{W&hJj!oOp934J;_LWYtBvwIA9lD)(jcFLW!uIY%a{*B-7y zal%e|<2jV5z2{x7U`Z85*rNn?%9^Xp?C=~x zfA{bkTBU`KCvZ!q{ca~kE_f%r$g~sqDf7n|j7kb|F65NnvG!%#vrwLEU?Y)N%NVKk z)TSb=ps^ZazttPS)LCJBqeO4-vh}czF?fO=$ILVCe>jOPa0k6NT%Q0wePc^q@)@I| z^YjxB(BFwgASp7PBNTYRf!+6$?_StqpC4iSHqZ6o8AuT)kE@j(*KW-B7%YoY%HF&A z7Ry{^JFbJkXI`9d5J?DM$c56AUikm+BqF%zdoWyY>zdZ=xg=T#7s|+~F|ZIz zO4v9xC@W)dXQAx2Io=v-M9HIF?f-%ud(>cVg(U(>EZ#1x{|ZlN~e`7(t~+?Doq%|(6&wPvE+ z&!?)4EA1p$I%t`<)Qe3E+X=iHMYedZ_g#hUrwZ2cdx^ijAAd0ucb$Je@C4O}mz)*H ze)z|@M++3kjaBTQ%yK8q@Xnsg*jM3ij#6hgpM*clOx%GVb93g>H1Z^vQE_+~AxRAU zJpN>lq#p{h++_pl4^Du8NwrS=`KH}X?nF6Y%9CZr4>{JccgslZ?p=5RY*f(3&FBjJ-i+TX;D1AId01_P3VBl& z$|UYB_$u@uWuBD9n~ntsXvtf^i{%413#EjbETd)hQPAg?Y!w`x^{-QVKz{uo$;jZ$ zZ0WO%kj7%-Cipm!*IV7@Wb#gce`FjOX~pNThkbqCbK6Y*YLH)x^sgE6>#dpQEKa@# zAjZw$JJ6_$d>G;k!8_)QG1|;oN6J@8`6RsFp3}BBMs|LJ-5!yOZP)P2f+Hg%$Z)VP z?s}{G8JRiAiHG+?4v&ny;18tZg>O|$CK8N*ls`yF2QO%h3?FEuDefUdjc!=j4e|G? zhqk<3tunV6oYedBEHC*y~y!|FMPActws)- zpY-?uQ5=Vxkh^9fB@rwZzTF)k8QJU)q*x1liCT;{3#9{h60&-eg(H2~xX-}BxyQ2X z+{@ndt#WSXa4~(#!>D;fIs(p@y0d!jmVpz3WtbD>&yI=?Z)q#ArVLu*e;XKvG&MKA zt)xv4otn{&mZpSnYn_TSBbdf>jt}@77pN-mx-L9EnI9YD_L{S>nHZ zd4ZhUwPXZBDVf)lP|O^Nws-GEwjuOSNsSq}!6XLR<4Y<1YW^+ z$;RAqA$p=S%r^|kn6nihNOmWT_<`zkfG72d;jOr1c3Xsh>0(j4#A@4#OaUB4!n;g?u3 zd#kbEF7>J7iU1*mGrP9UK%5W-_a*wQxX!Y*go>tAz7VySLMi6dQ^?|m^DC?u0PiVC zq&05pU^|}zP3^DrfEUlgdy!OzT<~=OTETLSuYa=Lb+Wg#m8WY`jYXkU@P#6tm&3U=cUKUnXWlLH z;`|LPWBD2`lJ6t%eI&oTk3Y{dd$4@)YnU4|Cxo}ru9czDA3f@#cV^8;Yh8rfplX(& z>@ca>wTNc~kHL3$47EB@s}r?;@R)1OhrgE^GfZ1J;o?4qwmKW<0Jn0~DU~{S7d?hL zcmKC*%?BH#&TP}lF|-1>tmi|S#@!*;%5d?5aKY$*|Da&aC!GbvX^xaWe@5N68gDwa zpz&9y7QFgM@mZ%9j1Fvdt!aP9)z~kTn%6J*Vn5d<57&LO@#cpM8k-(=y)m4UK&PR zfp4YnOIJN~)la|k{&#M^^~GB+`R>y1o^@OOZC6RGv>k`2B#P0KHM{%Llle0p7^Is; zYgDwc4&(leHhR=!f$ykg`i9dqbG>Ya!-{TeP3HvD?Fb-YCG*jYTfEg&K)FW*6Zm0a`k`qy-*_J?Z9+ zJmy{lgK1Csh}E*#5F1}TQQC+U#2#(XmVU^R(Ms(G++RD3aNKFc6k&em_N(sa)Cu`G z<MKS@JP+1R-5< zt0|u#g}*{a&6^2DX7O@VSRz@dInLm z4l+5KncqSix30wkOvrR(Rt{pH(h}c&NZa<4{|eh4r9b0^wN8w!gH=|xQ`uIea+_Bjod5PMna z{Kle=LaQv4O5CycyWU~sYhR`zj@~l66SSO9INjI>GM=d=h{QHCV1M-wB_lgq|KSL4 zse-`Sb`@w3-6MVq3r~c}eQ@BDxdmecSiAv<7`5E!4`@NQZoU?3T8@mu*RC63x&e2K@!Q?mwcXtTgN)V?YU%L+>ZP&mIMV zp`onU)%xp#D50DfZB~hoKR7&^3AE7;$nO*U<5?Zmoss!T3*Z2YrxM)t;( zC(YcCWkapm&sp-!a`28*65_-?dk8x%{%SRCKkY*i8G8@n8_awcYZfCrd8L}|(ahIc zZ0Ow|nK{_Lo%1`I5(}R57S^2j{q)-M)3CKr&$MU5t~h9Lr1lvq^Jq0V#$K)F>QC>m zsAP(?%6#DH&HoEA{Fn`#H9j+IFt!`fx4uV@att|_=q;@GByC)3It?z&U@5YMKhWh!~lxpOz{>!zyu7C699ksB{S|w8o`tuEP4y>Ux*V>_U<2=ML zT}3V^X0%WFK13vOMJqJNY3wyqt}0-SHSt>tj7*nktI~a`y@xD7K;1MoC&&2uTb{q= zqVFvFj(yLx3$Ycg@RO{SoSkSf)9@z?eNPN1xsBR9lu@fT^S1U*zV+d)9mkdBL){B- z4eZ_>uxX)F25fg5%|M>p&&;`ql~=dONQsUGuMsmVfgCU-U`rr=O66)Ak)NqyS-1DnQ3U+IykfmSBYtqU=cpPEWe=EyY_NxaVyF z4m}De9Tuv-KQi)L%u}pYpKp5}l3(VY8@rUQ64D`xTgFfa@ZEBgfugwbdJ~ei6REdk zMHq#ob!XaNi>v!mKUbenZ~RSJ#omM`Sd4)x3n{x|z@$R2rdr^J4$!tYem3!w|2S_} z9K?+I+<5cue}wb~b>dN>zQY)!uF~#Ub!YW&KBoCL zd%~%K)b24-0~(7aebI(<;a3TV{>a|oEIA)*ilRY zhH#DgSNMiwD_5S}f$av(MEoXA zEmF6voy_cOS4d2=+5^cM_3;CTz39>>Ln7m`hvOSxFs(NCtt~gzS0{%9yUfB^_)2NB zV{(U%ykBV|@BP^`#(qG5`=9mq$IbW1cxJC3+ERzR8o2^Dbo_j*vH#!0_rH&aPt6?X z4wBlnj*SmOlT*UYZ1k3s|Dze@7kNoezu=tBc)X)e4&JtC2C*X@tLAx2)l69}XK{k9 zEJIyPI5mG^gb(f`-Lv2o+PqQmrDI1T5_8Ef%()QbO(<1&LRL$eUHYs%@uA#=PvsGB zxyI*3PvQ706O;CSBU@U{TmQWF2CO~^wN0YzpIOgm-kesDwbs;*lT&hd;p383jXHyZ z7Ja0^o(kj`Q~e5T@{EMMOD853+y)tt-N6)U5xYGLf?4duixhqwy`q00EoTMN-p4&I zLt$!8i3O0F+!th7l{pzPZ=>e=A!jqxd`~wuKzggQ{;^SQRe^hP7HbT1Q>#)ToYgSD zoBbAQ5w2iA>CT(Y7X{CTGgmS<+c27|*w!WWa@K6p-s??0LUiNqF!S54*X(bsALJSX zOpq^q)ETj2Pe&nh5SWtr-z6VHmbz*@FL+ez@jjp6^L_4iUJxajiGF zt7S&vyp-YbJ^lB29Xw7tEc}w8!(95M(#;du$CHH;%@es|z4P}rZ(j)wJXZXb<$uwu zVWkgKDrabsXs07`ej2>VoS~I$W&9boW>Y1V9((EW?1)yaNDRFT_zWaI=B>@M%~j5N zcW3LFth?Y>o9n6;PO-TP94uCs{}hWW(>=R4dWW@UE(BJ4;lmeckWp*K+%^VdhQXGt zGQ6jLF$;!*)BT7@843k@{=J}~dNMJldWT|`j$x2U4Xi&w*C2SmxM>V!R3=mf zIX7u9^ncqX1)(jczdu|=i;FvoA>5d4VVoG%*M?fpQK~&cPrItOtBPfqN&TV-d*vvf z^~`Ua-h267Qr>BmVNL8$9#c^(i08n}$c_x!iDsPA;qRZZgrH7!;V)K%AenpOmEZT!9k? zD8reDl6vOB+Ul6x+OzB&oyRr?2sRzOt-u?#>9;izjCHcc8DC<2fUir0iBlsq7##vz zS4Cn`<|}+@|60H~Q91igzS(~W|4Mws0~LHS9t+G)dQr+?IaVIHonPLNQ+vi!oNw2y z6IwN2GXtZ{-mVZ{-Bo2~2RN|y*M||8)2_bHQ#7UCtUT~-zH6>hw{G%gX0_6nJDU0Z zX7!zAFT5FJ2pU!#AU%u)=AqKY*VXWg-7Hp)K1?mdk+@4mvAv(;H4Sd z5(HeUER;^ve&s{8OLeBq2(>akwZvPl^tbq7WgodS>GYxWh6Ab1HfE@GY2`rd1|a%S zwaSseQxI6<=2{u&+#3$_X{>yH6JG;=_G0_89qw-1(L$fkTE;*zo}v7H()O@DC=0V5 z6t4fi1`1+i{dIAiXG@J$b4D`q`=rl}o=HjNf2Or%c&oP-00*mGK$Msj*d`c9SZ7I& z3aNHJh|9Rmi@&1 z9y4acm-S?-o>%N)&)vQDT=~h+1MG1NKjSawyIK3k29v%shOy`Dr`$P(8A?gF5f-t? zY}9$XyP=P9`xMw;A?$N{h24!vBO7+O57@@y<;s`sEQIU{nbog&(8@Fi1Tmk1b8Y5v z_!|QlAl3yr- zzwAHH7DET%Nk$<9uFzCzzD8-m=85m^L>YMD%$MGKLpa27p?IgVzNsOk9(X9*FGd3> zIUBgWL(Yc6qf;U@t^M`v-lGLf=6lnI?Ea90HLfPQ)G0?y*}=;hQ@Z;T(pBlkX1@ho z1E(NnT8-p>enWZaMx%4>K922WKV77s+UMxl_=a~FYa9O;pN#ywljB7nuj~r=XcJ(D zhNywKM*(i053d(_IwboF)I6epJ=7YakMV^);ckUHL#@&1xg%LeKBQJpC2Ft5t|sGx zu}8u2r56lTv9k5pw)zF@>j%kWl*`a2dQalEsr4@|it?VRR@sU2>OCAU?ox90ax%^X zwPH`uEm)i0?xz&W_Vz&Ey@jMf*M$K&1cN>b`cZ~NhRIO)s0}di0-MBrS^lFdC5oe?zGh)H; zRN$r#v;t`XekR49t}K^(h_dnP=OccdabF{&U6A7NGwwrF*I`C>$!$vB5pG6-K~LeH zcC2zk$1UVthTPZ$TC*RSdF`FmS0U0OnmX{9h2P4KZ&(B`DaMTTS;}Y}C5yZ3ydzuj z-j{v?vdnjUUfjY6pj;PYaV@N+!Ry<+C2Rrw@~~$BOEthIa;tbFVBx0pYCr^0jO$SM zadj$=T2NsDdNM-xv`)bz3;%SUbnvAQ#Da*oed}R;BhAg-fRbr|t;RNH%DLTMqWUpj z-cq$w%KH;BH)u78pJ_$4*f_G^S2w|Odh$CKyiL2!XcgOM37o*?T#v4yc>Q(M%n?krOrj!aF|p0)-MnKKh_8Y7XZvXV^0CfC2! z`l>kW{}Jrzq^cLgbInop?7t6^`iMn|?Yj2{ujW$~$23;w$R{q0J~c4a%yahB-Wg&4 zpp9oue9gAp^KD#y@Beb|-$`|hr0k$YGsvqltNYOtDS0wVPM+l~X>3~OI4bN+_DE+5 zeo-r5j!{TPi~S72BC_zWdfO(?_SiXlCYYC@W?2-RH5nNW%*th~z9mY@TeKv(L;yR* z9jKeQ3zC7q2a$Y~B>cs1kPYDM#>nPYteYX<*Fh%YyxAb-7jOeF&Kzv1lh_Y`l&J;fXU zX6$VGlkAf$HYSXb7HWwe<|wN5aY(4;)B4y#`$15N`b9mvGl83^H5eUD2zm54OPwRk z%`|Ibqb<&&j>)oKVO_>)VV&&PQ6^$VPHUpQVI+i;p3p4f<5f_)9q~IWs^>^=ny=A! zsa_MbV^=g(SOik04c@mE)r=nnKTlLW2;zJ-^M%l-!%=7NEO3D0Z*U2Gv`%_Dxtb7E zUYN;_8*uVV$jPdXiiFMc&Jtz@Ds0elCh#q_78VY`h*10E?G;J6&5v>nH-Kz2@@7{R z;^B{|oBl+``GeTmQak;zfojzsD>?Pb!lpAZm!K2mEF*i#wanzFX*;Ut1?x$DGcS9? zk(59!C$tf6D2>0c3JCQrfSv zFIL!lh7o&0$lcL~FB7n{)pa#i3c_cCjQ07))4xP#~ zKa`|(69}1cwXkWzfe)6ze}KP(*SVgG1iI9E8n#A+r8j^-$qPzGewwWaX~PJ2*b;8= zE&e+X|3UYQ#fWpLVil2&kUSRT8M%#5z7%CCY_VV+=YPuEI>qH(dOzkIzebPG{S*I9 z`vXbAEcHP3u0P58?YPP)&$Two((5jekJIn$J09k2BmCo**W(I~@Vl%L5!W~Tr(84X znlmPTd!qNZXs2b6xgb#P~hB%*?V?*ufgU>9` zuJ^hqnY!v+2|NNU$`=?ArS0>H{CX=#sw!-Yk5%enTXX+DUrJch(RqRx%y9B_5aG+HMd(9sUyT z99k;bI3e7|J*+kJljSBuwX)Y3XA5XJIY`QfXj_T2fCP{g21bqN8g)DKL2sVkQETZL z)8Fp?S_|4$=S4G0w#?2#z!P*BAsi40#0i;lagyVI(spMOBd*u)r{6N|7NrFkqy1Ub zuX)v5&bgXT{i4sA`pwn!SitvE&7Sr~eZ)h9ev0PcFrm3kX`A}_G>4~AXinNInumnu zpgd<-_EcGjPcnYJ)BNvkyEAFH<-}-@+v%C(jki~p8Qx#8PEj9RDr-OJNa6j<*N;t(H`rOw9K25xT=j^DcS%?no3~~v`uVb} z3?I%Dw5Q@J##2QztdT!%&e56?W2qU_4;-iO4&?zecZ~8zX6uPUKG1ECg*$H^D4G58 z^IJDv|IW>ASm$Ha3Jc))FR#Eoj))YF9-lQ~#{};P$fc3|?Us`XuRRi&*6(yFcXe@n zzf9m8{amy%M(=zPRvf5<=f*S7ay>BN%tuE5>ILkyxbf``*L5@bWli;)t_}5XKeGCH z^z(T0HN_E6CUCU}CsWom#l>GrEit&I$lrMLAlC!_!81qid>=RbtohYZ7jn9fG&f9B zwor#4YYpJg9#?C{xmD1}7#+Z#_?$Xn!!rzgX{#)x z*DR}+^=%skv!xOzRBCtUiNNZs6zQW*m}5s(W>K@;Vouw3j@Y)%RkS&0jG*`M+3K*& zuLB<1dletBc4Nd}h`bcCPUhOT<`ZLkHT#`***t$B$1Y=C*g`taE>b!ecA0ZD^DTA* zRr!{c4UV`4t=qZo2*REKUiW_TJaGLe2yM-sFGxg@26cW}Goc*yqlMNLME{SNC9gB* zynfF!NZHoKQ)^oH@b(<&IMsScT0iags&$`k*DAy5nqey=eYAcbTVLmBeXQ|`_HteV zt%-%l*~oLN=tYWAeH)t8z6K;rStyklHGVMt8_&Wch*(!YyjNV6X0jz|e_|g0vZ}YY z&3?(Y-!bH^-oAc%or+ySw4-bo*2b?CvW($OKm2rAzv!p-5P0)ES1z`0SZY06=39g9 zg6(J{zvXYK?1#o5o5N9PN3Grd+q2n&_PDCoV>!#e!_TvDbGBGzSe0~aTxi3_Q@YuY z@)>5u;2Oudp0n4-=d|4CnlylSlAvrl>|ZrJc?$WCZwPJwA?9UNtJ_@fRe#r{{ui`( zPEz-o7!Qi=_n{>54inmnPTxLF>Bv`ZAlzBiVPNM&#E_OXCEKre?r?q@?NML+40mzf zWB)DIkF&fR=ai$O*MBE=mW8oACQqhB#bMnm?9Rp9J^G5eKFN0?^P{6C8%xPpvK7_L zxZzGS14<}!xwQO;iLyhM{@p~joI-?hVN)+Hz?M*NeVGqnrE=YAM!LA5pv`;!z+v9= z>W0<2z2&WKpjsQK)~2Ef{8!LN0pF@vG1y&zDCiJK%3Ce^4~d=mM@_aW?mDyyuyQA>3#1foqU0pq%z^G!uw<`mrZ-t8fnED@iw> z5x;dqhk9a5@MHt3M4E)sn?~zK6E9Yk7?liZ@e=nH+QPiq8dipQ${Z9p)jxL& zabTHU`pMTeH)a7YU}Kfb)owJsE5;tGp0Q2oMVnO?N+(LDUXRlH{H9$G{pXyN+&>}C zY~biEb*JFtA-!cB#zR(FWp2*V*R#~##*^`(6waf{Is7PgM?Rf8*|j(9H}Hg$7T^+K zD|C29-7Za@IL?uBtiUx+KH%g_E1bvyH817jE@?UgdLWc}V0zJn(SzQ1 z75kIju=McdsivRIwC$#>vsiTtkz|x=(6`q+1c2!C(n^XFcPW2;kavm^*UWI zf_hE5-ZEWpz0{l2t{}%yVy7+<*CmotV&0bbs?S_RJ$a-B{pYx19mo9=St<63JK=&a zMRLG?-WCM^S!HhK2SM%&Vm|r==?)^~o1zRcpm!eU7k_n8e5fj0S0phHH$*2u9?s;(n0eMbUJf-y)YO&6!HL zCQX4Q2Y)U1wrncoSP?Qqqv;i*51Xso{0pf`WY1sIqVFDvJg48H%}<#YEDMQ8Y+4gf z+q}`6MOdz8p3q%thtRiAp`)HR;7K{}0U7HNsld2k;hBVMz&+k!tunh%s(%uC3NS&1 z;-4n_6L!ILeH&PaT<6OS4XQ6q*)NOrm+|_`vg{XcSk)=MIZ|N7)@R=@#(TDde31nl zN6x{wTi&Yv*&+-4qi#cbNUX9D^arv;VWxnZ$mI1YV|@aBopgtzua@MNqiv%58q4D6 ztlsh3CQ-(GM^7s)EY4+jpol&kDk)^NfN}G5@U`j?dRfMiYJ73>`;VSVYfw z^i#Q1%`ozNZ@P-_l?|M`w+CB}Ji*M!T0__Q-;-<*>1?cLHlg2 zZZ!H$4vlWFJM8)zRaYr z9`Hp@s@NzqKYZFRZ(-~LHL}9x_@>v~pM;kIZE)Z3*viO(oh)I#ICsd6cZZ|TGGdj= zlWoi7_Z+39zbuQMpw?V@`p0*q?UslS;YBmwu2MM3ZgS@ADz^3a;QD#(IoYdK@8@P| z=8rUbmTtTC*^l^l?lstJg0GLy&DU5Me{vUh!L&TVsz~Wiy_43{!aZ|cA$HOZO4KM~ zFGx3)HJ31VTtl8ZGIK-I(BnO`RusEG9qO=g~Bb>`S}8dtxyzCH0` z7yky%eA5N*=ilPUh@-G?p4=0AvkTL=cd-U%#bvHwK2C0PuKt~M&=2sV>^N5r*`i|j zcR4Z;-2!Fvygg|*}KA)j*uU3^+b`o;OmgB4q)TV@YXT< zG(macz8PlzFx&QQ$BxylwhidLDvxrzL!*6B@-Pzvqxh_67A2V|Tr?pbteEOA@Bd zfbkTn3BlSJ!-%*$mN=BCXh-$`(ElEmN68`a@@MP6)_;b1ldb<3>N~DCfPF+L(54@) z!8WZNWSKaA)&Em}NT0RMkXL^TB^bTJ7hN`*-~9- zH;pklNdcNOvy{>3mEQ9tZ+fP!wyl;iuHxIoulS}!ne(A2q6rb*hxX&uA?&j;K496Y z!oH}5ls($687mmv0Tw6v`m=2{!RSLfvm+@;q@JnMJxZOCwqf?ectf6gaD~^ra&e@( z13L+DhJY^^ew3xbsI@{~sZtR(IN3vpHA>oT&1K*Dwzdl@Vt=1Twj9Vy(G{L$`IaEodt#7Pv0+1lfk&3iow3HYT_VBd`yE!qEymhJ*t>HO5*uRgBx?G+yOY zVFk~*{YU&7*%B7rj&t1u|4`C9Bwm3@-{G@*2ZF6lrnLSzE?Nb)p%yT}OeD$enrlFR^rdw}_ILjyu511nQl zsRJCzMYOz_x4Nz`!pUxnZR< z_-D!AdsE=bw3Elm>^dZ+-g1a=0a8McRh*epc&FoCo|G9tzi1(_5)0vD`-WS3z{^~X zbK_IIN;r+D)`EN=L_UYgZ=*ZcMt4CQ&j&0HdizVm`{2>eqeHYcfUHHpY*UOkTw;U+ z5-s}xzi{-E;(S6>zU<5JG)wnY?!dIgcY=RJK^M#KV;mphYNTE$^%gdQ%RGRVi4h~& z;=uWs_6^Jn>vzwlrH8vIScVgcAz+N}Gi|fcUe;)F(#tu_)|)vVehZSAe92gd2Hp%i z_>H?oGR}uW1CKwBdkGV<#~ic`YQrjV!DXZ1?9qXA$-zq_A0qUj0QAe>YK+~q#ijXq;fL3tVFg<(p zPf>S)C4~0?LB@}12@$NYOnCHtZ1t%@Z6|>;#Vx3qH`7;a)Lkj`k-<3RJ;n$7=Q$~? zcf_iZn^cTT4l?tXJ7oFE!XF^Ip1lrj1_il;&W9k=sYz5vhjjfUAs>jrgNT`6$Z3mp;q7McC>P7$TanW;N{M*D9AOuq zi@OEZs5=sSSZ!I$OId2s>W?hhy5t+}9C7Ob2XhU+gIyV8a`-L|8s~26Yk?B*u>?yT z))E_}#7b!cUby%BZ6F2#Ev$Qo?^S^waHDdd2WKPy#c|r9iz` z+K6VE^Np>X$!OqQt~TGBjl8>Mm}xIvc?)hv^EJYtPO9HWi-wV}Vs{#&cHi_Ne_t7t zvc&bh;bpSx)0P%OJLDX=xM7xFF!C>GGjq;v<~v_&E^H-!I8kC`b=FE2*8^t}N$7en zLf;`zXSBw$Fm5o0=0ra5VvPTD=MlmQK}v*0_l(7FT-+eX-Bwoe#GPsRc$k_VC3+8HUYf2x_iFol(jMmYy07$AFCP1= z5jgWXgXU@C9K73}ra!u+iP@QOZ{9gvw>a+@y9Txsg=6irXiG3k4#{@gYJwQGEAsan z=l0w<>mJ0(uE03gZs#~7l^7>x&!>&4cEwkVo|74SbbI~wHx{)2ecL{06B2g!DQZrj zBdpJmH?X|WE9GNWEqd>SSHI`oYk^m28N}(zJe<}&^84eIy#r!!d5wYq#9UFZn2B8q z@25j!^6?d%57x~|i{g}#ZK=)Ejnqq|8Yk(KI~(CYy8m~*_%pFm2R_M*#~oVcJTt%a zGx!_tq)+mt<+umJ*zBoe5xx*8diSy|2`i1vyMqT>Mqiiztq}h*6>_kOiBTWowegV< zFW)fs+%cLv$Z1&`S!Gh14INy$Z_?8~-^}fIM?0N)aR?e+bV&IF;4}Wcit>_j$omef z^;2JZo^i-IZb*%5c)iWhTi+D^AS`0#qB&;MGj9LkO;-yS#`CTnfH8YK%sm-3<(cC1 zA$%5q})6Df1=qg(;gyi4`|)! zV3&Ccc`fK8n!S>d1mW0uEia(Qp(SajDvI?sX}j!NL__B9x~B=x@$iF?%fw?a=5ATo zjutVY(3pIw<-g~Q^(;Xfg`Ul?<36)07d;F^wlFgwxxn-USG%>F1Xnwu*zg?xS4l=# z#14=xlxL8svcjWsrc|U(qu)PUXcGx*ZmY_6*V5(ytrGiM>;#4#ncwA-uh80rrs{dY zQ6eoP7mFT*b}82}v!WH%e~VrzH?wzs{a5-+25MoQLob9D^x;c)qxn0aye^E-MSW;P z<|!mIiFmQq;nJCLevRCdDlw%pEuF;H$a8>}r_=VgQ+kDE4ZZ65zelN|5?1s~EXujO z5m>Z1RR0V2@N5CL4rqp;9`1?BJ;?(voA+U~m^Z(!*ZYrpF3)1Ha4x|;U(@yEJ#yr(tg8ml%L?awLkGcnb%9eS_qJP} zgPur#6tcGim15t%^$=HOUkK4k0s^QB1-aYcdg#7*meWY0$}ajz}2;A z^@qtVJ;d*p`Pi9iwf0fu0cvFRv{Tz$#Qj0TMCMn_GPtM2S0yvNhk>KfIOaB-^5@JZ zz03_w;A=_G*%S+7re!xD&$o4WW$?Lw0sL$P^*Pxz-YcI`WD9m z3#mlk7z~K*Kk9YQddsU3<;a9n7H0rg~;u%)@I4J*e6HTRX0z&9mNw4?({!^pvG+4%;BaBDl-6yT( z`>wfY+1w9`Ggjq%hnx6#PtY06NHzQn-yj0sp>{F-e&CmD{AIi)W~8OMwj%q5>JB+! z%#~;JT}U+XM?%ySK`l{Z8Pt1#(Zdw=4x`tS6d~O9^{MY6&lTS zXktN*9ptZQUw0&=A?PbUceSM=kQ40fzf-rNx89E;voU8DB0}?r=|H}&rI=ZWNU|j< zZ7)9`z@Ne{9-JBNQ=)Gwr!Rfi(KnTAm;3UnuszXkD~IndUP4Fw$BMqm*GQ4K_DtR+ zU}wt5Gc0`NDg&j=Tv|K9hfv;$JtE#vT03nVK;ekAPD`#1PXguBvfqdrHa(||z1m$%5K6WpQ3GNp=4u<37!Nz5 zLOO!Ch1<2ToH{A42~JmzBk^Kw&#U$2HNDhPTVTlb+R@yIx>jG zOir2)F(*x9>^98c*ey>>?ERKz)@%Mo|2gqz5+#k_{Uq{9A6gc150^Awmndm|>utQp zUCrkGeeynBs_!@E-bb1amlQvjF*XEy;~K9|&BOAzAa2NiI0~x+4!6cZEqf=9WqsYX zSj)_u|H;*V%5hnk)&}yN6;dW389U}=qDV8tyNDrbvv5v_SIY&*Sl9)x5YCyoW=B7K3iTjE!|x&GADqBeY@Ht0=by#q zMJ1}q+97hdZ7!p-*q+Khm6_a$E?DHx@l?AvuI|X4{zEPLuK|@n>Dp+oDC~W-@qZ0b zHqlIL=St|WiOuAA=eHX^iRc%jP4_p4UsXE^ z5V#rU5DX6kPZ`SkkheGN?=8mi;Q;5xx)2%yH5zOCSSvR&fvX{EBCcH4#y%=J_@nUN zc;x-?&@f}w2SVIiVa^ioiCn^HhbZY7`=j);jFg5Y9r+72WS6GQWNvW@s~(%vl5R<4zGCaWLb$xtVH%kI+=}AyKGr&aOG6q80_cL zL-;jV+)JUBcUhw%x0BEwIdT^or1Asx=KJgLmY+CPN%XqAZA)UiYFuOZpR6AMdcxh* z13(|pBOK@rCSLISfGxMimp>ES?|pfUEVGQpLQQzec)~mhUCSL3DcgPqd zGti}FKKB98gO2P^xb6Zy!U~cc)0;e0f+)S;YIw`t|XA>D_#f`*zmqT1&r%^SYgJtUIOAg^P;NM{dtRUJ@lQ5h*(F zf*{S@vVySnt_pWEONWhH%0}Bx@M5Yc(yEC+RDOzG_Wh^G#phlD?Xj zk{(>SKM}Xy)MBPlm)0$p^WYL|299IX$!pDSx2?|fTgQ@%AOVx!Q#Ukn_u)Np1K~xa zRaT)zc1E_@Gn{=FI9GnBdeLiRKi-Q>L(^!!%-X;fVFAim|JbXD~1QJtE!%}R2Z9M)2 zti|?M?9}PNuhej)U0c(d^FJ6_AN(D@G}4he1LGY46&#H~M+6j^ChRrc(+d035+Uy3 z_j_w1n+~7x#hS>L!)LrN7I^^mST;sGzO;bYTlsse?w7!wWER6{HpNOKTWU+u;y}x+ z?pYPzo>Br{j>ha?;}T_VD@SXQ$B@B!ujy z4P>o^>~vd<_)ZQ$3w}>qOeNwK56J#35&H<`pgwng1nW5SIPlk;NL_^}ltF#&jH;}4 z2fAy;hBE++VOP!H$HV5$`V>xR$yh&t{Hwg_D1r8JZKI!D+h{M>Hu@1cp4V2cb-!)G z?|@n`7u?Se7+b`#N$V=eSHj7mU5n3@NE*)5!UHxQN36-&C!wu#{4w&wl5Lkoa1NrJ z8rDEzYy)JojYCIoU8F7Mg43MHh|ukQJ04+-T5oab)zlU7zI`F)n61&?lpJ(WPwh=7 zFUlX;DvTmZ2+er`)`%b8SVCzP%`!(lDF>rIws0ArXwhE+XO_(sqw#~2^I2`Y;F*7#lRbhLuH9;1I#qkV??5>CnbWoLcsg~pGF3a{O@-fnQJ0mFU%cS0ctj z$QMQ)1h0nTh)jm=2p-3F;75?Xs_Pvh-=q!Mk^MXN z%B_fi=LmMJUY9%njNf8Efal&ssU^M0T`54F%>Hz?bKPX_vZ!6aPa>Gl9)Z<7GG6z? zIA!2PS~#{O$IdZ&!cV|&a_td2WwKYNG{DK9Z5W>$7~i*V9T|_n7FPk&Ywcsi05T58WHyj_&&!u#UY<;J}+FlcaeiPk@F9i2@K?y_`b0uJCU{UFEPOS z!Y%o&Yc6ei%;v5cetD8XbIyTM;Q@wDZgNZIXSj+~5DSQWz>KnFY}6A}DMr}is0 z{-{-h9ciEs=@O+Gjnd-sa??S6% z?lcXzFNXif#E|FXfwLg{JVa6ypM|WMg;?P%y#L+KLW|4-C7)ojvljDwWVxjx*Z58_ zTeFEv`bKnoMds(3D@%TfOk|&G8f#8=H5u*$8`bnDBa=Ibxe=`=MvW%soJNHkke2Oi z`0@?2L9XKS5TQYGi~4`;FUfwZIWaLhb3Oa)p6hf@F_f*l=69f5on@ih4okPN{jhD$ zzFHl_z89b&=rx#_dw-w2w_bxOx%ZJq>ovI2&v4Y3B2N%Lqq(7Cxo?q0sSDI7 z_vJqG#b#2PpZgMtYaR7Yd@J|zm=81h$LgQC$N`VY zWoA;iiTg6dnOGi|1&1!%2Sa~Qhw_^Up5+CdNl;w|OqL1|k zr54=8%5h*H#GW{p#oF)wgWC7?Uq3p)QjP-+AsgZCa(r4fg}p~sjf?`k=I7UTHI#54 zLA}xL{Au4tw)GE4=04fAs8kiNM(tO!5R~lQ@Om~{&4Z9%dKlPs-t>r0yV9Ugu z%>+b0cXt2JNkyvZ{q6NXx}LX>SHW)@LmIs(0n!Fnzt7 zHk+0{jZ;H}F-&dF&{4{tr$lg``u%y*%zDs$IZ8qg%It$w;k5s#ClIMqvE==jP zW3dAbmg^E0*S?3ESeo2??+LDJIp2}ffpK25hEU!GjvACV?;76R>?7h)sJC}!{~+hQ z%d|@^Cq-(<_#Dti>C%e%;nU0`=zDgHQ384Nl;1~JFrMsyb_GlpmEd^q^YU7M1|Y*N zUlp7w1b-5VY-cy<(+>3Qb*udjf63Put@dNeg7iSEcySqik}_Ooo%=b)1qZQ7>j~dd zSD>yf*@R$A;XCXRSbjD&^`L$#8aJ#dEYG$4N$lciW9s?UmW0ix_qwblBMZ;#|8urP zS?JH>SUqFrq~}7-c(k6U_xL?GwM$)4IWy&Iui>18=WeKJsg1zY$TS0Gg+^}?Kckh` zNJ^{s24@UC@#gPN{X24|3Qq(5X)=2Gt4D1@?jOO@^lrSc%%=V6Ef{;IZSE?1C-Aqe zhI>Rl;iNxgnmgo(|1^Zt{?VNOlxG7ba7U17lk;8RTGT$g`nOZEUkFEEk;sZ?NlzKt zYhmN@&!P#hLsUlCXd}psvKdq!#azJpjFv*s^{ie}_lEVe#SxpPvb`H$8TCF1w7Uxy z*mxCiMlEK=bg@u2ufpEC5q%>YpM#tpJ65j{ZYJ3zk&R4j)EML4wd}R6X4-ci>l!t$1hbJkn3n>rJLk`}w3TXDEOY5I$+{!OZWk8+X{> zY3`^i{PN;ELO3Q|&!&)XFeq1*It<>%fCxFNMuF(=m>qu*%R!ut3DN7tA+jC~Xk+I! zEnW9qx^jA}p*6;$O%&|`o{KBXbsftcck&yw(YIUfaA4hm@2RIOnT4Kvo>K*TX=P7d zz6r~N)LXMQ_7bhm;nkmRTNyS0wKZ zzGY!Sjh@P4J#E>tm}Q$2Uld!=-Oo8P(&^u^chiyv@A_i!{JVvNcW8ejw^Gg`}0rd?06YsH!eM4*5v<)nZfa1rXfuxP!xC2^;4N779jZubFh z;FEX2nQaZ__6whE?65PycHUjBNsoQFgSdom^D}KV_wKXLcT*xDwsK0jeWRA`(yJET zWBVnf3m=J0?f@jN_atRxZUl8ZZM}EXYB^dRIik7;c8XmMG_0ISTF1$n8BI%fcBcDo zZjV%Uz>*c>X{5i%#i>uk9hnLXF&4{yNilZCru6s&ar!2)OIS|X%9@~yU#GZ3&X&hW z|FS}4jkd+&RU-2=0z%%2WE3d!*X>C7cnct~K?r7P|B-6qN#BXyYa%OFJ_kuSC_YoH zSKzdy2RjTOle;(l*D<-9avyMygj0D#>%R0cZ@_Z;nG?o6b8)id4E77DP_t5aXGK#d z?nIvS1Jamzevwk*2Qw~?&Mf7AH^_}`-JSc$CsxJkkCRUv_%X3ysWiwZsEv1qa9-@3 z`cllK;T6+XJF(7CdAQz=*)JPZ9&?Y#VJZEYGGrIF7mwR(Ik2=-V;p z=N>aZ-@hDG^83NO_c;UeuW~T=rq00FJBne;LTG0#2wUN-`Qu^fl_%^R>zE^pz|n=e z)_ymK@3p@_{7+i=k%1DqvRcQ2nsYoF6w?=3C~iT<)WU2GBXwi7e5x$r>cY%%=6_;k z8Eu>#x7br~R*F$A6^j#p2~G!{I+{%%T((nT)qX8Uuq!HOVYT_;U?p7zP8S7l370T` z1SpI=6&c&&=v!kEuvT}0ui}eD1n1uFetN8EdwN~i2JZF3|I%g|dlJhT)`D$&_Y>TK zjC|j-yYRNJV*IJK_jv6WaL47TEV8McN|hX`y%%z#4q8M3pTZiTzQ&Ts&J0NKTQxbn zp)_zk#=@PFY_`i^CQPhx_&l*|O1zWnQH$eywsIe&jZ*~s`G`*fPug=ylKdV%%FpnN=#ls<+KlWd zr~#65^DCYfrN-$Kalj{NpNs{QU5*1u71^ZE(7EIt*5!HZ0d>Ed`pn23K#ne<`>{T# zACk0X{YjiBidQ_hqTjPQP|G(JH~EDqXTfhI9C5+ ziu0VcV>@=Xw&iBmnbGb!D>B(1t%I4Q?9%A;wK#b{>beI0M(=0d8HN4Kz&&51^)qSf zAKK5c(!zfBz!p4OKXohKbw4lV;ceT3e=q1~+noOg+)u6WLMQPm`h*er{m|HbIK^mg z+k)IFH_NMrkx|Fu-r5FoD;xU0@Z+ZN73n=UX3g_or}wNugdKO=oEdOBtSh6(d8!LH zb~fofXuNqnk@!J;ir%wuM-A4m(7bYeYEXKEXGK%^f28+Z*w2#c-@phw>;{KZr~Q5} zd`o+qQod`k+~JD0n^#xECqes@mP`B}fDijsLWSL|DHndEuv}~!`s*`o&%pT7`W(aa znm5e*n)IHdC&l)$$wD63zahs&{#)p#CD5kK7`5bzSpM(3XXXFyj={!Jl{A>{yehqC z*RS%ifSuZJb65aGyI%DzHGYi7<1ykoywu{FT&DPmT$F&NTCtpWdkUa{K0QRu-_62e zCc6XdT@Eyt&lq2RRl4LrV`Op%-nw3E@5$Qj?QE$f#@}80_&;{l_?r~{4Et;8$7EiS zcn0?CU|xAgh4f6zsn@bEC~c+|IVr{&Kx;VFLE0bIdonWh3n2BXT%Ie&c@&)Eg0~f= zBnMP7`zH0^4C0Y=^`I_w4B}obn~TG*Pvo9!CPv}Hrg&%CjI!_c-S&s4xA~zji zL~VhZQHE!vCW4<6daZA@fQm#6?*VVMn|b)~+l+p6n1@;62zlCT9B|--nX#V)`QSWpOEJ5VPbv&oP~cud#eOzv_uY&>WnXJUD)1@Ln+j} znDY{)20FldV>mBzhat+Z3x9GoDVR?>k5P`yj1eP~F}mKf7+KO|KWYgNc@Ijh?i#|R zGk1KVr38Jett#buKjW{q8cRbhHMdP{+1FNc{4m}l>v?0Ef7w$)Hvbd0++$|&Z zd2?&5cQBQa^DU#qR!WqTu3UR#iI<7BVfP*fJbZF;*@#{E+#=N-A{+der=q-occ&PB zpz{)yJVJ~QXUw_1R}+084=BA8+LxaE%*0x1aMl7RMw`no!-)gx$hKdeOfChVhg|}6 z!gU=gcI$9;NA3ix+~e{Gz_QL@U~E_};4T8xqCOUm!Y^N01a_WK2tr)Q8)QD@3<@Gf z{QQ`Gw=DtHWue(Zhr?gd&8hL~?<*%#H;>&%-8`AqU*QL+o7-Pg)=)Q3W62{cCkqy|v5 zj5UfIgy=mEnfvSfu~tf-%kLlA=Ll+0x`m88UVAxZW!3?Y=c!q;|OxKg=%C$9zs+uEj!#)f9kOdpz_?$MyB{@FDL{nG;EQWih3 zdF1dD`&;1W#|A%N1b#XdqI>i4^UFerTJ!Pq*IQiTbGyaYm5c}Do4w{u!zbx&y=L+K zVhezV)RhnSU0*D_p4LfS1twz6ayJ8ekfU-XI#`9lx$dk5{692fxjwz;jU76cw}e{F zez0%NONC>hcIHAm)44wOm)Pat{15a3W4XYbzht3ht~}(9N7%+e9 z{4(a3yA8CWFeT~$-*&7NL`UnJ&Uv5*oUx%iO>e7wA8!a?4gQ)j@gvB`jnlx3uW8!f zly0y58~KfV{H*KTpQw-D-&vn-pL3~wpWe17Ov=!7hs4@rD}4S?%6M4ZlTxDe(41N;{FSbcZ9EB^_C>LoLB$P+-d2v z#Lhr>oIpt}U-{;c=xunz9e^1V^e^F-Xg}6HOHPa8N$%6b-*^@0T>PAwHh75JYWT*f zvNtAkG757CCBr}R$J$o&X1D_M z{i(%bp*nc&F}BUOsD1F-Cv7{!d$GGS=RHTxagT2eMa+W6-LotdqeNxoy<{c8=UC|L-N+|G-yGk1W) zn-v{vQyTMt<5|E8{#yJ7_v?O4v8~x%)3mhlgyA4xNpIWrtEug*=~QtCH{4_M;t9L@Y8HVXIs6cpp@8> z6nHrBJVDnw-Uz;)iAye{f3N$V&(XPVi#Ilb+|A3s|A;Vs!O z$zH3e^N#evHLD;42VfDZcGd2+IJ|)6o0~cpI8{+EJ#X!bEeUwV1!K9kZcT5yai8DH zt}Tz&K8p-I+j=;U&56bh*#9PCL&PMtFe7sY>NOhAYnjbn#e>ZK5Jv7`bjUQY*W8ur zWn#8IYgfS1&Q^Or&_77N09*`^MtWA|>J1@J6)jRSs$K9E!a4-{OrCatO=RimiBytq zLdeF>{|RTH{2G=Y{oXaeKr06@Yb}r#yRjNWL;sTAHth$vQ@*{_`U<`w_?vT}5jh*p zT;xiB6Zm@wH;CgdzmTy=0^?d^-a~65)x=0h)|1BMZ^jC8v+4FVebBmaA37^Z|Z4M%<6^jJOLPrj_PYoQB&8|z^MZ`3ZPi4zwa z_VIsO>f|q|xI3oYo74?nDHNS9Nt5S+23Sf@fZ?yo4y+gWn}>XQfdKlmfIjSt(#`4naOZSg7G~MipjAPg%`~$pu&Y@Opj& zZc3LJtFpxR;mt(6St54ki`rMpUk7-GH)2A6h;^`*XDu;&we#OW4=azwr~V?H7oX_qD8grW548q%3IV%A`r;suEeC=t|BaXUjXtbhO%+Xz8`6CTy8RWg>}1eJYU3fwEp6ZCm)yTc zO3uiSfynuz#D^IbpXFx3MJ8tHBQm)|);(fZLc}0^H0mYH@;nLW8Y6?2j*(_z6Vuc1 zjA<@yMlL+wqUd^?WA$gy(;Cgb^gF8|IiLZ)p`KQphDl4bPOucIiI72(VLhO|396IW zew0RFJ&HYQB9DkS*hXTk!!_hb!W4s;kp2D;v5%)j-+C5O>6Q(Vi^;vP$`8*cX5?f< zy-FL%{go-uIw0);`K0FnKQ1uknnqT6d9do@%v*6jZic!tl9M67_(bPQI z$Ce_^lzrGEFn&x{E8Z~ zd27&=!wPj^V|sWT;SG6r)Yuk^!`Qlf+Tu^bKD2c`utrS}Bd_aps=$N$JnX5cyV|{C z;c8Gh2kMZ!K8f3vVc;s8z3x+-1KOcxTy{oea)-#5btlq&Yj#C0<}YgPn8P!a$~cGG z3vo3yfxlorPyNIRPr((24xA zW$A<7T{gbJU>-h^#;Ye>y^hwZ8SVc=dvi^14ro(p-p^Tq)nlkJ6YHvJnqRRv+@KgN zTm7Ws3F~zwGSSGm7-R zdt~2`3(SO81#7}VkM!n|_crCm0daI%XDI?23VeL?XfFq z<(#p?0k+xSk8OYa%eg4MTJnPRvelX137$ub!82oI zUk8w_R_y_V*`I-tCF@{a8VS`c?+jHy?mE!W;A1YVH>Xy zpcyZ+g|Z53LT$k&vN-9fO=aWM7Dm#TU-PGT1%9P&Z(#(3cjc85&#*?~8SJl(63<|M zZQLgD3>al7`vkaBRQ5}vAuD|zyJS&hGBq9Qd6w34CwK#QZ7~{QLahGI)cf)O=lVZ- z7N0N1|5x{av^-Y7I8}0HtUjK4-!~qB#a;CDN z?19haen+2uTLsEu$H(`&i(#GlqqPd@kF4qmrz!-`#2d}$BIcC+x6Q4;GyMK^-?9~U zGzyvN_h#8U$SA0V>)YI3Ism=@m6|`x#Y*g68oY*CAkpv5cc9Nqy&HZn`%;h?zzuX4h~8Fogq+QM$gH9fh%cf zT|)Kp?L$R#XH?*H#xl9?O5Fa zY{MeYqR9BWh8ihmNc4dbEq*v~ex|f!v@_MR(}5gA``On%5~@8K^0(*vPpQ?+Sn*znV*|+dF?@mG%w!nFca(CKS_v>H_`LPX{ z3EaTLxf(t8*g|%>#*1-RAa)ZIdFGkOGs~OL4RY%F=Lb1;;)1RojVuF=K?~cpDG1r< z(jWFH4ey&;2pBb{nFqZ)Kcc)P>eY9J zOODr04RDFz>MfiXj?vPDgJ;Uzq<7J~qK+w3g4D6`qe1GJ^6`A?IJ$T&D2&Anw+xae z8K3Lz*qv|N^?gG4RNYGQkZeVG#<(YX;#IEjHLQl;Ssvr-0)->Y*?eF=vB!vh?Fflh6!{CF^?X1>+sSnf_%AOBe8%^VT zr(VfbX}5lNy-xyrBcwQ+Vfffs_nu(vgW&H&k;?bt29pr>y7A4_$>b6noa3j7;tj-I1pYZWFnV7Bae?V^;%e`c)<0KQKGg2%A)Nh>-@&+zu?t zn~=Uyoe{aQ#Va?|3JS${(&?ahOV2))!JRp0hu9){+F*<5>&_J1`;Jux4HCq3!e?|*Gy)1QkTH5 zcolWMbi?hS%LjWo3bZA$8JuUii!<{i+r+PUl`Ca;K~~Ve}nMR+gy4-&Rx9fw}2cyxjPk$@fhkD&E*Z{ zLeG05)uiX7m)qe3C&_FVDJ?5=fRQI0SSNW}hZ;n~?SkhDyk)&E{EBAvhU4R5tF7Rs z+%lA1aV>3vusSB_vG-b}=GdH8G@$(3k)i+Z&hcrvO%+y#-7g@uauqYz%C#7i|)K%)DQF%DyK&u+ZZq!-V#e zh!`0yc8n4U8U1mtCrSyfdJeJlR=!4JeWccpM@l8bNUu2iKhehE=LyN6=IR6w!i^N42!FP8$Kr<{t1f*waee8odmfXRRLA7cmmSjofVPM09-e&wr-u#_Ib?FP~3(6l=mKj&a~2;5};VezjPe+n_m z=>?UaWn6OPqpxb2rH!-xe(_P<0*7){(G0#%kng5FTYpDFPZphb{o?DtdCjk`xo*}o zvp)H``#<+pp<5ew%vmFzW!`@ezV1r~8@cSiVS8!=$KUlh^^|w>0I)1QcGuWUa#kAq zo^P}O8wjbAPu(?kO*&|~MPv_YNquZC-dG=Xa6Mw~u(pPYGswe|@mjAUT=^G_zqTuA zWQ`uIl_e*%_N0FOyYRPu4IfHfJ#GNfV(`H~1c<@qF%p3RegOx+eW+)eJSdin$J*1| zZpLkdHsgu?uAH1-&)(vHwIfI$yd8I#C~p1LVZZucU{fFPM-%)`T7c%;4`{)eW5Sui z+A)vOhqv|>TSvFcF|=dD<1M@fX_oWNoH_{VzEXHhG#u4yeAQd++5F^&5JurP)73V z;iMqyltV*@@49dL8ibNw^EthHR#*X%UH<)nngv#pE6OXPXIW(|)6u zK-(PtHQOXrJb6M(YVWpWTg;ZM`xQ$fA{6vZE4o6+Y#_Gx37d{c6ta#eyg0q$l2vTE z@j0go_Pjlp?BXvk7uQQrcv{ab@IUjydX4hDE)P2}DoLQfpjD>V}{J z`E?2L>%R-`MT69ZuNl(HUdghA`-E~lZ6p+*wooAcVBv2gm4pM4i-05K%@nB!I86M9 z)W&WyACBX{le|b9!%@|RqXIAHI8ZLw%cS4r_mUf}P=7MZUbwq0>}9N3pe{n44f74m z@{S)wF&v;y#kp^8>iiDzoW88CQSIQg%pgXVl)gBzM9U<;t7UfQ;@&rdm!ciO11;qh zjU30?G;lT^z#d;(4=&(%3+qY z{poVH&za(C?UpvRoLBVlkzc@nb$>Uqj;v1IWwA|^G<2~YRD&4e6jxCFPs3%{dk;|mb8)*&NY*UpZ8YkYUX|{nE)-*7kPfz9Y z8$2O*yN_0%_+n`}xsFlbB%DZ~@Ez%fX*;e^UWm5j)RgyxDUAqujv420u9|N5%A@sg zTk|8emk8ju!DU-${@O4qKmxlnywnYX@j&854?=-+!3P-t~HhO zTxYn;k(kPM*KO|QUt;FSbfv4L@N>vGEdeeeOv)F$=PVc<3kYYx|sYpQJVkNaC$azbfu~nGA70uy!nVo{uwmP|` zLa_d&0<0s}i1UJz1Uak|rUI-Byi%Y1fG|shNS0%qD41^P3CjB*#K;)`jM^$4N;%q- zC#%#TcRBD(JdY>l*F0xmu;%Vp*)wb1f_;m%{se1)i}HjW;1@2M^|`3sH-Wk^+pfqn zN@K_toX4{^-ANlsXAXK9sI9+HBLnoLi3_V4dtUBaSyCcP&<4wk6iTIl3s-(~XJsJ_ z(wm=?Sfm{y3lgQ^_g?)s*&9~rEUp%4BzTrF;B<+V1l={%?H@7T2<$=nikI@aVGuXE zMBMbhryOHrkE*A2hV4_)bgP>&fi})iYae z`teUE37=%ogQNFodV5*_E)4Acf}>FS!+hf8aWad{X@Z}z^z2W!=jhM-vPz~|qid>! z@Ay!$jLi1@3;V^s&0z+8Jyj~&YB^~4*f8eK%`&RW&6SCSX<2Zy-L(#CniChf92phx z8uP23+Tq?e-GEGb*zdjSiH{k7?cDB8bGHNk5$aIqZf*)kQR7%omK4z3sktjwb~Z8c z4cOjIJ_1_+_W#fMYbA)y9L0+Lm!&ED5G{)x66b#5ai_{fOT)+bt-Frz<#&(v(DOLQ z3=Ts5319T>q?2*1QQ~9LFzSs$VUfvd!(<6auxujscP+=*;u z{m9X{))UB8Q>$l|v1)439#%~pP*T1|umaeFPyNA`=t)Xu$my(vZPPmgz@fV}ngjST zqdiT_DYWMUq%*M<$xU6r~A)sk*l)~s#a)M47XK~I;H^Nv<8 zye8dn_6n`nXkqZ{-7s3c*gEught|7D>KSf7;B))Y>UMUd8}@%k>%PgDBaHSbmruGJ5g%0S|WS_-~P1&-mskz5;eLLzju~rxzT3V~LS~2VS!{R2WB=k8MTy6WaPi zk9@ctdqdeRu@9B_u!M+gscR!lZ82KAai97ImQe0xv#ZBwU5s&^31i1*#?xf zr1Htlw%`fhXY+Rpq9h~2we4P} z&y-qqt@yn>_q%U5eK1+TSu!%>G>CIbG#vqO-#7jB;I4V5vAcu9zXN&Nfm_O#fG>`6 z##Z{n7%<12ahW6RVrm@V4_WQXXiYHo+G`Cz+?HN&W9N}t$v#GX1NK_ptWjLPQSOV) z%)|^+Bfhu&IPK-_yHb(K#1HZoz?R%7bM0_7bn=}8i!@T>_X;==6mv+#iKO?X| zh(@4&9C(tes2Eqm=%{PH#Ss&x{M|&IV1n;+y9q{^jxx772!11!ln22%D}oRNaiaL$ zJ*0mp{mzGT>a7w|gO!RcI1%s;#wNT%L{CMue!pAjgA6yuBR9Wjy zzE-JO)7UDl&SE#rK2<}`Mh{&Q&!#VE4^QlKsz7U4yX@QNN%?kD(H>JQL5;F?Uz6*V1*bzTw=EJ_1F*63--Sb zUlB@C;<}Ir_1_k|iRR4(j%nMqUvbNek%C>I0=(6cN>qldLUW67*FLdgLi#~N7HtQ6 zq#Fc=SiDO2NU%|(Wonq+wN|rsHg$@Q)grCGC=l(%ygmlMZCOjitlavS!sOq%3|oZb z{PrWpA6jhQ$N{DISq`A)?b%JSm7BQx(iJ076pS;+tkoTlOjZen{pb{zvMLMPEoz(v z&cc4JH!q1@cmk(w_^$V4YOtsU4KP!3M-X?6Y@FEJyvkSy!#{`Np|?Bh?I}cYfH#L! zN9h|zJY`5}78b_(e^YA~F@v|A{9on(cCC6uzX3}5jklfTKNbs93!>HlYo;}Y(iv(T zjj>y)OVT^{GGYZ7p<=QXul@O!L=)#HgBe`9j&qnVuruL?M+^>AlD@JP)^n`JRb*~DoWmm zXnBzLPwcZR)^h!#W5!C|ya{zN)=B#!20lwkjmSk5Vw_P%tRXD(7~j}mJ(_(HJ!=co z-;Seq>JQPZdN?fPBUhv=9OGl+HGf5T1?++tPtY#t7#ia^OJ&zIvdpt-e5GA9uWnn7 z-W6Z?o;tIv=J)oG`x<+d?Cdfg(D?EfRl}`sl6wV4wAvk$(^A00*8DY7e>ZQBQ2tp6KQTi79^{{exTTJX7_BqaVk|Yp zCPLXD=d5r?*I#Atlbt})*u?0$B@}JIV>DYI=BkQ{T#>U_w5J%^I?}=czd#iv52yh8 zwdAc%dR^?%>z+%!NU-Z|epgn&SMscYx#(RJ>4i2m|1@Gt8Dr|;cR+I;q}&-;&r*XsPZ`(0 zNM5lWlo>UrN!%gT65NdFAQ|;8D-0n@XRrRB#3GL95j?+{3N^+qM}1d)&4c7B;$<7; z`cDpaz0eqYi<&iJ*j(@FPe-ad$a#TT_H&3FL^-kK$iujAKn6o_!Q^0fokWrk2Bg~; zjF0cJ^gM5_UKk`UY?hhJU$Zu02^u^T-Tnr~8mFz9#)xR8u{BdQ+i9Tv}E&i01 zn5NCd6X|)o-foO>=Rzn}E|th!k2`iiJKF(m)xQTLuS$YaT;AF^N?rSYK407*PNxolUf^O6(P1qyg>My`%a6Z?(o3L z5v4c-QjJ{j*z&#l_m<=6AMHHLb&(NECh8+v_zZn7)PVA9*PEOH8LWi(=ILY_>P%*Ran z1%n}aFbaB359Z2OLSEu~_gn*MUk~|J1{`G6h?YiT!E38EJC<4p_s9QJaXs8n6))6KaA*;eXrHRrmQ>=wR#?jT+DR?yBBogiy&R2v`jEZ45f1} z_o~%J3i&t75t7aA>4VFSex?>~*~=ZfCC(CUh<~ESD4s{GC3$D<<=j^u9L}IV=Os_q z&W|;ab>qoAhgv(;)LFzIJ+?PpQS%|6))NEH`-=ivSl9bf%n z;l6tE3t0BKZ|C1CM<@3^x`rd$OrD+vZMYB#wP(4@_rovHD;QuQ?eTL)4&^OgIR z##s?}6q>PGr|3~0V3EktNhgC;lD|6xopLu|&g0~Na{#ewGu&k*Jx0tH#$nkW!A${G z3weoHL0wamZ`lTBc$5}cqYbr_a({PWOma}C-kSJ$B62ZyBj=ui9?ElttV>BPc53g+ zi4X3o2&axI6v)4UOer$k$am!CvT@xVyXjlsSl&X;1DnH@;nIfNCi=fGn*XK1w~~g6 zSpTs7iai}x&@eoC@Q2Ft^piZ*xQx#$-uQ{|X6$76omm!btgF@V3)h%f8)4ld1*hlT z_#D>=?9-2G^Z_#pgtALg0}`)Ey(ubZIA!H5Shfhg&=Vkb<3nK+BMjOIW$VA#2Ynza zK8Fg?qvVY0f;Ic?Tfn7N#ZGH&3hU?R2M10lE+7n#oV^h!V8zVwJmmntwXD*+5UX$7731Ee7*HOX? z8&n?k^!#Wn>e(f2(2qsx*%e0%LOs{skzTNDagci6_)dU&+T><8P|rH}&>zjCogjuu zIlBAHr=7wwJd(s(f-S=i~Q#(8&|7qvgU+0B$^?S~zjPmx> zXtF-tetWOqXMl?rS>HJ>K63V?mkW=l7hJLwKCbp@$Rwxlb*NcXTI$# zxXwAF&*v$Bj#g>=jc{R)Fm*D$Wkp+@5PIzFt9r^!| z8_TEC|NS(T;Jg99PeiI!>o>E7Q%9JizTKxVr^prPJyCqdMWbZ|$h>QRA{@Q_LUZ#r zW{`ObOS!{!RWAUae-N5!KrfhgVIyY=r-w@T-s%NC(5u}7y&!jI!h*A(XIabH&%WOw z-M1gz3VyShU!WDBC(zpWBa{6xX(^4^_2(ss1wvwSD~6EMd!xmO$&+a?G98>`m2kf9 z8eKio^1N$lr$w(f-jDUsK9w3dVb~C~69=`!$Yiy+ZV$%+Ki9*7`+|CJA!Kd1S%51* z_YSy~0y4#g&6;~I*hC~ZEq+T(IDRwdwZ>roFg?dRex!Cg_XH>pxWGfPnjrZ<8ZxAGDMl0slYrbKbJ) z@t4(XNpN>(;fw79eEWm>)~AlJ^1GStm_6YmP{JBWh%N3DPp9Wh`^k}7xi3DWr!ufs zcuOI2IRWl$eNPyapOkL~+nt!NXZWpZi-Z61lxe{nV@GIm2er*^9v4Ce3f^r&t4PR$ z*JjlAI-f;*d)eM=s-bf(0{w-5itoFR)V@wh4V%=12WSh^XRae^`{kP)XfbF*A`-Yy zbE-hy4Lc9QpOI1<)kQK7uuX$T9h9VQ*8A0d+~ncgkR*ZzeRB_KsjG88`hWaLE%%yH z>_!jZM%Y>Q$lb|^jP#zz2E7OTx*s_QvYdzcr7-IsaSUcloNXy_-T_I7g&cY z4UO;&pWejkfUjZyxy{aCQ?DabZ%j_Uhi2f|v%Jd+M> z3#C^RXY6I|alS36^*=#<;AL&IX$=i|ch5$dOpE+a8r&gu7v1Aq@_Z?6EeAm^EV2$1 zB$)*Qd`Tm!{27GQTxV$sH@Slg8G8K%@U^6AJ?E^uCXOf=wWXMKe-!*C0XVa~g#`0F zn?5Jd7HEUNwEPZB`^VCA*0>X7kK+I*Ee9SXm4YTs?OAcq8l=jMqd3u)*V3$!Exj?! z)vpvi5p-ZFx{LYcPtij8rhJ#4K$#)Q=-|QLL4 zi8E6CcD|OLb2ELY0j*5eN%hbDJB;k=0LHme%~71=&=G`KTq$scySiTp1;bX z-lBW#cxdI_3A+NJx?mKj9y)2E62F(>3NF`oP`W^N<9^hFHcEvjaBOu#fBwC#z1?9- zXUsq4!_P*Ikp+*S&oX#gRDp*99(t|G_23ws^MH zIDkS+%UU$nPrhwI8?I^1a=!eYSUc(cU5(c7mS6T>-LatX{R1QP-G&1N_ZZ|yD*>Wh zW>R{%5J`9yPEyX;^;m9a33>pBTW}+E6verE5QvE;WRQ`W5sbQCdd4*Di-WTe%=7ZO zJ>!!_a=cg%Q*MuJXL(^RzD;M9xm^lp)dAm!)$&xN+VF(us9nZEB~BG)b;h;331@Mt zuo0QD&DhVM!fD%$su$@=%C?vT>BD=~rWozV+NpM{1P$+{vQsc(niTxSB z+|5gZ+Ik_(sEs%#);29+X8^tqDRMJz6;v&nT1c=D*4ZBJJwJaRP}s6$y=u55cP=}p zWBq4(&e<&|Yd)qD#S?vY<2E9N+lTRXl?NZ5N`=6<@ip1ezK>b>(Yy!NPQQd|0-SR+Wa)$@n zv2Vt&crV|47!hUU>Ga%#XC5KX1n+Lx%3eI4q9!dk=*!Ii4@Sdz-hA)%=i98AxxjE> z&B*+9vGtK_2J@U-GeQq9zf+$$F);7O9q4nDu08Inu|{;A{)L`MmYLY%aP2qjze}l2 z>K!~6V-2n-w$nS_QX0!#xW6d9i{JB;lG9{IBJyXaoHRJo0f%n=c4EqS?c5W zri#4>Cl~2ubfn*cPxc(Ct?DRVHfR+Hznz|Od-svrx3Ehc*`H7@?vE<=4SCky1uWqK zwEyyv+FOgZj~ogy+y^=iS(N)yp>opS8KA-Z zx+y=tp*~l>hhEdDH?=5s^RXDtLhHt^|9Qlt1Y)wx?j#OuIaoD_WqfrnqxBaY{Y_-D z%C8((EPjZMja7|M#kjKWplC?3Bjs6J$(Av>ESxWN3ZNjPKpa%b_7?2wfoRY`v`6U zrLWTkEIH2bdX6)^nks`O38x(y0}j~wX0I}TH_>W_H{<8cqbBc1ZU?1_o*uQUof2}_ zqBzE+atlwCf8Z$JmQ{tf;=7LWEwuSozRh;ea!`(TU+cdmU*Zbg4P8y2F6|RewBSN; zi4Y=7Iiiqhh5U#;iQF6H6YHLH(gB^N7kIF7yRg$490)Y*59KH+&+UI3<+8{V_H~{% zl$a8Uyg27|dB4Crn3LD@ZeQl>ep3VXCnF6OT=;BmcW&){<>?vTdS(z}f9N+ux?s1I$4avKS{nT6V(cbzik7uyVJ( zD(As%ufW-zpgH0`UL|_OWga42kV~+p{O=?`(l? zro?yIT>u~}+9ThKO!InsQ>Xb$d9s5i;jHKPpYo~rW|Y9Ve~!qzs}!Pz@OgyH$$dEo zvk?>uIY(Wgm|clq7?}ebnT+V6-bgjEiCEg_bRCAn;0L^2+LO#H)CS-gDz5qEYz)w4 zBr-T_b2lx66l7*3N@`?oS}?pPGMW9j-n|0dXytk^ldgxTi4sPPV9(CDngzQciO3hG zkxKG7Q#9NATIzJM)2a6Kw0PJspN@<-y*FaUYtGZf+7JOB$9FUO_oQdMF#tZ^F1frG zc=y`!Id1po=^6X`Pu9|ckyQS)4^*S)aPd0|-+PrrL}`nOvoRw{6TN_vNsOsA1!y>) zdu@KO@>s-8mEbEVpE8aRapY_NBgnUcoF#{Q>`ZBySSj#Wyx(2Jp6oAR5%Kbh0nMQm z2W}aO?RrJ*cFFq1YOPU%(bZ+W}}+;@&VaIYRL5Wr1a8kgHEbObwSD8sfyG+2)-RB{@aBlIhbWJp*?wPXNLENoY)P!Xq92mj&EOlj z_E{pMIGa>t@Noq#+kz|H!GX50S0~OS zni1>w*xGe`Hv$vqX;vllP5FX#>Qp5&>#iV7#krWJeb(Uq={0hG>46R;(mgZ8ont>@_(q+SF;d%lY6}TiM3Q(rY(-HJ1qsJA*kF4iS3Ml{VrG{I6B6 zaL@3@UHsBEmom5RUgcF1EswZVbJA7gDZG|i9c|(R7;WDq%hwLGJ|a!^R4k$Z4SjqN z_}-v<7KtK88I7gtLH-!%XX5jVT?qUTJ6<^`%Tj+ca0__m?0QY`wczHTjKv92Tlo@J zWn5?swQ``Dkmd0z@|=*DzU&g*GrTfwtRBXf7^?*Qt%U4jsBI;W zgD28v?>}K(puQQ!#jujx6ZF6p@;5@Uoof}4%4~r@Q$muHpdHmQj`bYo%4GX$2Zyu( zKZ*i!YS1on$}NKhU`dLjA->R_FA>qQ?Bl%NulJu0!ct%#i$UrYjY{kW4cI8ek=8KI ziQa~KBQq!B6^qyT*7OP#yL4$YhS0XO{3k^ev`YwsQqRkikyuRVMAY=(f*Wrp8p?LDY<>b&p!{r>(?_Uyeb&wB3bSqpX<;?eJt1cb;|r}-*dm~uCWvH8wW1A$G@xH($L#T}VE)l&2x=`wzH7X6hj|JvgFl_~!^nRQ?LbhpwS;r|yM;9DK1TGFTc zeLg9;*SD6&f{JPKeWK8tFV4AmA6E~yCfE0^UDHuheN4|Zheb01%jdf2j76R^KYNWn z(U>Jp@{<3@sdw^DRM=)ZPex{u_bkP;!nKejxiuE$QHN@iFh!fds)M`EUcV2~AG+tu z-I@2kwOd`(_j06co6PHLOth`;mAmW>4`59I*JU#77^gv&m-%l*1;dVH2KJP6P1mRJn(dsE?7w zt?YqsIeKk_0!I9!}{LyyZ09rrJo85xCojw~1J*JeN+pya_1CplvS_<122Y(yhw{LGdR&`Mi z?+~Z&?v0Ob89Ha}ZZqX1HP&IP2+e_^wle^{QczUVE~`7m+M=Y70o=$VYG%AQL3{%Fnw9p;tKY@l`tv|HNv z;0*u4Tj2oN-HrE78trb=6a)G@Qcdd%WUUDr_%J*ad&uhOYAAGWr!udWdpJ7h65Th* z4x(~+=2PIxBc@U>Hx3?)FXq*mZow03V#h5;uCyuHOi#%zlsxP^+rlc})Fam%y_v4C z%DW+VLu<#;bG?af!1s_kS$DhWY1Ql?%2_Kdz>7Thqo)9&S45K4_p-Z8!{AljQDXa> zsBOfV80E^oU)(lU+@J&h0}9ZfxCmdpVkO<%rlu03thr-ur1rWe(b-vCC*=j-u3=ic ziPn~D9aiQPikw~EP4Aqdr&>}Sj@D83tlT@Y;d{c@EKlmM(wuiejS$QVo6=(Y9H}XjuvcD{I z8I^yf9<4?7B5lk4Nc$Z{+gRx=3nxw3_EQO0PIhukRcK!|8T^IZWGhZE`}r5g^DRSr z?8wHB(r)eXAoR2c3aJh=68fyne>fR#z~bY0-i@- zHB5;Lb^pdave3Dp+-Uk$?4gWX#*VLLiW^7*a1)!0k~l$F{I)w1VVVYh-nds@y`>|Q z_n9L{T3(d`ETP3yfLh1uviIuG3IMs6qP9WvQ%5brgUpc({$*gwO7p^ zSrY>)XbW17MJeS>0qTuoEV4(m@dfI~#d&0?y|Ru$NwqJ=ggTu{EM}JsEi7nj&lSEH z4SXv~>3gS<}EF+l0!$pC-H(HzCjJ-L#-y^Hp%{PKjy zE`yxWnW=~R(<5v+yPo6bK>h$NoqO{fi{2DZ?xRCg8+NZa+`}GhuIwRDpXvq50qmeS zVEZg$U)^!fO|ZxCBO5?9iUlv7jmp;hoBL&GbUBV%U7QU;dE|+LmN!56Csyx#8E?o- zrXyEcfnVJvXZOo>zN0obPWH!XtVB)y_&2>pO?33I+HqdG6NOs#kB;kn)Z9j?i9OzX z9CpNKmh&S_xY3H|vt;^ot~*QlJDpOtbIn{}2mZ8D4r@rhjB1wF-%m>*o70^xOFiCs zX5pQcdJT$<-W#>m3vc^QH*^ofKf)Oe$|-!UOTVD-We&tU?`9cS8C2GRPqf&nXae6U z;P7?Ro2d+Ax4}Glr>qiRd#R=WKHMphu0)GE|F`w4=A-^4+W&nDcdwv!l>F4(; zhKykFn$J4Fg8JX%)Of@Qz%ReRDxJ4?`v*VQ)4sKYU))h}-&+A*sN}X&-xa-g%HFZz zr8w?4?yjOE_$SR#DM5T(6Rc8nTh%n5)_cFD|D01NeRCMaGJI_kr?%7cNWd*t$Q6a3 zVqE;5o>D?rPO#4%GH8|8@W4wleIbwcM)cr)0O&56o6%1PMtZdPTU~#}l5c`mQOmOqc(ZpbQE_+J!PYyn zPP+{$aCX;KJVC`)zUM*~A~>OYt-tNL1yi-Zz!=3;=V*IJ-0 zQ#<|t606V+q!AOVcdbRfsRmkT9U!)PJu94MtmLft!mPn#TQhW2*)H+tKb{oB3KC@yMyY1+o+t-kxrAp(Q~4R zpLn?$niw9mN&a=Oj1gtvCy(y-6iRu^AUa+;hoTYh%W_Ndx+{92Hyy){;{;0DK8^83g+p!sRn}l*HJG)jTs`HPj`EHRcUnPrt7By$L4QN znonZBgdIR8@e%4zSv!G!**0~zQG85k1M{#4+AvvY8^t*JJsbERlZTt&eYL<(ljzB9 z57J^K*2*X?8Yjt6BBLL%Rl4Rb&#Ajl##U-jKJRhm(L9CL7GQrp=qy`9^}Gbsp?6#c ze~?4pvG}U^Rrl@EgEDcCI+!Kt2B@jDK_XL46JWcs#}BvlVC^PXzOBc?f7Sp|SPb>>y;>%Np*n z9THcffj|9RtV1`DN~qPl-c5Zh7EfqPzI_I^QpOw|=UVv*UvIAir%}5Qci%$XUI&=1 z-5I%<2UzJnYw#cGU&<{Ha^^L82d1)9pVm>IDXn||rkkH}7^ngKgR4%O zzXViNd)?RPJwB#ye7V862dw)m+-FJP{zA5lem@cL;NNkNXKQbTagvTAs) zQ`2M+1Dc3)Z3EFaTq643_2guxUTP%LbU(&fAI1v3{1{`JWM&zCdl)<1=H%*Cqxh3q zVyBCg&0Z;0NJLBwTu6CoQ#qL z%qheLEF=E;I1%j4U8A_knW^!!cZ}c&V>G!JZofItw7HnM$eHxht5g`l(o24H1mZh9 z^Ju)@yo2n?VXH6#+{7A<5nMEgVHf?J4&G>sr%)>p3xL?!7S2)_$~4om^gRH9P5f&W zGYU`xf@DDbZWSZg070&vuQECpcf+kWqYkfkQ@AgxMs~xkc>r#W0(V-<2weAQjCaq! z)HW}EtxMm#k?8B13B{l@SHUTTNxz_-=og2vQn(*eYLTXC82z*`;ATRW)1I#?09*}Z zRIbF`^1;Oz6Nu8S&)J?AqGWF@DsDqk3Z(pPrpcQ(YEt z-(VJbWGXA@jdj6tH zynT_B<%mrhM*N9BtzYSEFH()-jH%B0B9xk)>D1J##J|*$QESEd93x`fqt=FHf~%O+ z__P$4ALwRs|EX8|dDEw^2W07;`?9pzq&MHDvIK1qn*+ZK@Kzbb^;H_DjWbF~evFTf z6t?y{m9wr6l0P}iX>*}x7x-124;gxgJ~=rT_!QqMgeXVLNZ~v)J5&72?t3uOr=ZMT z#WGi!-19EoK5yDxtnb|$nx=wCX2?lr^^_;Fo zvXXZ;wvq5lkPW{}{S($%68*@&brdW5W#L9KCmb`pA|k%BpXj;$hP9dc5nGAg(PY?T z8?$$Wg6(q}&w119#ZGfC#+d`&zeeRhj1lJcV4M%*_o8OjxfXnC7MR0XQdkdpY%C+y z^Pqh*Wc=7ly`_ojo6ZH~MvlVsmC&sVWS+l~q&La zcjA6sv9pQXSS!i;paQj;5Z}Albz?0svT*iFNz>J(f2W?T&orh94S=Za3~};QO6pa5 z)~(V*(+!t|2A=7gOQq!f94aM+ImQJ`dc6hdxSq8qSG-t9#0~iO-YufHHyE9+Dsm%t z)5=1JlfPxqKXZ$$%}md9t^@t*Fs7y*#97BNnO|Wo|3p&tf-+4#y>(;aktv5}9+*@4 zQhBtsFr#SsJCF4z!ng5^w4s6s|8;k%^zAo9ICYB=H37J{u63yxa91Ok>zI`R&i`D@ zxcC&}{NXN<`aDB~fPN*+_|&+)dCulf$mJ?=MSyCKt%VF7FYwd4uA9UI&8k}olGfG* z`PuM)7-!N6)Lq0l`#jA^+|d&Kifx8c7s`)86iap8B?Z_#&VGMpQpX&2>A(Mkj45&P ze#F^+mlUK60j*1e#+Sw&yeq7&Cc;#}S~r%F-o3T-qC+}$hxxP=T6U?ptjS+$IL!!Q zPm|f1Bh)EmOoo*EAFz#KC5%bx^*A}X(#d^d@bvmaygp$jBfe7SAKnC>;|ASWt|`b_ zGpZmb&7L|gbqq6(8z1SSPqb(4_{WN!$!nNxRgnhRprMuyuuH z>BDY<<9;Oim-AtLI-%t;Mo8ui*80qR9`w{0WO+*N@5~0z-=>N2X7*q9UK2Zsez$VY_$w=!QL~777&byze-nQuZ8n!IJ z*}Rw$JDaJ7XT3fR-%JGd8Z`X+Ea#bgm5{4tj235mzN#%<-{UOo^6V_dic9IJ;j`jW z`Zd^*QLOV7J!2H59zS(SwOU3x3ylKHuJ@i~oZd#p$)92M)>>A-vW9iCD~WK1XCD5W zGwlW|zO#~ixVlsnp6|hUgb!Ei-}!)`wf4m%RuYrVWTI7k*sOwFsw#7wu3k)8Zfve# z?SLP1iHISWRANgnMqFTqbX*`}#{yUZrIcX3+!dRvw?J-rv%y)kfP`gv%p!lOhjU84 zO7^N2=c{t;`W|zkvF?q`e&hbg>=%6giGB`hgtM@VdeqVPtbsQ$JL`r+v8oc^jg4kx zR#0q|X}()2X&&uE5GfP94&fw$a+S~=}nyf z?8PLk8Ktkon$A7 zJsQ+>Rf5izW7q6)?8@_mr6$CGHN`&1dc^UPBQrtd8wS`CM5bXtdV)Kw;m%`uN%pHQ z>3b_-;=!emzwEpbYCmu`lK?(0)?S1kPvVPT_fm^9FRM=#{&p=1e=kE=#u)_u+)^=t z=Y)n4@K{bTC$ofUPm@uODZES5x^x)#Zq`$&GcrHW=#wi5jcBhgc_%Ma&a9z#o!l7n z(%9OuqsA4E8!&$L_;^IiFk@yrRETi+br3OJ3n(Z=kLArj<1y2|r0=JaSla~G{I-f> z4!h#~)Kc4GGQhE^Iz2(giRPpVW9)en*w(6~wssN{FJ^8hf~%@aFolx=xliR`L@r0y zVT@>=g}&ofaPfMMGfJ8iRxH~d=t&T(x2q*vlTqK8Pn^BJfF5uW=S5gg+!R)qrJwdO zp}l@u=Ib-?q#Av4C)HwaE#Lti;zdi5TC#%u?A~WDa{Ny$kwh)g`U)c5g(W(95S9s+$nLX5 z>31~}wM1Iyt=OO*>e(68TF%Z8xUdpxg}NYmUV-)bqfQx{pr*Db1Jr_r{Z-rZ1X5u){yB{m5zm zJ?rFes+?)d=)8eQNj;g$9Py_%vS+n1S>jQ5X%~?Im1m{XaS-#QJ2^S)^gYU1XL>BF z&swRvv0gaAGh5b+KOJO7ek5!0_Ji`+M)4oyzzU5_fN!T)o0#D_&f)c#BZV@~9+)eQ zNGAHH;}}q_=nRog!b1Q4VP@hQ=fy@ce9il7q=pZeDDaXLo_kfnRPIETh`X6iQ1TnMnXIdJN$y)lVr&~+g5~v0hsFog8 zAGjnz99ypzIB4l!9}|6J1GIELX3mP1K9;4Qdg8y)(jf_=rSiU(UPHAsm!#JyT3Vk} zPPMeX7v|SgOMiS%OCQT(;${PLik80Wp<4QUx0VKWsg|Ca8Y4njyQJcReV_Pkb4@?5Dx~iHi>=Qhhu_qeD_# z+frD}XJ23GNfi?s$gwMvGmV$iQsB=T#pw+y&|5wyR&Q$}dk;(eIinFfXEB!xFCs$H zbnxY-AB6CKl0UjphZ{ONEOUwJSe6(EZ_-}B&)Mq$@Lfgp({_OOkHSx1U#jQw41M;$ z(?6V`24?PzNz}l@chr~YbDQCv4>juHX<~jo;vC{T`J}@|z2nkiqv^UU#&Oi?a zsf@NhTAJM-kQ;ZJv{_<#zUos`de$_K>U(|Y$MmKxTOmIHnroNEi8x7-&B&ysNSLcQ z!*3EMuEGV+1(pjl(?z%F+y^t$e9TM*%t9k!yKfPMl;CYO5072T#&ej7<{Oj<6z2MG zG6jecxMOaGMF zkKsn0*FQ7jhOm|w`|Ar06tX|OHSEOj`WXAu!38#UTk1~Dk&%tDr$(JlI5WI5^06BR zdPfg)SgzCBb+gbwXUplx*QIsSQj|Ii`{VW!x%R@LH7U}qTRo$5#Lx=Z@w60+i6ibz zmzU!_E?_+LqWsp$HxUlA_a;JfgDsV9U2aQ*7jZ9))mgQTWUg?6HmS|h`6SKh+&W-nJygP^wW36l%@p^ zZMEDcXX7a~mh_r`H#SF8PY=;Di8rVUR>nAT z8^NE;ejg!rHV~P|`u87EXgFz#C}rX)hmBljLHv?KL^PbC((q{dl3N0IR3)y;_mjU& z6!;-1NL*ew6L^R8>j^Cw;63>M?=uhQjt zNrFv#B`rl%_keuo8N$j$HNJ7}U4dm(R}l8gJDU^I(FFr^?Mb$l z{x41x`S}dzf7#X2KX20I;w95g7C-Tp?(x)MU37M^F6yZe-9TfAE+!;cH{{U}-GIp< zy8iP*&YZpQ-NkROoV?ahkRD?lw!Fxyt%#Vt-VGh~drNpZb`A_?#Bn@HU+|ab>aujb zZjz40^epSY9<`Xu$>tS1zlli1x$$^@%yfB$nBDAW3ICpmhk4Bw8#^#H#L~Ysgnf(& zu|yk#+21k2-WT4Ob!OJY+52X1w@)21!&}eZ)%CHh?Q3Odn;#?5Gq*qHC z!s;}~R9iKrD&e)qiSXCX;?%zbOG7`OJpq;IE>~>6=xvBI0AqwwO}CS#84F zA@a4>mkF;08fxvCE=$5LRg)L3skU;*RM5a`{c0fPBjtiaYTGxOP0(iv<_ds#I@6;*LKLGwrOJ4OPt2zUi_7J z`0@}JGv;tHdi8t7RclWjyVK-ceh2wJ8jnp=_#q1mBbR;mEAKI1A1NBKS3TkUQK$cU zT2r0s`%-fMi|QHrg^4U)V~{f9WbEsD9Mf=!-F@GC(-!)TV)M(&U*Zxmj5&TpKm0{T z??;SSmw+ugs?rC%Xxz$`BJ)EJEQ{=y(}g9S?czh4=_1j_K{u{yo4$8DT4ZQ%*_D(! z!t}ew3B`D)X14-sl|nz35nc!|Ho5Swf8P~NwL(7&-mEa5EEWLE8bh`^q%zI4vCQK* zUH0i$c*ijE@4ZeutF?I6t!g7Sr?fb*e^Uc~rL>Xsue!&w{>U%KBGW#Ba^7azrwm)F z4BJzA_^nQ_WWR;}NIXxW?B7(+exoLbi_b5j&`XsXi^6%P8agH>k#du+*D+OWWqQK9 zF50RmiGHyfMCRnfW9_N&QCP9Axyy{}Q>xdlHO$NupZ^^*Hj{Evb{Q8WEq2)0ZjRx}RPZTXITmNWeH zuv4273Npo0mG`7==_g_&Hxg%xpog{9FD2C`N!%{z>Ai&0*fh3y-Il#%*y-V?A|a{b z%=&xvy7I*k?)PUhYjH;wt@T z`kKb5--iC9kHm+$m@}FBfZqWNFLK>jNIVufx>m-*OG!43M6po*r@^`{uQS6o%#=s- zS>}VId1Qmwmy14=`O-Ah+VTVwz22tLwq zfVr|<(N`C6t4+5iD_$!;!VOfNx@bL<>G^_EcGB(WbY|QWyYKN^^)LC&mN5CNf5&GP zGUs>mnZjLzcMK}}cXh((*L%DvM);9!Ch>AIBd`JN)}HeMCH3{7^&f8xiLI6v2N{_0 zv4?6+Wj1)s2{UbywY_W95!~^*w-#}7j(t0EYgWGZf{6>kM* zQ~2K0huGTldf*c-QL72o^(fU)IoqDGxu}%WZHZ)JAO+&&{VIh@!;j$1mAkVq-${ zdqS<_)~uUePv~{8v?!7&mQu7gkgZuKypsB2*T#^sD_+ger{@~h7g-uG!(^C$!Xrw! zwL#bSI_aDoV});&u&>_I&_v)BVV6}%g0A0na(Y5^y6R|b?di$TZ}l5{$Ck$)0v!#p z2Vy~=nkxlXF_9yWld-di6uXsO>L$g)T#(eIO3_)f15!4H+JwC z4fWtUd>))`K!?U+J_sL<-sG-jaAO*N$zB{z#j=E7CgKrZea0STua-Ts7iUFRGdq-L z!^>}-gm+er@kL^MkyEI57Ku?t!aIwAcNPKfECT*sgynao{aB2^^0=`d`vlX^@Z_@#uO>D7=>ygvXJ(DcYtrRy z#H{Z%=2Y&!nro&=)8;@Mzwa>iUy!3(8Lrl>D)?$s>N9Fhr*Z)uZNt4V_*|mIhmx%U zjQ^6^szXfNW8=3?kTmeuzJVM&!pX==K?9GC5AeEQYa1V41{zvSjw26|t4`U3xZ?rLfz0eUKZl26)`7e=KGu!0&ol?Kjy~Xi^<|$s_~> zcu18X~RgAs>vBbjz!;Kz=Ce-c^eOQ?eSk>xh?tOAO>V_#@{uSpJdwSOo7fd%0wQDel(~hc*6T=Ts?_t^dnP}4 zrM2ZFS~KP0DX4kDEc+818q_}fF$ay_U{42^65B?YXx`#-u9Uwc-twAp8wqF460JR?Z6b{)__uf>TQ3` zh@pE4Mieal*Uk1mWwd3tCMc9k5UrJX-#>UE3HDPs3;i(2X+#gw>`vn}m#|o^rrZ`% zC2ZswVOAh~Z@lXtn=${mu+f1x8SuTO#a6Pr=00z(8hv8)I_wr+7P7CQ@L19DJ#{TZ zU*w|CB03#;OVcCiZ%Hxceda)|U&ydy!;g=wi)~OHRDGj5tg2~w&JZCcagdOsvJ6Z7 zo9f(h(9o)WMyyX}lxOSH!k=%pr;ZB(=L3GN4=>xt5z96}4!rn<#Fn?bnP>PgDcZcp z?4Pu$7&DAsw^aMg^xWTnZT;gX-3`fimDUG7Il(3T^)7ZU2dl+?ooeb)=mM`J&oEd6 z$>l}$4^)D=t#~K#Lp8$71BrMx{~3vkB-9d|{Q~x?FZVRn?}}yWAo4S{)mi+O$gi6?;l%q{O!6a4J~h$jCr$9%TN+dBP4zyEpNW~l*02>BUg=%p0;Nir9|K9r%nEI zqAOym3L68NRlWVRZ3ulW{9NeR#F+_K67HBNMMfPfD;ait*qPyV!%xLF z#FpKojNx-}wW&7g?IcZNpYxn)rr4PkC(34N!jAH?gI5Q!oQM?awjYI5hllY{hodsDqq;Ebdn*30OY2 z@7#hpBd7a?c&qOmXsaAmhLN%bw&+uIjHK7{X?>IGCnZcOnplvu$NW&@XN`rYl#zW< z`u_e!6{D((_;%UWo_mlTE2^%kmpn{I-By3+ zgts>5=#3-2j^!Ns;JCN?{kl5`7B#e0J~000i%gXXNeK%Q7fme8DoY!lwQprmhl1_q zLAd>a938y|Tu0);Z`^i zwOlA$=^?dM5@KNc5@<%kKG-?rCD^Kh1w7sK2M$% zxQksBmPV$)!SUibSKrhGv1uD(8IyyuS4#Z6zU$G%=9G3UKt|P+0CV zQ|u||F^Ny@=RgsxR?7L-c_)oeI}g$a%)zR_q*LT zp6)uhx|haXU0&qi8rpS6Z+&`$qY)^$OwL=fq&_9%^nys(f0na_s=XkzUb83b#IqJ*7}zW zqB8r?#M(J;&xMSKqZK*|ckI}0dj+)XbbP^x!jEb!Ucpa5M0UeP6{YaLlApJ9pQql8 zQChQ`v=s^!MxK4&yeF5|iY@Dw@(0TQZnY`o{Jtt!JT}(k{&V|nK@(02t7wG0qL{+q z4*l_*0I2lI`HcA7=iHd8GLzonAtN^l0WWGc<$(ec8z*dEmp#3(U z3xroEdq?hv8oaB)k)0&XtmoTRBR6@RtEnebR^bxh|BNh$1yWI~r2S@!Y2E%Mj>i34 z#udgbY+ZO9Ul^u}zJ>P(+oi>`ZdEfu%|EOA&p&}*Db0j>V~S19-2ZDfm2zZi0`;&; zKfiAmQ)Rn|xDVRJ*{G)jNa_S?`_zaev4;W>_n~FaFQRdu*m6ZLA&F%?DDk>sF+`ax8rB#1Z z6i?|1=lA+_VBUP6fBIX!Py1Q#;-(<7EkV3uhjk02bN1edMD$rm-VBHkV#}oV00T2N z_Q;^P)g~H?c*%B6jz-}A+1;z^)bRSz6SI=)*oa-&rz`NAv-! z);Wh6{f}6~`ECMc!(TI(y$i`Iq88lQ8p16Td#FF4vJ_b?ashwQ^_VA6>dq-&*xFJ- zBMFC?&)`FgCyuBTKW|UT@H4n+_$M)#ds}0=k(6ZHnLWrxEKHOztu5Z_{Fu_9aChi#hHW5~v+{YFORy`+k|BM4Vz4AL4?2JhO@V zz&4X^ODDNz;`lu^bZ$uf*azl^=dzkm=GwD9-^mrRq5>ZlJ3RT=*iEIe6<`j{o(0Z)Yj zW@qvpzy$F4TX=Z#80t@~U-teB;*;==*C4G0-62stcoR5Yp!6L5xkP~#m{ILia z5?^rN!}X-k#NOQFN%qLm#(sqv@w<;9PK)ye%C?wQW<~DO%n!<)B6auaJgETnhty}J z!E1QkXhF0>e7+shBhGA9eE=%cQFoG9ndX}VDYeDfSAD(5Ld#6rj`{;@%@oF1j2vs= zrZkf=k+!rxOEk2qp@Z=pyCHpVnrTS{U@KWmc@8>D9?Q>KTeunP4E<}(Np|SB@WKr6 z%WgWmXnIqZ_w_w~aT{-UQmBeRi#>-6Gu(5p-tNZOq)pJT5fqwvuHTUF4Un(iihS?h zea&P;1Y{#t-fg^)0bZ<3U^D4PcJY1uAYR?J z%|*4Z-r8(%&raEH9GCkAXlETbmFjVdW2(Q!F)LKMEg59wnk}-`V3>}G?!BPY}GSgcuj~%woY2sU1n(~ zyhO*A6@4x&JojuXA|NX(+q4O=;L9pgq_y8+Mf0yjGXDpSeA_jw{>NLe^?xMJ`ClXQ zeS${5JyLr=l8#dh;N9EXFbBgvSVX=fgjXGNtoqDc_-jfm4j8Wb|1Ac7?vXW^Zy=wD z#=z%4{=bia(+sYtGGt9zX{J+*l|j})wp$ycY%g!s(BA!XVGRU;9q&ud* zWSTKAWJOq2;PmW+60cT^wp#@LDCydT`?6Ft`cAVWq;{8wM&Kh7BTAHryaOwp^fyjo zKpBB2{SmJpLQlKeVnhAl=ia&BcR2c9TQ)V3=2|#4M-8EeLKBhYd{J1;`wi+sURm7g zI60SW(O|+PWM6nLF}S<~xnO%L32l$IMlpfhCxk1QkO7CHsx?Q(9++53F;QTRv5KoS!CW#1Z}gtJq+yqZuG!mG=#JrNA~PeVuirmw7XD5hKRz`f8f#){x$ydt$B1|s*=TszBra(88^Ig;bG+W%j=cA0 zYCMZ2NBh!SS-lf+r>%qHau-gEQbY?jZ*Pr|a?tGP~;@q|PJjD0Ma$ zj~`FZ8;r84(4RZ}R@+9ywg&WOYbG;H;@W0-9|M`7VufP7yoM6#lA1N@?}{xuImVr# zZDn_ISk>UMOGR2d0_C4!^x8id8B?~qaZK-W_Y3`7W<584e6@X|JSuT)9%5bPWXZH{ z{yDj~V7*?u({QqwVp($}+8P4hOKpy+oIIp3o??G})d1T|aW@RyJgj0hQ_Ld!5Ll)3 zq*;f$Ub~4dyn^WZbKo`n8z}$P=!W2LH2yt~>?q{-30wu&670#z9SkkwNbZa{sysD& zXZfCz*@zR$JCml+U^q1Egu)5A&rq8(=&#Jqh}oNepxIah%5!B1Nbl=rwZKii{lcu;c4!z#5irjK|B@Tw3!MG5vP^5X|5o>eQLmo zu}7yIqFGB5kI;;z=;bl#!>m}(8i9DoLo^?B zq%WZBS;&`2KAH8`+J&uMHzE>Jo9QV?kfMePGW)G9<<%uqPTMQDmrXpAbZTbfocfne zEU10;=o?2iuZWiOole$l9CNUSLT!1>p9t-PiP)R(VOt@l@x4;VG4af})Ul%7e;{); z$-XmwCeD6oxgxFTOPC6da|X;e&dCsedY?(k@H0dtPE8bV=MPZF6|E6ZSaqjtQTCRj zH60O#Ew-_??YR*pI6v|v>~at1iVX%XUd#=E=D`XgPB&a~o{d^gqBb~}e`s*3a}2tH zACiMNv-6biOF#9P|M1cHjqUeYgXHWNHS-`5A=Q^#M3=t)|=r5R8?dtL? zR`H#~h*S6(>TSbNtL8#P+^~e~tcdamLu^iP2|H*x+5VwEXcO?dR>rIC=B?dt0Anqr z1}C7;z7?2ApL-sWp=)n%r?fdM!5C=l&D!}+ zaolM_DL7N6Aj*u+J9ByOOZHRf=gInrxC>UN!-2fN2*U;N&v~aJwcR^9sq7|IgO8UB zYAz;q3^&g6f;!F;9Y;KU#iRZzVtD;_cjjUD?x~5k8)K*xS{k71|LZQX?$6{tX zXr=nld3h)NA*-g;CGqi$meW1LdEJ}xOT9(XdEKf?;?8ZxH;Lc& zi?Z{6qpWTtN77QVO|K--JX%Wbdm5u9%e{3_h-K)0^8t6 zI(l{V=9+aMX}s?BVO^k!X*}7t)>6m8E2Q7f?Mu$X%<_lMfXvgcLJ>UAV#Wc?-Fvu8SM`eKZs$?9MN*xW_QFbnW`Kp+igv8 zB8rE(%!UnQmZWxjLQFjDJzAk<_FCu~xo#EZlR?a8`SgIOvauzaN?mr7>=_AKj=@bp zYMexNo2!ucmx=BnHMt(jnziJ;J{0@NQvYzE&u>$Wkv%s)j=Z9#-*~S(@}{>Aamx8b zw;C&b>ZYz=*3?D7hjPt+YkOIBiM?`5d35?`R_N{PGn!~N(X-d1t&`8o*&wZFZ;lV9 z@8;fQ&8g6MMwOV+tV%bXPZ)|_|7;TCau=QpR-XD?0iUmJ@D^d8f}*3TKIY=)f4gMr zEf;6X-oM10YC0ePG})I!R(Dfnr(S&yJK506M=secCn0qNqXXimb;>lb?UpKL%^%KTx2{D?xVTYjW6BMTrP~u7 zFn0A=$~~3_D-&fi_H|biaAIBQys3h=wQX;nC44@1gka;NKfPfcd}yOSzQQYj9lZ6( zem6I;%hK>NY5JD_Pg{W}Y{{;nwJfA>gSK!(EsJawSOF}Vr zr<)yk*U}J2n(n@Z)e#OWRNXw-?!CTPhnd0o#Z-25edtaE0kZR82`UqhCNBv;nWcO$ za9HXw@q-qMv8^xLyZ{=gPZRXUV6u6Er*9(oT8fK4%P1kF{!!6j(n?AGUnYa^MTnOtjQ{78~+ao0B`j z#hSsaBJE;A$3xY0w$<9zfVj~^;&T5U(+v>@(XSo* zvpxndEZs26An+-yxV$-39NQi|&xEI5$OvL_V_)b~rrzZvcqU~@`1AvuNf+@wdBQZk ze0rQE$;v#+Yxn`Vy08WkQ6f(2&rCN^SVe!F{3P=qW!FiWh6^f-NY+0&f!Xm9MYV1vfzdyo~c#uxIy(_;7m<@k4Eo zS#hk{%GmksxfWQ9j;vd5aqPXGaWWVk=~8@)Bk5K2d9K81Hz(^hstGVxJ2=Qk>ulr^ zI^xKAwQdzMwRrcYo8EW#{t~ON@3xI8#i|}ri>b{jtabD5_088tIEZ0M_|Ams2SUr| zEv6WmT3)d?@?Y@O$8>)0`h*eKpDOU}J!xsQ6kJNr22tb9()DP8OQvu6l-G;16HXSh z)1pWp+1BbpG{B2ib9J{n#Q(;2n?k9N)`k>|)3ijFttNlit;-(BJi40+Nh-6<97F~j ziUHp!d^EFU7*2CYV5gKLbFFo5m1XKc;#^(;2?K5_(=*^xxAyE5k56TlSy$m0$~CHS z)sF4y?cBCp($3qA3sFGh#5UA7yc4X&YTB$Z1dyuz5oDuin92 ze+-A)2)pLH-hFF8Mb!SWrM0IuRY%U$pE}iervAbSs=A6#TFn1fBt2ND`?;rWw zqle}1`C8dB%*}tMl>T0t9i1+>vTAd(DC~qsqw8~%4EW7Hi%XPNZ8K=C;&qcde!J}1 zug2P517AOz8D)Ds7^O2TQ_mB2#%9&wLl*O9RrT`oHCxP*b}TCeTv6+y?_g%PobBec z#a)87ln8;TUCcOkS~{aW_;~P9wDynABenzh`((StT&^GN5qt?Rp8*B8~VN!QdmPT7V8Q!d?}!z2KzuV4oel_>?ah6H0jHg>bh_B`~u z3SYkn%d^y*!1L+Ve?sd^w>i~$hMlgzlHS4YHO*eiBUuf54AF7_N}05j{|Np|Z+BL6 zr_zGw)DVn*?q;X|P6JciP4y#ZG*z{yyQzM$R-trN7A+r@X5v5l7|q@PwABOH-6LEysrh>w-TdT7U4_ zVfU(Wcb`T+$$56TBh_S?W+GbtaF#ow3a8)Gh*S1{TYMQ;nkqTQuq?DKcm^K%MR<01 zz1a)&+8IVquOkkH_o`*yTPpoK-dmb+aJS4sE1Iu7$U#qf^x8bb^}Vdjms*)GTkblS ze{49o_pc-reA(u;B$dLqOI3-MHu7k)uFv<7W$>QOwzmW0qvI}3q4asQ_`SEHY74B1 zgzgWEfzP<`Q?}uIWQ_xB4zY??=^kQaTm5d9GD;zn?tQ(CE^ymgfrD)DIxmLs?{`9*!CR{5$z|%V!-HbtGMFLo zReBaZ&Md>#5I8wLY2<{dT@{l>vC%@6Q{!p8;zXe40`ghfPH0;;Y5z6=V0;Kt^Vf$%{i4W z;C!&;|5k`Nqm|ZYkzE|TBtr5}4dK+HIdI|tyAKD|*cnLP9J-K@H&0nRc3Z+rdF4yf z0r43B#*e|uh;8Q~yM8Q_e7&DkZ z^~Md2?c$6S?K_rST$Q+5J<}{+@EUtJx24hQEj{kEj7kOE!p^xA;7}fAGVlc*K9FO4zkgVoP5CO zFn#Ne^jxu+=LJxX`!P5%WKZr}iv@mg`<`5ieT@H7H)nEHxWTcRdrje}SF03CT&+`R z@MMlVF0X!k2x#8AaIH8gk31JrXj|h?e?OZwlv(3nXrs?PTV7ft%!f4>ads}4N|no^+2597R+7yQR~CcK5&cu?|o>=8XN3FkY(oPp7N~a z;p>5rupnoq*%*t=@6Xxs{yX}#oO|T#-}_wB0`@aMY7;S{N6y?puGJj_ttVy$(JYxZ zvD~A%W<#mgCvyriS=y>OwI{77_G$M+-D?|>@k-S7_LuC}Y-qK0;qI^pqa|U`zdAl3r=^*F{e5 zSx4v6z1y*8+WlPKZ3XtZ$CW=vqtvf23A<_t81iHZ^Wv01 zoNyY<(#$(fee7!r%OiUgSeD9gKKnI=;p|rmEM1jUn-2lEKUqlo;rwadsV=3HjBz~< zIzwAHl+oJ$hEnH>zngL0Jt=UzrRv8n$uZa?-x-eH>*bwewiVmjZC{ANRVoURe3H~f z#6IQS`054$|!@{Ty`MdJS9j#rn0%-StBK61;FzB=MhSQGM?dg0VW zex}h~)r`}^CCvsR{;h*Vtr5-GW$w=e>+%9f(sIl80CFlP6L~mVb++mMWAEMLqOS7) z@$(*-8Nf^Eq^N5)iki8C18+rTivS%ire-RlR?;{OFbNDYAll|8A|NWDjf%I*+%j`_ z+j0_GD@0Sgq(rQu`6+Y7OSzTidM%aT^L5_u_soD;?zW%D=l92V9vsejpX=+K^E&7C zIb_ZjfEH9*>PbjbY(=pX;FRF25vxZ&?D+Y`r;4#yLv=Km+(%>OBE;& zXS}DGi`p~EZJZkC=bPNSx6b==)~;A^0Q&r{oC`SFe8}M!)v41Na2F?E+}7l+K3@V_ zcP)!rmvDxu95{JQE!^a{_uD3)qu)+0rgjWpT*z;JP;0;Y(Ki;mWJTXFI!m*VZ7e1X zGk(-FYQ!w)!PYz-r8yC?3!2!wpEmjxM$`gBz5?c}1fwDs?S3wf=Cr?%Tu!aNG@kDE z2vFk{Dx-0o$0;%1Qm0XJJ{8?cY;|4ypBj|{(pH;WrQ_mQX0I#3^6 zQn2z2+jw|WLs4Vs!peo_FVu|m!Du%ak}ID=lH^1_y1~G(^BvJNQhhr#_M=p_h~67Ci?5$vqmshj_*Hd)g;YS3zzFjJJr%kzhp`9!jexN+98P7 zb6;WX)B6-T5Xk^@n1Kz%s_Vt88;x5QV&!!54}TKA<2&xyTbldR59=J~9^yOn^LA96 zYo>8y2n@b~mE&&kem?uKdy5^Q%WNa^1@3%W(B(AOzFRg_*iUgNeE?7Im9U%bUmDnT z1&gXG{6|!$bnLZsIxsgOANpV#wtlCVQNxI%l%%2E5mM4Bg!V^YFp}(9^8$;$LP~UUe??Zcnf{T{#)m8LE+pQki{hxiXPxq02 zOCd>nLStx`{m~6L6JTu89=&;MGR;TGp+;?-w{ z`eG0(IuUUoe1G(zm`}rY?H{lar?a)}>i7=8U@A9wA&n}Ock!z;=6E%GByLN^Bm1Z| z2%88G=jF}A?HGiq-$AA=jSoop(T|i&=W;YB{&NK$<3hJwTUAt+t^Tp2 zZR?%BeNTF)G{wB7bU$p zXQUlq(ixrlCz?wFx7=X=Z5_}$NbxTCN9MJu13LPibwJaujt{5+_0paTY^ei^+%LYm zN!9^<=hcM+>&fTEH~yav=>L)q=xX$WPh6inbU-6d45w3%t#v@D|DglwuTLax#gh+_ z7U#X|fGVjYCvpwRzLfgjbU=B^;}`rlJV7a+)svp)&+32zyKs`H3qN73=(UbK7JSz_ zA@7s%Tm!QQ<=sjLl;?I1oSKIYsPXGTZRvnYBSdfH?bF4j1G-W(=q@^-3D<_#`%0;5 zqA1n;&ZGl6ewa?ySNXL%pc^_XI-v7AH>o;w!wE>P1Iju>lcAkk*X4gj2lV3LGxwwe z>d#&ySwOs8nX2FpaaTtOfGLC9Z>E*UFM+!8gSDG zbLcPYfd0>$BS;67=HfCsuh~^SoMvr)5^fdFW=#BXWf(TsQ<~w+Rz;>MW2?IKEriKCHGU(T0*_-Kh_=f zXK8KdjvCmrvhJuMGW#BNNA+yze@%DP|K#8{bw_z?KeXWA)E)JY40q{{`bQ4L8MptZ zJ6b25x^AsIdgT588{N^-t#wCFKDgk&tUKzz!SCPF9rfR!{eQZnch?=g@Tu;jNAL3dQEE|YXekGz8&&JADH|1ao{au`#g(fTWOM|nOE z-TLq7j@JABtnTQt7nlEsx}zIjg?4fqx}(dUXym%1v;Gs^(UX7h*5U4|KR|a>aOsZv zwwvv#J8Ijtvz6{B@rPV@lr4J@8fIB8-O)vye@{_#M?d|TQhMr+a?Y7_N7=>SfICTV ztvhNv6vg$h+`6MY1;y_MDw76o*h6>J_9@pLJ(2RnFX)ak|43PPRKl4X#5>EO6q>W&tng*5#WTIk!|sXO|_wOZ(ocJZFvw(h75pBC^< zf$r$~cGKF@9hG8bsm-15&>iKip#A1vS|Lk7`u|9GR4V`3c}U;3?kI1IlutIcMxeoKH#Z0I*s&3DLj|L2P#^l&urUyFIuBhNo$l+ ze-w!R?cavZ=+wLFj6O~JgOoPnxcaxy(7e0G=o1%Jn0c`~5V7uEm&WKDo*JVbc^&DE z{_WL5U$hXkwD1g8{~r3H(XI4F$A9;u1Wf{^??LS}%TrsFYZ(%>Pg1z7EBcp@?y4(# zpT@t1uBfYLms9#*))aNc@ANRn@4e`WvKs4%{XeTGdW`f$sSZ2)o9;zRG>NoCldgGa ziE^Bafp+Q7X^EOVwM368z5H(f5Lrjm;;AD#{o2)SZXMC7^EX3BbRn(uPv2;vBRaa3 zj_9Ooo20rN8PwDf8lo%OG26w#i%+0-7wX4twq3N9w9pcrLRz9!_s{yya_NXt+_E>8 zD>|Y@QjD>EaR#wa(hyDh9`cbTwb!|ZXkqPw|F(wct9wY6Px5L_-MCumtekuwbj_<3 zJ;(IiO_J)@mVAU;pa1d+?cO+UT)xk7`SN{SD=Sf}=^5!0N7_eE$C+cV;CvD4RI{U` z_cxNZms`JUm@oym@^!)OLO7p`JPVhUeDYSTxdJ;pJk5(moxY;*`=}48YEZ=@%{9G<`f1&=#DhYbh>8o6bBSqL5JNJ(@{}5uvFw$={2V9Z%zqA{C zde%t0Q?y619B&%nzR+uX8TLPXX!l~l{J{BpppPP*mnW&aYY*-kV}XCx_P`!MR`6DN z&jEe~Z^riU+;fn0_DD~mm_@k83hc>_W|p z`SJX{1bNRyg1@7tcJ4q==uvLFnZ%(-Z z{kfX0OMm#(YoG=%x&<#JJ+BUrmppD(b7Y>-wbwhceVn-Ty~t5< zI&DwVCi7mWa_-LYGXLu|+rAJj5P9U2O?2Y7=ES*yC0%GoVS}Vo=GN^De7!w1ZQC=P z=O2ju?V!=Dw_p5@_Hi?cE-ZWTUs6k6gFdOWml!ypuP|!gj5W@M3!?({eFg8`&y|?% zLBew-K9QqI*K1kxt)8Q#o7a0r9)Jc`!JA8&So&sE;Ol=DnjY+MoyuzacK4UYsKy$B zTm6d&;)s(2OX6>|k0bXV&aJ6(_|&WIj4|`mYUn0VTWe}X@A;7zYA)6YGz zl?&z%!$FBCW7DZ~w@tID%glqj`YsNANQay?EUqucbcwI zBh2fjdqpESy5PmgV^{H-B;1p|1l@FcN78v!gEun&C72)32;$dA@%rA^F#80&`Jpkd zsrBi;!MqkBX^D8d^*ZeLnfXBPs%}8I3JA%_xCFjL6$i;F7 zW{;rkPTQaD#+Gjoj7N6#w#@5d?!HMyZ~r*YorBpclzyzko0d_9P0y%r(kTeFv1!%S zn<8G%6H~7VW6PiU3a4cYn@*^IRAc|NU@*>e4nVDg3t7QNHH$MAY(~A`E@X$X(@ihJ zyq2n)tQKwsIJ&3>odfkdiZ&?QnLjU|-WHx$ertibC*D>~z0ONNRKDk9f^TlZyBlym zi#gAAhCe}<%FbMiI_r){X9;}&DPHI-h_qdfHwV0$l06VP3-W zU15AT**xhiv)sB;)s*bKZC-6rHJz+$HV2&WYWmjamihi}LetlmZZ$pIt(m*OO}Z%< zzo}9iKd(B|{LGG~)0Ufib~Kqz-1@GnNxS#zlX%r*YSsT%-F=P!|F3(w2QGvc9@u%i%D*NHg$@@Dq5)i#h)1C&Ap_Pi5|KpktIJzC8Sd zf43L9tsYshX>aon0Ufnh79^A(`?#sw)!VxgXXUEZW!i{i1J?>;gi$|i7SA4K@nuuX z%zm2tdw+@(X3M@R9=H%MrQ?0!#K?I|g7*H9=+s`NcSKYUAHl18siRAO_O7`z+^QcY)0?a>bn6i7EIi7VM$HTOA>iQ0P1E+$TPjs6MtW`D z+bkB~RlikdnK)%Lf88%o|9AF7z{@+1lM*iOx}}Q%kqhE@ju*{dkpqZ}Y5x zGEMG+&&no!+_d`4ZA~n-Sx4>mnk^MVY(oWZR>h5TjsU!AT7E0wZ!yl@PYLGluliTa z27g*~_Q}OK=emAmCGIO0Myton`p9>T=_BX46*MA+{pH_$8nXYwvhp9cEQF>}v#v2Q z^45}VduQQ3JG@sdwXydDyp2P&F%{<3Uu(Jv+gEC0=XG@kK>vTkm78h}weTW__AU7# zZ;!UH{4Z5zpLPtoH_Pt()`3=jrfSV@a3ISD{}W%{rX4A8+s?zSnI*UKP1aT`KU0PJ z4?rt>Q7d0<(aN&|R_<_~MlDV!3;UP)#x^bW{ythARoEf6DOUY`)TlGt@QPOKp>0v4 zdOz1tx8UG{0}J-e>ybao@<#Mzjd5q1qv(3GV*=*xM75AxmRl+o?^QX~dsJe^bzoq_mWe1dG09NnNqoqUhs{|46AWyZZ|t~k22@=V{DhYcBQC&pM}>?NOUA= zg&SqgMVnOO;=ihN$MC`(PAX5RK>20Yyv+7k;nFKqden2XSL-_d*c`n?oU>POUf(A~ z`-o*Js+iTH_A8ZR8eS7#WK+ddOs;TtY(}~Oq2Uz=(p_D>^SPLPjzvEnZn?^)u?C(sdnf;tjqng7e2M^!{G^X@Y86gF`jixy{LTIfB5+<1?QvN1>D}hRvhjpL?4_G_x8G8HLo&G_DgL`H(r&*9*?VbwcogN~7+WS`cr&Avo2CRL;d4y&V68Z_Pf{&S2>QLg_l%O9x7*X zqRR0l>Q?xMYD>lU73P1v$xf|{N_U`jba=Vhd96yAzH*n=d272cu->`&L9gnU#lmAM zyq~LbJgvstG-rWlpQ4u%g;VPs$C0Aod12>F$Ks!wo!1ftF*iZjrQK5DT%4(j*w?GU zsZCWm+h0&o-i_;1R*LPvLeC@!)7LwusfEewcRqKk2c?NtQ|c`hmqt!7I{iLjV&wtm zY@f>(OcVURmpOKF@j`Cg0{E78C7@BZtWMiZAQS`%yFR*CiOB0>neISTu4>ITPa@hpq z#)+A$#77E+8Aj)$=p%$Vhh1UtQwMlCGjLQ&N>-l+HcCl_B&M7tHk?~&_@{A1s2|BJzgF7s@ZO1DeH9;?-OP?fX8a|@QZ(C z(f7?O1+IHNzf!#KO)pXVHA=ZpNU7M45!_KKA%otXl*at`*n<7tP=~(=(j7Z*FI+fUZbvRV!aLk|38{1 zh+&^F=VLboXXW3Sc=ixz*H?IF7Mfd+T3FaB=XbZz#uH+$zU(ae4qAD&f>^ZC%US)U zAXb6ao%^0uA9t3W74Yu3;4He$U#N9fe=mroZ+JPszYYC=jo?&GQJsIuseT{twkI-k z&Sqg}YV}HIUN>N*a}HiaoZ=%?uMS_0`{-k9SIu5cZx%b7&as%)yH<+NJ2hC ztLqx}-6%JgYVZGp-+G^mKC5wpQC)D`BjwdtN>Nx)T~`|`o{tq8_F=aXy3-N3Ddl93 z+E{v*_pM#NF^w@-jdU-+x!wNG9qrC%C*YRp>_~KH)b~QG}ui9HTt%o3I0i%s}EMjR@d#^0X>ynJ3lJD_?k8)hU#A|*FR!a<$d_$=YGcs`F^(&FZ1(84c9uwe)c$X(Qlr`XZz{Z>ta4o8eN^xU`pDfw5vvHg zh_xd&EI<7k{EKnU_RLM)w9$fYbPuL`z6UFe5sS}8I<%2m^T+3U=-LTtT|#2yalBN8 zdzx3hshYRM5zvo4aIQnlwBr02U%ViH4SZptrv1mAv`y0*Z!eD}3D>(DmPHq8musBo z53p~lewgC)>Ed<2fEyY%X>K{dQLQO;uBv3t^T%0f%<&2#uB6O7_Lz^9b}@0VtAL?L ziGMwNbNS<9(Vrsy)Wl&;TX~`8!+*uZI){zN%dXXU4K$BEj2B&HEbZ`(58ib3!Asr& zz|w2ia1UUf*W?%lOQqUxJ&+O;v1;oU38BmBi%^sCV2EZrete)$~c_!UA_xtN+Kbi!Nh-po|qsVQpA^!ok{DTn(s&L}B_ zZppRg4&P5-w`ryGcfS{=)r(7V1#&sJtz^#AxuCGl;#JJ~UIlYjt`hc?MXv~3F|8p2 zsS9J@-9ooem=_+!n+_*^-DL^!!Y9Lgy_q<-ub>;zopttAO3XLzd5x#(`Z;7BD} zT^?@oStCQI8y3JiYn9jsio;88R9%W0rtx8)m4($gG#Jr`uhPpBUJ*r(#L1D{3vqu} zjCs{n)x5=yRSz-s`BLM{rJ@h+a==@lYE7VCD_~3?+jF}UUfjGES+W@~isG(=4dGyjQ^bp&HOKknr+bKSA_QVxqXtJ(Hd zxMOniUX1M8o1J1FC|j(JSV<%MLd_$U(HPgyVq8b;+l3xHu?qKDeK1=H!^$ELoGM%m zr($?(p3YI)7VUaz4EgOTOF`>W+a4$mO{_w#Z zuL<4!{YQ=&sa|kfJ+{oB=B@5$ZignS3&I=e4c-Nl6UxKuIToxqH`(0IZwls=UgxKn zi+rcxjCNzh;fRKadZJbFe{4U}D;TfScT8o@BYT+G3#*Sad+-8lHN*1`+U`{oMx7dU zX$&Z_-l-iFW$xkY*Eyz7Y^c#`Im`B!I?v<^E5G3-y$XCwT>(=eh^eVUciyMswQm`4 zE`C~lpN9U2QyTFmK)JTpH-B~%UTZG=?)bVstHcjx3e)SI?NS7CiD5-dOimH{S2(rB zOneV!SOtqJ-?D!D`su*Cltz=2N^5%QT(W0rE}XkDNX9v(#92JPIpA9rUR#G8tAekX zh4_34NAHM#s`#xBLSqT%o-D`9L7*Z{k=LeI7ve;w%DMLn-X%a;vADZLg?DcM4&h^r z?#dN`v^=_;DK!c)z`w$?%qL2%S+r}prs+6v&*;=%iCn(fCt9uTq!F!e;jSSaD2VgS z8>(3oS3t)kY*j&j&CUEc!p07uE1Q^T{T%l+eU0_>1LfvVzt$j@HmqW6jFgx2NF`?P zs+*l~cZS(`jp2RWt`D)rT2XzS5gvY6ssbMB2@i3Kq%&Si>QfdzRfu@`+gVk?wvHmdo#mU>SFaC8Tc0X^WO(00d*s%M*Tm3EHX7`HXX{IYt0GqoGuyQa|%jOn%WoYET$5;{-b zI5{-Yd2SExr2f3TX^Hlc(Br|!!XR_+dvMOvbgcsqNzFYYbZS-Z0)_4(l) zVw>8X4{Pe|H=O8XrNbq<_$#0k7?Gt?6UmYCqP5c+&Xlid z>fiWiRh1UwGvLjLioyohsB|1(C=y?ta14sU0!$A{bQZ=VW!LmYYx1Yf|q@} zHZ3_C?4A|6`KSBeKXSaxiQZ4M!5W$k&@+>Vv9Ly+7H@gHa*n-}ph_HDzA<5Jc|v)o zy`hbGjjKUbpC7+9fwbhSed+$3z+QNb@xc%;)#R5Z_es2zX!iDHc71n7dSQVZ4uD5J z4j%P9c+?*m>4{y9PZ=Hac;(~$$E+Ho89TYKaWw5N%WU$m^9yi zP~$mjn|!nbi7wGB(WKE1EdBJg)Cd_afBzT!+mbcnC9Zf#8tc1nMs7@qH}1e#{-=Up zL_@cIv~#KR+ZA}XFI{Nr*6v58pO3iuS=3T5=Lt$Lhc}4DtC^@lFAo8aG^~gj%PTSC zOsfyYC{WtBaKRtI=_~Ea=e$Md&^I*e<{O3hPTR~HKNX*8nK|EA+f4<&xA7vH)c(dZRor(Id^depWq#&jpU$H;j@mlL{9t>(32~>4*)h(P_dx-j zXH$fiCEDI%uFY#X*Mh!FbFKOv2dMks&WcNBMu}SQC}$Ps*P*8|TYwL~IuonzMUf=E z-(M~kz85LJ|2li1G=FblsiU$Bb1pp?={$?|U(pwlVT}V1hc`^CFN}S8WABuCU7KFn z+uq%apx+9;cg>~K>z{njMdw|!E>U{Sx^jOjv|fU>)B7#yd{fO;pXwsVQHjQ5mJ5Ka z`07>R-l@D=rt+WPJC(0F=65et{$P~{m5-ee<1GFu(y7@UDOUZ&oI?+@HD#a=SAPQk zP!vhEoM9YWo^KS3UPl}6X5Gt#z3Ng2^g^>^ooCcEColar(z*1*$dpFB58t5BesT6u z+ytjdlPG^g$G@oHH?}uDtoMXv9>R#)B(QjI~z9|Lu16$ZJ=eu1*-q)qSWUw ztEIl_NvZR`lPPuohCYX%Ydl-B{C!>VwdRNa>1_A=C?}wI4*NZ1c!$}`Wx$`=;1RVe zIsQ1$fnQPsgN73ZmFyLZ3wgc84u>MeRD^Z-F7i3xP*}tC`m-e&9}o_iSMGgI^nk&I zLvw>%^jm?$cJZ%YaJY$vBaQRin=NVh9cfM#e^b?xhJ#*r)`5bHd(WvV3sG8(dGuM; z_CoVSEhwh$$~A!~C{ghI*fpTwwV>dIT8V;R0R6PYpj%)^Jprh?pJRv zCknpj9B!)Dfq(S_1^=2;@TJRJQ1BS17C2S}92*84+a}}KY{Icsysi64IHm!P4VQ3C z;5Zg4;~4dU*x@7e1L4@I;?pibE-E*iJ9L+rn@I~-XD$Humyj#q?L>n=5r<;nkLBm#G zzddxj`F^|<9shY%$Uj#8^Os^1#f#!JkEomN;)NRm_-UnmM{E`1cmAZbsjyWnM2mK; zh;+XHC$uOedp^CQggEo%KQZ0#UQ8?~ilqH&=Z+L6-scsSKhEs!!yFN4YqTn)erVMr zQNw(wRi8f`(=f1}w294LJ{?^xI}{@yE!zQenweU5XfJRqha(RyrIzLGinf;8^?|Zb zSF465j6HNA>&3k~ZzJyZVJcnTWkHO&teUl#T9mKLH^8awi;+tFw7BO@mB0ViqWn>qf8*cu8(2&yY=l_I zkpxHAer(T~4zc;MzU5AJBguQT?RRz3G)=oE%X@BYaHe)apPxgYzx$Jdu|hoB`*5EG z>@{ZX_yD@{s{AVOZut6YJHEU->`*0K$a;|6ng^76$7XZYaPB0M!pu{Ip9USHar!wh%}1rw7W!fW7SVrQQ6uuj+uBm?OXT z4xO|-Ml9SE>8D+Rb*wY-GFApuCz@B@WF>rF>FMvMj#!D6!8<(UmSK-EqP|Pj z(rB+g#y~EF@pa@1`LQ?=mv4U6x1sao-ki@ZX5p*EVP{!rL!Zgvt3nTp zVP}Cg8UZ63GBZ!g}t)x1u795wqq3hiJ!Vpa|MoLaxjrhoez zTJy3i?H!3-g$N(zekZ|KVA?TDhgFElv8!b;0~6h_xMus7`Q zBa9Sc+e_ddfhtXEqm5qfg6x@qfM`)1yY47(Zyu6MV zn6KT=tqLtvk5k9)siHdp{`@v!w@Sho z)xP}romEt$(Z{Gx;~FRMyC^vhOpOs70kt?&dE>=*3miq=S@6Dy1C-8j_3VqfNmqq! zyBxTcu2bqIt?q~s=bW@P`^z0G_6XxD!s;S$Zj*Aq6dU0k1IQm{T!Z zaUTxWX&bsTf-q43H@sVb{e-^QPw0PxHB8z%wa>KCh0#+9R`E;~Gdq0!gxF_3f9qqM zn#dab{lLWzbq_CHV?yMulEOnRPG$%lN*!J0lNoESd-ud0#m<%Qv3XqsH&@>7x8Xw8 z6X$h)YSm6i*OF) zO*++r6B-4dmmP*g_6pt$>uuI)dokVWVa%azYL4DFuiV^0+wF%u+z%A#RAYxsd-6qd zeU-*s=a%eT#4z58Hf$o^g8@FrhcH{8{6 zcwlLadFkN+=2yK3IA}*I#=N+8fTJju@5M!|tSo-=b=mtj!Ut_AjQ~HS%nCe9LRI2KN&!hqTI9Xj*&jw(i;$ zzV_d%gVq!=#yl%T&LP6uaWQoOM6z5VK{K zF!F&ibNt7uWX^UK#4{Sf+_R&%bJzx);1pBwnu?dUv!fAwen1z{ zNyn-Hrn@?u32_f#kI-DYTZ6s9{M{OL+?ubk&ScAtX6&mtDr=h^wOtY4RG^Cuz&k1V z#%H!!_s`RTqw1cC`&Yb~c-=?P4e!P}`#6s75nl3fbctcJ791)UQ@RROnn?DKb)uya z^0A9AZrj#pk@2RZvPjNT9hXt1j(euw?bBzGX$Qs3j}?qv;^;PCYk8+n3e`I8#TU)_ zXYgXneC$EaEycLN9g|1UE)?RJJd~N&oPj(oKc-|a$&HbI6!t4$Y*262+$eo_!J)E0 zc#G$XSVSRKJmB~2`ff~lIlzcH0rBIg+__a$GGrNXPgeP!b`%w}H$KR?+3zb|+5lF% zBR{s}Afy|(jna4Dtwh4+hc|%gt~-4@QkUL_K-I6`qYPPT#lQrFvtk1FO&Dj=H zjzw?DOwO`dGjjlUKYMt;^Im5)pr&~;Ri#{vcHrtwP(YH#{o7XGVlEdLcXSs4${IV@}gt}oSe{1$Ey)A_& zv1Di4vMCb|a}Yw{&ds#u=vyV6k!zQ|s1$UAIn83%=cHNm8KyaU=qgcN?0(D@Z;;-O zZUVqFm1blU$5LpzB~y=PA_%fgnW+{(mSRn@>2vU5PeJ>;nvq#U&3X=?-kxL1$+d^; z4RiV#hR-2*Da@5buEpK@qea|oOHTG&bnGBhA_ulU!-jT+jZ7$iO<$HPC(nwr*@e+J@PvV+V#MXNMujG$~FFyL>ISGqYHUM>CdB)@FHK)7@_ z9OC_nwrJh=ROf8FyXW!k8ps|vK+)VdKxN4|fELfr$<6W@d#(XOX$XbVOqt0TC1@`x zZV(OR>@4&`67PB!(ggy3B)X^ZjCe^o+1AulOEz-J@F-s%`&2ptWE^nC1we?OZJpiL zd?BUblL@8EN>3MIksXp0I%MdutgxinX1qB|-^rn}Ez0%~*&Zs}VX{3;wuj4h2=WRQ zvxdm|CWnYgA;U+w%1I8zw;?QRxDp;VBuN}j(WUgJ++>0!Ygmi#EIdj@;bKy9h-`EC z@Xg_a&EbR1;e*ZLgU#WC&EXT1h8v{xLu5OY+o_J=n&K^)Lri(!;^-Fc;qL4Cz-NbZIK}+hlC;;8s6oXJR&S9 zbSU?b`XOXQXi`Y1ySwwRS~skyX=swco#(J5 z5wIHEeUdc9Fv1gt(4C zAhSX6T(Eo88FQCZPjXOtUPtLes-xQ-n&fti9_}F??x7y;Fc0@I5BG2n_Xx#}xx?Uc zXLFZa7hb4b7s<`*BEzDv6KQ#TZswCL>XDE+Gt-ur3DO5XCdCGJg9xX-A4n(WcyKnL z{MO7=eX=z<^PwC)C*wK94e0Z%Ice5Ry=X8Pa_zl)gY*L>au6p4oEWFXn1&JGk0skE zDfcGkLNBGK!hp3>IVg%l&@VkVC<6aDBLQ3T^(4;-$;q=@mHwB&*_@kA)Yg=&&obHVdQ%FqS)jOJ29ho5CeE|9O7EG0M|_Fj zLFQ7~ZdL(2#2ibq#D%a{OcHxEf*0P(+szb70jP9VZcb39DZ>KhwM81wAa^pvL9Jx2 zk(V#Ep43Dx>Ib_1Gqg0jB`HQ<)&1qnx`1oy=c81kt56a3-PX~+9 zI;|@#83TpJeyg-C@($u7#zJGqY|Bkg)@Rye)JLk+Y+G(tKP%DvjNCauniOJ&J+Yg! zlyme0i1EW)gm;uR!^`;z|$wXOhfKAEC`jlL>KGqR-C2GH1@S;?ATV@KcmOVEs%a)yEp+yPL zIK^r~jWHI84|f5FX#vB3hDC2cJP8eH?UZ54F{eorj75*RKwf3&sfvE=`ctC87cg~u zS~PToJp^_;*ppy;!Onv14SN~vHrfeb+FP~-HMrD7)P59>vccI|l=}I#(Pv5r{5ENLA5JFJ9df+;i ztv28?mLsTR;9UcQ%veCv(iX7ub*HqX%QB-gafJilTZf^ugMh+8=pE2hNVQw$-LhUZkt1B8 zAFc|z@zw>pG-Xh1YE?a-I{3Phnuf5O8rX&69*u<@f~0ZTvTP}VInA2ojy%JZIg=V+ zSvv($ru2RH`IWeiRx_+C{(o_~IjB+K1(w~y>kV`1^6z1wMw4uA5 zWjO;Oqz8_*?lZkI384q%FhT{Ai%8Xjzh^(v^6h8k8XjZ8Gp^@Q_$3%=U8u-!{Pa)j zU(gTc_z|R^Fi9Vzr{APB&I&&P8eqzyE}S?Q;;IZk78(*BGCW+QDTzg8W$QyleW)RH zDANx{Hc#`k{gOdZ@rRzag6#muCDV7rG=!l5BnZ)uv}MhO{3Z zo@0fK3t3LG>0Kyo!Lo$})8S|Wsk4L8un^6h$clBrO)9*oQ)mDJzM%2$BzUiwe*`bIciKRzqqIglj28F z7v)Ox1=zN-3EB63LK|+dt_I{i%`^{6Kk9WYg5BZs4qmT6X@WDTd0bW$b z09p^*)4CDfAdrv3qrVr)+i%rV6Yv$w^gqP z$%T-b4;9P~+=dqx_cS?i&Xglyx+NtCi(~jJl2?6D5Jo5d(ND2kIc0BGG&z{VPB07v z!imXxhS}ScJXf!$I)DV&vp|!%o3Ix!aW{w&_7o&{c5Y@SCIaq{{)2d(x{)mW`WZr# z`}KoE_UdO4iPu1B6n`)bNV_R3&6Z7kv(y%|5nV1A>kq?MJ10mgiZaa1_b&MwyB~U*jlyT~fXDdMrml z;Ph!W%zmwF=qi>wTwhXcQL@rULBn}h8HP}G;g5MRowlT;GH8V~SHhRp1;}kEBg!2G zDEU*yXgQueRje(4Y6uJhqSSJ^Gq?~+nlm9XvfNQU-hWEjcd23o$G}4-|#-2^{JTgkgE|&WX zJX&rxWF6Ar43|<;acm^`55z>@kK*$_`9<>GEMLHXFkTbyjkW4;`tG&b70IiP8Fr>89BhR|x1H{Nik2I4J^t z^!>!7SpGS2e7wt6@|rj*{s|@S__6x&c1v!u%_G0@)+_>-jfZdnL{mw|CQ-k*KiOET zoz}mmOl))7J^UwHGVPd5-RW$(kTkeH+4!`%uCIv}w6YZ<6ggOyhoUd|R!34FH?PD#cV zCm6E9_H6TD%9;4?U{FuwXHEmH$Yi#ern&Sj5jl(R8;qHg_QtbkTL$|g zbvmb)&(HZC>Me7uij*jj2*3QHw42h7v{&lcr~kYCY2r&k>d~Krk<)X|#Nh0Q+~0(^ zR#~1&iyIAgf2M=@x5-K?*cMvcvUF(0hIWTqNb(3FU#ItcNYrXt#sPr(c2{M~1>lIfW#*BW683YM>8X4V*oYUE^3sPG4Emv* zcWf1YXMO-vVsyxnn{KxN$d>uaq9v)q9x#%B8~ORMSQ0>F;w%kz1SEPIu79eZ{TXSU z0b+yS-Qp0TlHlPbDa&8RL6Zu1`Hjj2{Wi}v13SpCUq7BR)27lcpIb zJi*%?1Ay1flU9(J2OX&IXMf1950-d?B)+%m$HwM@cg4ySTO8Q8;cNrQIrg}6N$5vh zgk2xOcdrz=skA8@C<#$rJO%#*yoziUyEphE_#w`b*1@@%5DMmS84=N~7XJLOBk_a@ zh(sTRXl5{{R!DvUIIojum^29yF>8^RJZDf&jE&-a(VaONm5qIZNGe&*2Yew;)Oo<> zmNUt;7GW9GWL7$ANJl93!PwZ$Oiq%v;j{I@$rcdC3~Q!E@K$s7sI26Dr@;QG0^QeR8Fj*I`niC1iD=28X{Y`pJy@k#s?Cpw8L z;?aY8^a|~^(kV#-lV)MLUbIt9hb2g$nxoIdVGbOcuz|CZ#(-3|j2oCI`B1~It`tgh zycEXwi23$*77kZJ-elKjT1fJ5!W63P1#)D@?wk^jpoA!l#ueXHRpRl=Nit0d7WsGs zggk^YG<}9sLM6UF6=wu8d7bphHVb8np)KuGyCcbC>5d2ljgk}cP}*7Xq7u=1R5m}t zLhUXQ3>=t6<@ol#w4Lmc1m{WRopees#YeN*E$Nb|7$o`3RLv_*Tk z=GB(*?gWhXNiok-^*tC|JEX>($dNyQAlZsEPq_C`F%)RuRH}yrh6F3HhKqjb{r%|1S*zCk{tH{f{dpGhJvzk+5!D=1u11p-NpUf^Q9{lN%i~Le@E>~buy=$ ztQoFE=pQ*E2%(HcEuaLCVa*Hz-^a_6)XO2Y}JH+NQH;zhM@HnQD zYvv6}8_-FVHK*mj6wi`F+aP{eb4cg10H3sj&E*ju7>H>%d+s2>f=wkk0Gjbq&(3?<$EU--}G*QpCLdFCp ziX#}NNV#8V3XpI!*+t8hMnNnfi#*rdy-chT>}H|5kZ6RKe&gDVyGXrxk&-d# z&nY5l!GI^Qf>6n4#3b<@0ZQrV>=tL87kfN*X#QMF*aEyHH*{4f&u**Kp-SismNjRGv9+$X4;)-60=maK%RMu6!}V z05Q;!m{9J^GemW8C^%XFC=R${jA5FTeUMg>)6vl@0xbzpyQP70HnjOo7>xfe@=Z$) zO5Y+KeNp6KI#wX@AFhfj`03`+ID}GDGlEN0NJnXhvuOpXi7}#hCzT=;?1cj%G{HWA-E)ZL1Pw=!!X1II$uQ|Ke}Gxr(LkzCtm}OS!$6pKV0ObOM{htz_~t1;HG+69 zf9T&qnUUBtw;u^QWIyIV9XmeQ3xqiYGoC*18wvBLE$10)i0879*5QxySopVMC|$k$mQeZs82|pP-3E}03)#Rd0ch7KF`Rs+4D4h6Q&u|gnhYq%9 zUE>UfzA&LMkuc+6o`!i2W)4gd%nBIF!}GUltijOv34>w%<1ND$O)wb#4C5L1b;R@h z#v%SBXb;dd%GbM|VT$|MWP@SSB!i*nQ!UemJ#8?kk_?7!CWB#9iotL>89EGbE9uCl z{4=a`TIBEPC#`zXHCYD3O_*nA84L~c4Te*&m3$iW;a*@cB*QEyFc=mtG#Fklbcg#b zF&I|MrWp@#u_+i!s z)+>I>x|GYokl!8tJR|!Z{!~ATD+`+3I8B};Ye2XQ_xb!Md4|7YFf_spc-3H-4nz6i zyj5CWQZ9r8IZ9H-Ns8f=pO!Udo@%|CiGL+VTw{q2iFCVZ(-xh>9LL${0g^==L+sFk=lse$&1&7{S4Zsxd?L|#wSxWbb~R#M8b@Rc^W1i2Dp$#aCmkrKT1bfk`>J8B7iZ}S5hBx zfgWuINxc=!NFqk*ClYQ@fHVO?Hw=4!)GVHn5%1}Q5W}~VLJZHs?gK+M`FR@hbM2=S z<|NIaqfYKK6WkAT79e-UOR?ezcM?uE(wfl2AA8Xr-Z(dfBQi;@nNK>NnW3-N(C*jAU)aCX=w!^2T-+O=*oe`#~r z4U!8cdDmD@%A1n%ZW&(!%ax|ha@=sa(#qf=oy51dnNF&|oQA6xG8rZ%8TZul9dW6x zaxqESprc3p&rS(8Ci_}-5FC_1@L&T4Qq*x%A41B?%BFGs5!k==sVxY zmd@9-vC-?1h+sll;K>xbjrezNG%GNIcj4(ss(dGK5jYpccM5TSC>e^ov|kJSroBVC zC6nYWNXoA*|D+jnIa4%U3^hCtvlM16%mElmb1%P*VZR&~`yh}V;Np@j8@8*ln3XrK zNX$fKB$3*&6oZdN`Cb$7LD(dv^$Brti06vsv5&>~*)nZ>dz6RMMjDp>oC(I<=1N11 zvBac8swC~E5-Y~n$RrJrbs11L=g{nYGcRclflDy<>f79G=-=GjL$>vBE8l(KM~3_; z{C1$*48r&Jhb7Yh`#sqle5kou`6f5{)Av>nv*NeS%}h|Kyzujuf9h60%`g14zw+nv zfBYNd+JFkzQ$IjK85*8+oeK%JWVs9EFSvn*`wY_Klpfs|LI=)i!7U%m(CY`#&-LYU zEb?#pQySXaTlSCQKcS7E6d{`bRBikyoC8gO{~!L`Jmk;wm6r|8%{gI`@eXmj$#0iO zm>H5#_m$lqup-u%N{A`BirP6)x)i%Yi)a$zoAw6X(*5U*30EClI_hX`!Y-n z@>jyB{9S05KYNrJF-n4o{O>+oZ%Se!R|Ky}myOyI2nSO5t|y(eBqD16PymUB-5!zoSPkk(?#in=cFf@t%Gr>HXSq`2ZOV5^m}$t zYG!UwYd_G!bnA@4vIVDkustW4ywa0%Y$iH$3ToASv-x`S#paXEHO=#zSu?xMZsG~X zix7s@u=!N3L4Whpk6#PSZwfl`DxR70{&LeXzvKmf=wH@g@&9v?0u;z^zWgwdNu_9Pw4mY%chNp*yuCyr`rjg zmj5`S`}5|0BSUKb{7A;B6aVu}{Z;1+f8KEV!{irY>c32g&=2f8!x?*Yb>L%fd^6&W zht9vadEjGDwYxMr|Bdguok-ojVubN8z25zF#bdK}INvInn^qk>=Ba;--Cez6<=Op@ zjeYdd7q*A}w!^MlH|tCbJLMhx)9J?&c5Z%sT%^wQ@!x-I>3(WTK-FhIJmz=wk6Dkl z_;>xWLkC;`ernb4Xq5TQkIlBcG$GVK!zqUfZST*6<-TiVypPNv(HneWQ*f&o< z^XQ&uez)Y6m!_pps2jiJhXIdvumrTv%`eKGy+3Yj%KGb5#(y~JY0JUdv7<{-=I3 z_s*KR8$2v`c_Qq_*>+1$v>-L}R;clIm z^6gpv*R9Hb2j!99X}R2b*&cwha$ssm}}Qa+5!WUxuxi^YBMkvir+KLr<6PUjpEWeRK1(UKGl>-yqnp-v_=x_KSI2k;ji8S>NIIci7#5VZ#~IU57mY zrW1@@gz5_XYw+FrN8)(;QLY`yp-5x~%?t^eLmpC?H|%yWDv$3T^0$C1C$WO#Kgvgm zOL;5b6qkM!HzeDK*KMGgFgef`}a1(rF1m#RC z+)6%ogP+3b_b7~%F39u7Em!(cJeHJSdvbf;m4r{FoF|1$ejOWq)5^xwA~#R?lyXGG za;LxNa#&Dpjhv2Dbd++W+}bK91hM{;a_)y)~f&v)@NO8u)4n0iR%=GII51`@e%?=CX?avNVtCKx| zW&v+@Ou~@WHRR2r=U+5&hrVVJ+4}J{i{_JqU{GMD6bj6($BYt(L^s|rylvgOWjMJZ z-{Tr-krzLRgrAa*dW+m-__*LBco3apbwC~5B_2g3NdB03mDx_$V$$~r8Z#HWfHll-XIjk24*>GvLt680(FdXI0+ ztIf1eP2p|9>5rzRaZc?^a}!|Q9SK{>kJ^>P?>1aAuG{dHJaCOegS z2~*)gZAo$P6O!;xE?b~2E-I703C`ck-!x~)ZNvm>4+A{#Q_>YnpKf^NNyamr%5>F7 zCI+721g|Sxo(w(0scCsQkCTN16@1VR`Gq#gMnp;}!OGjDW>F+Qy|ZLLz$LsSyQw^k z1>ujd>8Fz{S3Tdxx6(e8?r-=;JGsL5!W}7p)94RVlq2A#pIjeCxTS&Nb)kD(P3Z<+ z9dKuI)AG2yeAgV5HOCaBT%gpVJ_G`9AEmwSRv%@JMe&eGXoOAuLU>5_1Q-fyYrLTC zgfEpdmU295gMZ5LJ?av|>q5sI5Jo@Bv+cULX`9?P^@w^;b?HkPIV)h_6|6l!_nx7OTRneq;W+TB}p+TT!u5B;`_^KV7uCKDEz4W7&(mE=!(Ek%<%l- zO~rHfFT;krWhgR!cZcncHe5jQ+k%Z49D*$thVuJ$uwhFSdC>3fut@{mqumN9ep|57 zRa6999L%qW4f6u>q2JwM6J6nQpDrYiwqOH)&S8s({p(>HdJnJ-Ay9Z(GHiwP-4<*k z;7{!~8s^u-7IqJ?5r(&bt%$zcf{m`=AlM#<`Sq|3y9d}f3-8%(oHVrs8#LBAY-9c_ zuz`C-KJ>dgz7dAEXtzc5-4<-5nosRE7UtKt8~6s~L%+MjMi|}#wi5bo3pQGB5p3gN zem!jNb8vTujWE0gY>Vl;E!c320f+4gIX>Y0_vc=^%b61f;G5iVcY%#AMp2qsfPqbdA^6Gtq_A}R zeE0WV>)i)&=tt?gp&rSwiBBSagqQ+yQ-0*8IQUjsv*+-qCh*DqV5#h~`>u7DkIwSi z0|lkpOX*v#`$(QbmxJ(Iil_))hTPX1@JXO>Kfra@diA16_{r^|qDe`qLtDHS)sc8a zEez*X_z^>cB7))h+>fx9{J#{5yr~=xBYns}rEG`c|6}ic;G?L{_3@e6$z~I>$uexR zAqiw9hyepmHW3gbMvRCU5fBkEV!()q5hEZ)n=ht_NG%r=M2kuhDW(45Qc9_%mQqBj z)N&E2rBu;Uq+Dt#rIuQ*rTBfG^JgVfqhX!^~AsM865toLW#MsT9PHVnwVF`#XM5ptNey}g*LETJ)P9J?>80+Bscf?JIuw?#H zo@bipyC(^sBk_JQMQ(b#i9brij-Oi%wZBIGgX7gXa^Y`m>{+AkSAvJ)z0IIjTQ7%I#427y%*vbBI3^R%=a%Sb2$Lw zfd?&*C@*{n@#u*sZ86RgK5=m)1H0m z(t4BGZ-Txi2=LTLv9e$3v7_xDgZw~GIODWupSrZ(WcH0M;5R{nr#f6^zuIF*+i!q; zl_#80+OtnxT5mG@O|&m+Mk}{c*&pYzqwODq{76suC)ua2_Us!kkspExPkD?~_Uk-$ zwEYIi*LcDiqrLP~mr|R&{zD&ix2E1OYL)#4j~#9Q804pT!avDAb+u>T*a|*7Kc4Dn zQ1%-=cC`Hl$j|hIGfI2ur!KA6n?@bhMEeOHV3V@Hz+*?-KL+_GPxvRL>~Hkg(e{r)ew`=$lk8Jh zd-jc=p8ot>r|fU@*wOYIAiv2I{z>+!t3CTo&=-XOPkn4u_IG*gX#2+?zugngIPH}` zb!olSaoX|9>Ce9{%Kko&9c{k>@^5;=sjofz)TM1Ev)=@LO%ULzkL}9-VUHbc{}|-= zd%_u~J^R$9^(M1#yo&u^%HDC0Ua#yCPq@}~CZsOS^XkxH4Y0RY*)y!R<4Y}b;xpKz zE*&qKz5TGaU)jqzgFV|5u63OWsY~;c*&DeX{3s-Ns^hS-AM)5?T(zwsi@pYa2oz6s6f66c9y^T7@@$6uKu@@iLrhkl z)TL#T*gpSne0=SmPuwm z3VpI>(+hbtEBgyPcC`Iw$TxYybsS={^i!9XNoIcq^d$_>jaAD25|15iKeQ9$Q%|_o zeJ1#=2?rPPib!bdhf2m9Jy*6}ME%Ze}@YIKWoqS%tnZ*7s$nWrk z>o~+@_NhzDB(uL?q$dgyp7IDQ`+Gfh7+0kKjaGeHUSl%*)TQ~!?AHo?ZCh|pW&dCj z`@0~&&l9e76O-AeE-jPH{(jnTf&@=>lq>s(J$B;h-`%QD%WF(#pSm0{HrTMKE zbckWpLLb)*^tu5#Hh01&93f7EsAHb;FT>*>*_AkVDgX8ZkE?tAWUh)rAmN}c22q#C zM61*<<@*ueqxkMd8LwO*iLbUtV2Sdz0eZAjzK>SoY*b+jfh*L#_LZBy5)bNP7r%k0d7(E+%R*d zgSyD0E>97}#drKS{M*!ye-*!y_Nsxk>R$WDa!5R=i(zN-uO2!+YyNGAPOgO|%fEff zrz6C@(zfT1uw4Cwf*{=M0be~rqgg}@aF{$Z2*X$N(+=ii$DhJX9p@vq?5 z(q0L$Qr+wP3!Ua2);~YNziR0Ctoe7O9sf2dpLPKEC-@gm;vaRjmw!k88~&YW$G@7l zq`i7zle*XWhs|@R9n{sHe+!}Gv*w>Y?#%7ur1B}_ZHz&2(zf=m;56^>T!OCl{40Tu z&+1>O9siaopVk1kB={Fi;vaRj=iiS1hJOX^_*bz{+N%cEs(YP(J(KuHUG4c-4;_KA zWiH?O#XCIY6UPRh^t>%s{_a!$&>s8ZN}NYj*hygM9qEhi2Zdvh@gCGgn!1wp=LOKg za4)Y?+4t(v_Y0LxO%t{KVctM>PhClZ<3Y=yujyLk7tUd{i}SPQ*BIq*#=EVybbb}6 zuo7UUy4U{hjeF60LtUh(%bO=!q8j1G|8J!WIHosC(^iF&#@dsEa|=mCWBY2yZ)*H;mcJeu64N z7VK~JN%OV+WMgIO(sIeL1o{%~FKEa9vUcnz8~;*QGP^o#4fJtiD}B)Uv!osS1;0IA zpYFf3PA^iImrlGdfxblhE84NYtR4H>f3FSd^3sX-Ym(Ss(~kXu1E=fL>DTqZYlFJH zbmDyp^d+W$V>|YjwPQco_>a00ZF=c7N$hWH$9}@RD_ezNfw zb;XS(xmlCM{_%F~7yRyYeLDToB>JflcZ=oxG zpX6o@^dFhPqC-+8R;O#98+e5NF+1AkMm%fjH~7 z0ddy-6o|9#6(G*KSFsL*vkL3?8*r9moqH9|FxG$P;k2<1IuECf^}u;JZLEvU8`t5i#ds`)F-bGd5T4D=I74_wHRBAS zuWrT}LZ8))GlaI=j5CBf+>A4XvTVi~LY_9`jA!!yLpRHiuJ~^aPXB(%7n0Hy@BeG$ z?eyEG_vN2f-*)pYNz=_Aj`DyUz9)Q#B+hW9%*@;B&cOZW1?wLVdA^PE&r|*>HPHwB zT@ilb6#qWUr;Pc}5o3S&yJZ%Rt$ zb8kv*d=@`FZJTj=EGXnkKZVbwUr6&8PG;i&OKK*5F@0#fj<@~JOxw)*f+(iD?td%Y zN$SYwo$Pqti{Avszc=%Fn~m#VH_0ucV9kl({cTKlldUO?-G~!yl?g=^Fe;ct+a}6Y=P_!oO^K|#(4r~UTvBR!?mBh*M9O|`^kIl zr&oSE_V{QYc+d4=>gRniPHp2b?zIixYo92ied4{gop>LDPRcQyYw)zed#(p3yXV7G zhihA_uzySY!+V_`-cy!mlsa+hIJ^&eXx;~K>ayYeIfzGj-Wxdi?H0YCh;>jou1Rr z*@Gs>$|k!LC%Sb527JMvyZhYJ_elmWzx2{U(c;TTT-!TZ>h_EEbB#;*1<2{Q&A54% zVfMzY9ZH!#t1Na~tiiqM4qhhmGMSf~aWMjBIzE8H|5)JnH1xlv98Ymw@Bc1Hei)zY z;8!*9T@Al0zVRgpTqJ*WobQ6aTQh-;I4$E__|%AuZ>75KaD-I@R|1a$9|Fz}NVL*i zcP{98z!#x)a3@!McVsLu2jTTV2RH}F@1HCNjsYH0;U|FmLF=OiH&9e;fijF8I4vU=pEZ-|o90OUixjQ} z^1CUo0EYkrU0in!a074}ut!+ZJAtGtvR!vQ@FRc zJ=N#P^wcX{2xK{|1XcnM0Qs56ykghw2OI`u_yXWi;7;HqpxYb%0G9#}1DpEDdbSKm zKdR1k#kb*R12=>2U*d{y!_5Wq`!eeleF``W^vu4l+W-GY!9fJG< z>Z1xbmQjnMlI7q3GFiWyfHCma1D69w4wdzG5|D9L0}lfAQGpxFxawZ5=b_78HxFT} zfT+C2Yrp`@Zy5e&0QA}`P(MKHqaHVw;Wq2|1y{;)t58@2q`p}|>RSe6eK`SK4n2=u zh58S4u6EtU2ww#}$aIf(#W()e0E<2L7DC1{d@HoQH?NWQjw=k0k@orlX>Sa09`x-U zi}WL_3T^-&`uf+n?qJ}|8n7Lj4*4kX1nAs}vi-QgZ7A2{btp%Kub%AUKY$^q z4m3dcv*rcu&*Ix;ey;*D-J5}|+wV`6`gA;&g=JihDhH={f4l0RfP+BK2W|rnub292 zfFnRZ2iyRC`dEW|%Q*R()-z!m@(axQz#+ixK-$Wkb3m2%HW)3LFU>e6Q;+1HJ`32;BT-*R4mn^qGTp z4cy)2x;FA=&sU^h#$4%79dIt>4*?l}?)~`27v$#6LwbR$9+0?gzUxi^zsG~n3tR+@ zLhstIqTc}?`kHLlOBc%a+~eO|cRS?X2R=c454-Lj(Bqrozl|GpGy*N-*1zlWTDe4) z?*<_Iu>-&;WgeB-1Goe9Q6T%H?vKgx8V;-l{Ty%sF!pu%99auo0eZwzSznd`=ffX; zRN=-lN>WW#?|M8T>s>vN^=>tgWO_W|pGmEXem z*~nk*x)s1`U?or=3qcPBu^TuUIPlw2-$%eTpjSU5pJQ5H=F8xI+Wtr24+pdAS@}F@ z2Cf2K{+!I0p+M?i2t25j0O^Zm3>u{MG(0cMu^GtrvKqJo^=If>(8$l4@1UOmtq+#9 zWqf>@jz8c^UE$u%C9E|ci{385=|0O@h^B&>z zfNy!qwE$rlhvAW7;|}HjlJrv$xXAwV$eo(M7<|_Atw7etlfc2iL0gdyPd;V97t8oF z9vxCIM8q*+oAg`LYeBRAo&;_LZuqHePnw^IO|PhW{Hh!WH3DlPv=7MqNj!45%XBvY zr-Jzwa4gXMnd{yQf1mp~>Z>2^Vz+$mO$D<5Tn41v2SC<~z%S%DuLlKi|LcK6z*`GsIzCY0dGE?{odRS#Tnl79IRe~;bZy%2x?4au{#KUb`#|!G z56JN#ZrdDnpe&=}X>Gq5a;*0&6s}XaMd2m+l1SA%70PFUu|P2WfXWFw>)?TC}gGwc5{d;M1QbCBIeC?*n@xJoAXm z@0~#Q{~rOz0!RK)mOF06u@>}XO#s73+rGCQ0?qoSkLiDs^>ZJP&yDnBavY%fji8sp zSAB#(kmG4hC*r)nNWXOWTc9ftKj*K=XOAAu|7Rid#4=WI(fRqphq6EUKw-bX$$mlG znpwz~)X?Fd``cRWv!KkuHD<&g0YjH^L6pK@Kkh4(i~-5ONs#dfL7y7O*Isd(Y+Z41xiJKs_6>cpdUw*MPwW!(@I4%?qA8k;$8(4{OCzM>zD)21hiubhra>%7a-{8)r;(4$i z$h0RO4{ido|Jp&s^LSr&sp!AQ=E!)@0oguJJ0flMjsd*{LWhBm0q5kFy3L;Q zEI^oLG#%G|1}yYD@KYbMd{)Q#I{dR@W`3!=)1z0~tvIRe;)(0N;^9}rfMraI^Y;~$ zit$@hH|POxM0Z&)v>!7;uK^J)EEWA(6|je90(;^_I&DkU(yzU}LEyqN z!Fzk0ufxOVmAY#+0o)3j{lG~epTFbXQZas*2R!1DOT29;mF;M~!sEaX;NPLLQui=E z7`*dBO#e|YaGfXeD%@MfUomAN{a#a1DxYIOKDY8NlI?ep!tuadgii;S16Kp50mFk! zUC#a$Ukray-$q|jD&GIL0om^iyA*Q37ph9#fxx4ep?rahFE17S(ZDOv-a$7FhhE@@ zD@(@T-vwkk?Q3MaS_<3+ddiqmF(0w|+EOuIJ+5%b*iyGU z{I9)EhOY&V(?*h@d~Ww0uI>8ANxRj+HPCb7dTGC8JnSL_tv9>i_QYEO zdYy-s@kZaR<7w8&+tqjj$Z`8TV4Y?H*+*K&#j|z1!{D?0`_;?#q($Gl1OEYnGJk7Y zsrwfCiw$=n-_Xw=nJL>#&E2J9eniWEQTRUWvOei!+AP`5wg7t~@E|ZxGl2!7-j>eS z={*HL)0=oyeM#0=9X=K`>)}R)Iy`T7Tl+eEIl^aY!h_*^FpdP>pwPn-w>uEd{zD%_ z@0Ic^fwZp=`^%+b-mU>S8G(C%qP{oE@y!_Ey9kf{AB;1R=DInh?)yM}jA)Ymou)Oi zO-fnNpTIY9ce3iuju+Wm6eX3vw)w?^O)gl`6NJU8Y6sdtt_1c^hYv*IbOpZ|xm z3LO3?PJiHZV7(L-*9u%MW63wQ{JY@Ok57BZ_!+BpeEUJ!k4*sfL%A$mQ0mSBray#n z7jXX9@Lu34uL2mdjGfQx_|Ct{@qxC_x{i6d?`VG0qPF>|<(3J#`WLj^O2{!C+kwpA zjECE%E2iji3g;+XrSLW2YONgD(A>8EdRXF?|1C5Jcl=+W13><_&}@&8Oy|#D(*A7) z-&^l@K-MzWzN-12sQ;teo{z|K9}nySO^v|epF!g*kUx|}e$A3nH-vKB^r#%?y!BYy zezFE}EaSpo>-0?dx@^CjfGiJVDaOqfWS%H>{m>J5QjQbv1vVl4qi@LZL9Yg~zU%H z=iNZ|4ZT*%@&8WXR?yAgl;fvuK(@hSK-S&xDw*&7fqYJlQ8-;8g2d4bdWt51CqVQ4 zeEDjrceg?<;{P_@*FlU1^7;D~a4xXsnYPbCEq^B50(tNF&3RVRb--Fre(U(#o+}me zT6NFMe0oOV5#Sz_+t#%*-2a`n&xwOjU>W&2J~ggx1fTi22gv;Fvrg8hLEn`)e7(%S zX+Y-NLSPiQM$xYUhk_1$Pd+DR0r~!M5LgSW+92~~2at5h_htQB4rD$>U%>x_0c(Kk zftf#${q9~M`*CX{#$QO!@E1$Py!@NMl?b2pBbol3O>!JQ21q^n;M$dC%r4RCYzCk8 zU<0rRa1W5_Ij+$8vCOZrK-RxT;1J+uU?uPrko9%oW+~SQDaZO7NsKr??A1DU@Y zfXrWg>{j$Kg_+w+#X4#qAoH~j$oyQQa2t^ID*b2DPJiHJ(93{qZ-;>o0jIwv=eJG) zxgK4yL)Q28K+2s0a!i)DvsCOW*aKw!ta@GIdZ3U4V$#ldjl7;&F7Ze9x--b*X#OvyP+XN)QMAKO+5VX z%Jx|cB!2_&8DPzCWPjIvzwDPrE1VCEfxl7V`@rWwFZpe$*k3dAfXt`$@5yontIcs7 z;nnc5@^__e)+;|eg#1JJ`or=$)+Q2&!wAP<%9#5H)E~$_bEH(P>n;3asr!*fc>Yo4 zAFv5>1COb3rANkl%Q}g9sM$KdCP97*!d?R=%P$?b`=8OSpkE*C8!Th=16t3b59E8< zE5J(d{C|-+6v+CUcvL`_Wz28Z@uxtJ^?N>$?Pm>eHE{HC*{%;Nob^}Pz7GK>fM4~Y zoVVBud=2!7_(+WlfvndjfeV21{w~vd1ju^0;w0vSfwli=J0F9fq{jis)q^wQ zlDq=c%hDJAi!e-4Tw7e$byC zYx5ivN^lv1@U5Bv+Bq@t{-uKsfF2J$6}d4n9<1&f6YqJi0NIabDevG;k^C_km*} zUwKx{-3UC{3l%>5AjgS}&7zH4Tmn0T*BKR4#)BD_aQOzbP$ z541e}DeJUl{QRKy_rQ5E@f=2QyGOMf6Z^5+6-vTnUt<}k{;chdDV62?n8Lk4_6HvV z87`VA&kpOi}GvAwEPPfNqM0Jyz&vS2e67CjpCx$$r3pMNG^uJO|{w z-T2|MzstB%`a2ZJ^v(vZ1m;!C{$UBQ3iMv!cwp=*^uxefAfIdVfvju06@3CY2lT8F zF){Bx^lDk(w*r}e;gPbuCIB~r&KVUG>q1+B6VQI6*UEey3}pYXWNb`~GdBU5-){ly zfP=4-{lQKk>uuFI*Hj1k^J@t(3futXIC9sGGW{ba#KiM?5AX%>7v3c6`)j~P&_ioc&mq5Z zVodDQYn&7l`w14*!4C`mOqS1;Nw>zt^LZz5FyduQk^TQL;B%lq0P_9bni>=1;~202 z;rd`+S;i$3b^RX!elfyk0fzuLDtbR~2k14o!w&4fe+T*p;OGYVe0&#p9Q@sP$$ZV5 z-uC&zI$|03-=^)H0H1cEGo+nKK++EZ**>-bX|H*vtk<{|$4p!;<4@DHo>SnLAgs^b zG9UK?D?vwR#l$-ECLs5XPMa;;!{mF=9zZX@SGMnUz;{6}YQ*ya>1m!LpX2s@ZJ(oZ zJ>l60wB1VZ>F*RE^XWMt(|8m}fAX4QVx8t8;7HJK0V{#}$oq=4vk1s`a~L=UIC5@G zjNje@&V*kh=1IA&K(?F82hhIZ=iUcpKiPjlOw7Afd=>E^|H?zM9|?a=ju$on_aR>M zLOEUu{2SU0=n25dz->Ujw=8@(=4L|g6D_hI7`#}P>ubO~$Q=ac0#5?HFTOr%Kw)a`F4)Hf5Qje!&V*TYKAm2v^elzAC0Ooy5 zmRkd`2jmt5S^xgG5818@59@r<{=5kP7JwMCTJ}RnfE-7j>DT~ET- z{9Oj5Eq&|<&3-~3dC$bez7+y;&O!<&&I?)4$aSbuI>0ihgTzfGV*=>^Rgb# zU4!}tI=ohnJG318QtUU#N>Sq|9j;OGmqyy>|F%%`mq355XPheIKYfnoAO9};k<<7; zI#2Vp zk8SxIuhjgi;$-}8BQ(FVcbS{VKO9zv)W2$?=8x}R<~FheYQrDXp!s`-m5KMyw*0?N z*L-_;S)1QSN&V|*Y5pGYXQ6)SL-Jp~SM#f@%iMXMau?5ZA#9s`&S%_?OE(?cgO=&% zd#`1s+zRm7DYs3VX;@}pga}N%kYJ}yKnyD&>V*|Z9Ye}aAqn2~0Q)Y=?a6AweafA< z`0e?)rkecy9kg8sc7Wp*!!%4YHLw+TX%UivRNh-fM%q_MrujvTqDmuuA?V#WJ5}Ry zv5}EUen#OVgcP4~S-G3>5bq=Amu1l2r}3ZA<`NR26k(aaTH`O%5Cp@EaJ7sVaaDQJ z1c#U>A)Na725$a2d7_eSn_q?*(~%z08~zrKeU)ka-KIy}SEM{TsyvEncYydULUNDn z7cFou@6G3}Dlwa58EaVY8yRGY(zBN^=!)JA3`$m#HWrf&>)PHeLO_(NjeTu~HMaLE z8Ap^bciC9udOv_5`y$?t?_G!cln-$qux>R2AAs_I=_YV)GxJEGQ2kxD1E*@*Hd5`E z!3o@gs%q7n-AJU|03vKXUp?R_f*Pj016*K+IC`~;0{-c!0M=JEo#tP4 zHRwfVh;K7iQHGILhlo7Wnc`ID3~OJ?o$#~7I%)>q0_DH+=a4>T=A?jtl}^*|{E}gP zVCIl%6@~qin8M>`#tA_e_}?J?S2Krm306_m{|(ZAGjo0*toHQZG7j_!O&1$!bcYMp z!V9!NlQDz57@2meO;*Y-G^8f$1}jjH9FPg0V0CVj@SCj8I^jpRz(lR4Rl+A*omIm9 z{pixInhtlG(SV${I!liW{QZy}*6o^($`sXWx~G2*i{uVX7yB-;fyVK24wRf1B&q!d{jCa>jpL)5H9~C;gO_eLLe7Rr`Ca0X}VIh;$Uq_V*5j?Cq-k&+Mbp4L7q;GpqJ z@pr8}_PwmFqc9k@_FH+Qgx3ZBG+5i5wVRYUMC1y@%`iq{>&MS92e~Up89aPL9ZUZ%Qbx<{f zodT>@Y3wLOnv7hgSU#jqppR#V?BdkNVdhw}hm`34{HJ$+ z{?ofZe|z0uJ~G)qrZ=BEqAT=Y+gm&Y^$zl~s`A=N@_9lro&BdD{U?cl=s*4FKOdzA_Md+ApCqV({inaR|4d{5>2K{n)7XFd(SKeb z_q+OL|=v>tEguhJ5fJ6QArmYo#>MbA>j%-PLnaScrik@-zF;{ zI#EA5(e=m^nR;}hZBpObiKej=^|yASGWF<0RqE5&iTcrrN;(`wC+bHhDm^YpV<+lI zC#q8*QiM)a(mm7I`S{U^O1e0Wov6RH6HQ|$>PIIk9~*8OJ5hgYCz{4i)Zf~Prm++C zw|1gw>_q*oooJem`dT~DG_fPSlT1RLVD^1U7?{#S5w;cF*F_q+OMCleg z(e&!h2>4Gc?-pqH+jOaOW*RE9%_{A`-{;T9*wtA9DZ?p8^EaJsoe$55QyRG2Ev+({SI(`4Gx7obTg4=%nHuAk%pl7PFin z_F;#d4`H~olSYHif^@^^;?y7{?A(YBBHIZfB*&QwA0p1XkjXXDYvGE2w=cg3NWWc- zYhWEZmTLc>eSyp2j?AvV_zHFIiWdG?U*YXYEt{Qa;UD@644q&l%NNu{fNyz&Fc9TdE*Mu23|d&y!v zux^dBm=M82=-hZHlOrQABf(lKSX9iENERN)vP04azZVyx`yL@dDzE+lR@iUv6|(f3 zNtd#G49Ol2S&Y!^VMu*J>SY0@KBp2D5iKM#_dZm}>dsGy9I+$ML_l5@yqT4_C=huY zRV(%Cyg@=ZBf@Svb)?F^P~-=5L5@;nIMNgKHg&WjbCJxRQ0lkWppDrdqecbJ&E*S* zeOG7PUzN*8qdgLa0#|oMIU4qG)ZM`0yawKz$oaI~E-RoRcNZ=x`*5*mAZA)gmo>Z} zjhJa}cq5q~;F5caq1DilHadG7?z_rHn%>pC3XVCO(LM~P3a!m_CNez^rUKDM|B5r#Esh&3PR%>CQZ;?&N#}$;xmzgA;UCfSc)*!>ugmX9x*7c!xJS8`(F32&c~q zoDDZ34_|}WvorpHdlXmx^t-1S>Gvqoj*MsLac_nNB`mJ@fazb(2n#YJaw%-4H+JqL z$dHl3q-2^GLRFTyu-T%3ENL zn*NO9AF(1ww}5_D(SNk^?`)W1q(9$nxR5_)!QVdcFw1QEHp1)3LhqXw3(NaRv%EvRQP2s#9N&mh2Wv)b9e$Ah!e8<7TTmhTGo`46II_jTCTvTNoe8L8(5 zo}^PVp8}&aD}XFz_C0eq$XEtjHj|MZM5bhqvPhwIaZtDZ+tj>R{D}DF-f2WB8jUpG7T@{~!?)m`YiBAfkT_s;M|2;N{t73WU`?_x!j1Z*;H8SH$e-BX2v#YoGJoO#BY2sjs`6(*=TJor%bx+Amn*6|e+G08Q`E@(8PIu! zqQ>OUfX?BH8kauBM;mH`Z`4~ zFe4jK?!oI7jpd%~<)~ZF1Zx8Q@YIM*ydB&dJFh@}VypNqc)vSp>YK36urWX+(!N_ie7~uQcgx~wPRt?l$Ss_oY^z< z2puU!WzIai%Q{&zBRBJb(MyqbWH#K)ELLPj$NkZmXP%FG+kkeu)1VmRMHvQ1|bv{}wJg!r6)hq&#WjcbbY4qA@ic?pdu z)hWQ3IN+QEnKY*qvC^H_(c(Heo1i(v`8f;*o&NOMnTJ$mIkV9QL(Wk+*4Zh62FE#s zxLuqU$cG(F$z$A%g<_1G%McQA9zfh&=Mds{b+T~Hb50>{zVjGl3LI>yF}gW-!)|xy zEAY0^DMonI*@3ucIS<3n9?lqOC~}@g+@8*#keO#YdEoYP9)#pM&Pl{Ac80=}-p&AM z=;JgajpsUpVWq^m3>x}6UxtVM99D(%obN+}>-2-4rOsNUF6LxIf0^?>;+8w_A@2Fk z8;INA!Lp7q!07?`fld^X7dWG#VUTkhBrkO4!iNf{2>LH_-h%bP&QOG3?97IIrL!6u zE^+vq)gjIw5%*H(mxx>CWFppOhCK)D%*TDJV6E^JB4n;FVnr~`yhbEb7N~DT<}Uc{ zbVrEc9DyOz`8u-8a_)gSpVJI;wi83R-}y02q&mMxLLyE+j0T)~Xzk<-MM#G8Z6qX! z`4Rh~Un6?JUXO8c)J_?h))QqP*$AB}qq=Y~$cDlf#+1>DG$YHQKjj)lT9KvjC}oTy zv2E#T#7eo=_b!6ZGDfD1PkR|E^DiBGIVO(dD*p?frqnol!Lo|X$l28(Z|vfOZ+w>c zsA7WiTVX#CSxtkJ6qy$JI=OXZ3xsF=Ppnnsu%UDPYJ0NM%-u3@Ko~ z8$HiLov^dc&UzGf&Ym@~-pJ~eNju%ARzkL~-3j4_-3dv|>gS^~@ah8V!m##gkkT)_ z8V2XHE>t1Hs~{>wR)q=?UcG{n&bmm22(KpJijcu7B%gkEVp=X%A$bhhPR}bSflYJ|-a=2z5<+1UF*f5z5PyFHc7P z9r!3-kn<26_t>wZ5rqnTcR(<^1hp#AIWO>Y#^MO1bAC4O;ZlSXbDi@GB*|glQ()MC zLYbT8S?}Q9Z@-7D9CD^+!wqracqWU3tSnX!{h}8HKRW}>bC`KaU>ykIqj_oS@*HXH z2E;IjMl3-_BM)~4d4;H9m^X`zWy7vkWO3xH$aV8-MV3S^Kn9zmBUEb@x%oFwGR$#V zZ-``+M@}&64cR*db6|w8+UA5X(}FkgNap1rCkEsotje&@qpJR)O_286TXD@a8B-+9 zus@)#0fK99M1GnBLx+Uq5g|$Ev&4ltFVYV!0fc4`xeDVf^S%I+8!16mHou~LFd}cF zI-2uxnMHhAdg*GA4~AaF8?RL~GIBYpfw>@yP0T8)jc~%;{91^`Y!%f-Hq(nmUEUIL z>t$kF6xkp~?&gxbwIWkzMqZ?cf5C$NrS-c?g=t-tYqf%7OY+QzbE@G~9R-7g72FPes=C^Bv6ocr<8Ervw zZd{T+wlTE^0iD)C$FFcBGRkN4!Y+2h%80PYu*|Rzs|AH0p-`=0Hx|EXb{dWdzFa(8 zjlz@g#mdY%f#{}Ld=+{q>w44t3k0~dv9iqVZC=N~zNTD2<%c}^vCbWocpN(VOuq#S z*5{dW;kc#tT)vuGt{LQulhtx(pILWcA*|HwMq#UE%DI0fzsw9jCFr_yN2A=W^UWyV zpi+D@7nHe3GP@PO&5p99mL3+HL6hGSrFpKcn{Oa?-&-1By4bvkP1|azH~RIb?mRO? zylCRG_J@XPYSt*}qUZCX9JMU2;UL_h>%ap$Lw@hR7QQ|GErLOOc={J+Ui3Mi0 z)Sk!o2zsiNuQ6OPACzr6;&pirY|-XY+H0V_hC2)^+l+DAfbNy-XHKReDg0b2#rIM4 zNiCXY_ST}M*P*Ffr-CLwuu5sp>6^cRWQ3=SGzTLN zG+Nh&imlOfSYcbWmsE$9K2gCb;dw4 zM&Mi)XTGGEwZ;Vt3bBh0&K$#OeJ}M@$P9Wyg&joLg-?R8T52$AyB&8QPz<`P4fY2V zy+?%^2)poJAvzAC!+3|FJc|A>wHp#R=mr&*Nzoc1ItHS>aaVvKCc%2q9!AlDDy$Dh zFA$>0|B7dEHyT0XDEg}Jf zLB33=su{$4tEGD2TnIddb0TP2!V}VD3D+9~$#@RuoH+9)#hhXcBx5tqC*#ao#YEj8 zV>ix?appwDtThIbaR}!xh5LA zeuiaFnX*v>bjnUZz=ptu;7MiIbc?4f1B_gp zb8(z`U02CO%7%e42IqI;%yD^=iImlVF$Je|=6c0I$}ZW-CgsR(kDqX6+O{xVPovh! zs^XNepwVE;#7+dKLXzWTs+|#%93$IvShwd3SX-wsr*K*kYXtO(8q2U*I8}|ULxZ8{ z0t79k=tb5&T9jdrwTe!`o74t~?n2N(iVpJ)`iY|7rPvk_=xyQckheMb*dhmUT(@T0 z_<10cEiA_F-`sM(>dnj8o10sP@+pn3FviZ@d?`3Uq`J{=)*B9f)GTZYlQV20O4S;>=oG^ zDUlyrqWWQAxf~-%-%C)ye(ka=g#MRR{NX_x%`auvcU9~w>+y`VSJJ)e8SvCD z^5It6u+R1>HO5nXW*D3YQS15N!4a_04XUz_!O?-nNC6=J_p(k)DC zGn!bd_l@nn5T^86J+~_P#`i`gHN+-0-=3^>xKDWs7r*@iuHJQcAJ*ajfH1KR@54Gg z2@LneI=m0-@RH_ue-k)j9o~m^coK3Q-iLMgtMF76E73lz!;_!}uG0Au*5Q2#>+n9T z!~a=W#KiB7h{!Vob=zp&$HXAH4)4P{{9aIELC}YF_){XPT!;5z9iB|R4)4P{yxIyR z*5Q3vhd(a(avk1>b@)d_e7O$q!#cdAu?|n4xDP|P!XYPPX7M7{;mPvb+#cWA5zAHf zWq}!>x@7 z3Wd2`Wsg#1ILzfLd$c0CT;+qD-{yud=T=m=j1(t;uS^(Wu7ak7JG0>FLOKR?DUmFh zyLivzRJs3+2=i7?m2=dUdUaRU9{OdPnij##P65i3Pnij##P6 z5i3Q+dy9Vjq^4m3b1`$r(~v3t3R2=dV3v7TU`AK;RFnCl7lfOJ-6%5puy9uShG8RmL| zJ+NRZBw1Uyo?u^~G+{k~*8KLL;FI$@x}}g^5n$B`a}B^AtSXsuAikau=6Zr%*-2LU zK$vgy_7Gj?psxWca&7zalmocwDs)|u%?jI<>k0Po9t?*Z{df8y2Z!0y0$ifco7Q01 z4XQ#K;Yb%q-=&u^!o|M^IXx5mvym1!e;Cm_G4rtFTIOk%5s}Lib1IsNX-3lfL@dlZh@j;Sz3-DL*d_0Rk>)oc{)$MG~UOJo|@8G!XN0%Y=-J%WYMcX6L-GKX}?aUmy) z&=cy%z0(X=#{`E5*j)4KZkdIZkS?;1GxE5G7_9D27E9uf^!utXGm%;Fdy*s6#^{Xj zubAemQ)z_#A#mxvmR}HdT8s{>ZvX9B_uE=osF{CWBFm0XSvgiL0#zlj^ zA3>sj>Vo1BGof@vKA-$HxtS)TWyOQ_1j-W#b#8^7+^kNa?&y}o7sJD>3^CQnHu7Z{ z%?c{g4j+JMR;D5Y;h_}HQe;MW0LhRdL*YMAxU(X|hCPC8$M*tl?t|XitZ-l^Z7xL5 zm6hFN z4}23u-i$jY8CeDSyl00X*WtU}4OgsNi&(xXz6F@_=)}j+&mko8(KNc9q{N*)`KU_q zjr(Dl+x;r2wSHtikK)JF%wcS{FEp=X*i89~SP{afoE>a$M;B*)6OWzfZH6^VzX3+4 zf{@)}%arJC)9(VAA;-oeqhbnYR%c08cVqpxz9j2^%b0HLF09!y2`x3<*lw+R3TeS= z8Q1OE1;Be{g=?wp_8f)3tjM~vUIO_;NW$Y4a%N{fQq+mV1qO@MW*aHb;=aclG<#Ff zWXt0Jx-dbrn3xI-42quSG~rDHM5BZk!l{YMsrqhzVcbcwtXrn^Jca1p5j`rV9O}|U zkJM5t!W|ht-LP~xxo6+cWQ~{B`R_9HfX_8^YTWwxLDG7?(aU8ruLzp_KN?D(qU6rF zhTD3piD~hUvn5^KBXsT=-eyQUKNRnud*Sc8%G%mzs_&#SO2zt4T$^I>ow+-KWOql zdT8l2TH%j#&JoqhU!>|$(fG$H*iTv+CX*XbYNvD)1)8R6*|=_88@AGwm73@sGcdi8 zF2{#0V_20t>8jjwC=5@=DN8p?cD5*8hL4xwC|w=S(k*@sd1>N{sr-K-`W-@_YFP?+zi0^J#wjdffF+;q~kXk;P_lfk|1;fl}ERDq04vj9GjU@9~x$ z6?)|w5$FE=Hg_EvkK=XBGAhvq)GJynSH7Yh15+P0%-}O_xo-Q4CVp|^JAKPFUe_9+ zFX`)=%`MkH&z5W7>07Sx8proE{TjzD*FMjdYrN7i7sQrppJ&Up&$HzkuX-mSlk%Uq zoWA9nuX^z<*L>CUZn@^GUXm@>eAR2+a?Mx0_?BzF>UlREf0|c4wdwd%Y`NyE9%o?V zuX^4s*L>9@)BCFD-Ez%WJuzd9y`0=~%~!pbnYU`oHDC24{aLnL`@CDOeFTD}Uya}7qFdl*VY$EBhyB&%=uKrC zOW0rS!~SZyMlAPN`x5q7`x5q7`x5q7`x5q7`>?gD+K2tsj|y7uul8YowdBkF)jsU6eo^q{{%RlgS056z++Xd({%XF4=>63`?63Zf z;LH8hKJ2e<6nweA+UMC{E%#5;+bou=-s#M|k}NtdS?p$zsaMBY^ii-7IyD~3l*kBp z=VXK?!FnC{OoU{;4N5GKYlBb5h3L6QNRW&SO}_&RTdTJS*&i?nsgklB7U&iCBjC%e z)tIYd!gIcZK@CR8Vrw<#s^*H!kXx%USGAj?O|`Web5+j@VY#&$b5%0uBdY0i|+lwcqCM$!tAi^&%J%HDe`40&qmlSjmS(>x`9ns;bSMYQ~BWNLHb}j((vD<6G;oQ?Vy2JtB7q?VjEJ}X+}9~w zl}V*yGfF7;4-C0Xg<#tUccA_b-e(&dMO zw2c%R$FDCyW{2TVP2lzb^+}W+XcW16yG^!Wqd z!(nq2yA4`rB!7zRkvp6*Bgwxo6+4_UBl!jxRHSAk+0-z}qINiAMsf^g)r_Qfhcjj* zy*r#SBYC}O^|sjIj2TI(36pxXhS?zaBzHJtMv@(b*u;YwN!gVs2jVl5Vuv$kBxU80 zEe|u2s%L?|o1mhAGm>xMrkk3Pq^@piMv~!>qyOD+uD_kL0KdY$Jq!&#BNSc*Zhq^| z=U_j76mMdmu=6?pIy6REje-OG+%@S`q463{7hFx}Ja8@N1l|vP&bQGM*v?G$F3$D1 z4>_r5Us0zQu9eO$xHdWGq3L|Z$j*XL&*0ENI$l8{w|2%X)3Bc0XUSsuEqK8zqVx^L z5_uLeg2NRVh=0=t2ylixmGDQq@A&fv?Gxfh{JDB4E&yU_-o7HO>z}g6hBJ6!x$ia!77KkdE5xJipPfB4#bhM(g z3*Ov&9+pcm)Q=P~E+{kNa7QtIo-xoDHy@&k$FT@nh1T}LR#G}C}f%_0W(t|!u z&7Y3`l4Wp`s_H`v1ZhWhJqdD}A_I|4OF`bL$PCfP1sg)o3gJ-X$X;-#hr|jnyvibZ zcZmDStfJh=4wCnTx`jv<7%B9~Z_|hDCy+1o!8rl`_(!I^Dc)4xC_%KZ6xJ(;e#eZM z8_y<@iTA6NXGC6P{?E(&0jeqU<>w?HP-Jf8?oyERqpZsCAoBB{fPAnAYob+D897DG z3o^=uf8)f4x8PS*LDxj~v3@fIE#}^MFg?^h= z3%@}FQ+E2y;4DT!=v<(0AfO%yEwp`JxVH zv7tfo&A22BBT-Tboq|xN$=r|v)PlHp%40%6{3arQ52}vZ4}Pw{77Ql`or39Hjd05- z%m9>|RzV;S-FReR9|U$&8wh17TipY)e%s>VX%&X~NJH)K%0A4BX1)V|eMQ)f&v{Vm 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

OZ8?^C53(?xC@FUaHMikTvpI4k0QU>^|pj+^$ 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 Lxub$( + + .section ".rodata" + SPACEMIT_FIRMWARE_DEFINE esos.elf + +SPACEMIT_FIRMWARE_START + SPACEMIT_FIRMWARE_REF esos.elf +SPACEMIT_FIRMWARE_END diff --git a/bsp/spacemit/k1/rtconfig.h b/bsp/spacemit/k1/rtconfig.h new file mode 100644 index 000000000000..3750fa1296c8 --- /dev/null +++ b/bsp/spacemit/k1/rtconfig.h @@ -0,0 +1,752 @@ +#ifndef RT_CONFIG_H__ +#define RT_CONFIG_H__ + +/* RT-Thread Kernel */ + +/* klibc options */ + +/* rt_vsnprintf options */ + +/* end of rt_vsnprintf options */ + +/* rt_vsscanf options */ + +/* end of rt_vsscanf options */ + +/* rt_memset options */ + +/* end of rt_memset options */ + +/* rt_memcpy options */ + +/* end of rt_memcpy options */ + +/* rt_memmove options */ + +/* end of rt_memmove options */ + +/* rt_memcmp options */ + +/* end of rt_memcmp options */ + +/* rt_strstr options */ + +/* end of rt_strstr options */ + +/* rt_strcasecmp options */ + +/* end of rt_strcasecmp options */ + +/* rt_strncpy options */ + +/* end of rt_strncpy options */ + +/* rt_strcpy options */ + +/* end of rt_strcpy options */ + +/* rt_strncmp options */ + +/* end of rt_strncmp options */ + +/* rt_strcmp options */ + +/* end of rt_strcmp options */ + +/* rt_strlen options */ + +/* end of rt_strlen options */ + +/* rt_strnlen options */ + +/* end of rt_strnlen options */ +/* end of klibc options */ +#define RT_NAME_MAX 24 +#define RT_USING_SMP +#define RT_CPUS_NR 4 +#define RT_ALIGN_SIZE 8 +#define RT_THREAD_PRIORITY_32 +#define RT_THREAD_PRIORITY_MAX 32 +#define RT_TICK_PER_SECOND 100 +#define RT_USING_OVERFLOW_CHECK +#define RT_USING_HOOK +#define RT_HOOK_USING_FUNC_PTR +#define RT_USING_IDLE_HOOK +#define RT_IDLE_HOOK_LIST_SIZE 4 +#define IDLE_THREAD_STACK_SIZE 16384 +#define SYSTEM_THREAD_STACK_SIZE 16384 +#define RT_USING_TIMER_SOFT +#define RT_TIMER_THREAD_PRIO 4 +#define RT_TIMER_THREAD_STACK_SIZE 16384 +#define RT_USING_CPU_USAGE_TRACER +#define RT_CPU_USAGE_CALC_INTERVAL_MS 200 + +/* kservice options */ + +/* end of kservice options */ +#define RT_USING_DEBUG +#define RT_DEBUGING_ASSERT +#define RT_DEBUGING_COLOR +#define RT_DEBUGING_CONTEXT + +/* Inter-Thread communication */ + +#define RT_USING_SEMAPHORE +#define RT_USING_MUTEX +#define RT_USING_EVENT +#define RT_USING_MAILBOX +#define RT_USING_MESSAGEQUEUE +#define RT_USING_SIGNALS +/* end of Inter-Thread communication */ + +/* Memory Management */ + +#define RT_USING_MEMPOOL +#define RT_USING_SLAB +#define RT_USING_MEMHEAP +#define RT_MEMHEAP_FAST_MODE +#define RT_USING_SLAB_AS_HEAP +#define RT_USING_MEMTRACE +#define RT_USING_HEAP +/* end of Memory Management */ +#define RT_USING_DEVICE +#define RT_USING_DEVICE_OPS +#define RT_USING_INTERRUPT_INFO +#define RT_USING_CONSOLE +#define RT_CONSOLEBUF_SIZE 256 +#define RT_CONSOLE_DEVICE_NAME "uart0" +#define RT_USING_CONSOLE_OUTPUT_CTL +#define RT_VER_NUM 0x50300 +#define RT_USING_STDC_ATOMIC +#define RT_BACKTRACE_LEVEL_MAX_NR 32 +/* end of RT-Thread Kernel */ +#define ARCH_TEXT_OFFSET 0x200000 +#define ARCH_RAM_OFFSET 0 +#define ARCH_SECONDARY_CPU_STACK_SIZE 4096 +#define ARCH_HEAP_SIZE 0x4000000 +#define ARCH_INIT_PAGE_SIZE 0x200000 +#define ARCH_CPU_64BIT +#define RT_USING_CACHE +#define RT_USING_HW_ATOMIC +#define RT_USING_CPU_FFS +#define ARCH_MM_MMU +#define ARCH_RISCV +#define ARCH_RISCV_FPU +#define ARCH_RISCV_FPU_D +#define ARCH_RISCV64 + +/* RISC-V Architecture Configuration */ + +#define RT_USING_RISCV_NEW_COMMON +/* end of RISC-V Architecture Configuration */ +#define ARCH_USING_NEW_CTX_SWITCH + +/* RT-Thread Components */ + +#define RT_USING_COMPONENTS_INIT +#define RT_USING_USER_MAIN +#define RT_MAIN_THREAD_STACK_SIZE 16384 +#define RT_MAIN_THREAD_PRIORITY 10 +#define RT_USING_MSH +#define RT_USING_FINSH +#define FINSH_USING_MSH +#define FINSH_THREAD_NAME "tshell" +#define FINSH_THREAD_PRIORITY 20 +#define FINSH_THREAD_STACK_SIZE 16384 +#define FINSH_USING_HISTORY +#define FINSH_HISTORY_LINES 10 +#define FINSH_USING_SYMTAB +#define FINSH_CMD_SIZE 80 +#define MSH_USING_BUILT_IN_COMMANDS +#define FINSH_USING_DESCRIPTION +#define FINSH_ARG_MAX 10 +#define FINSH_USING_OPTION_COMPLETION + +/* DFS: device virtual file system */ + +#define RT_USING_DFS +#define DFS_USING_POSIX +#define DFS_USING_WORKDIR +#define DFS_FD_MAX 32 +#define RT_USING_DFS_V2 +#define RT_USING_DFS_ELMFAT + +/* elm-chan's FatFs, Generic FAT Filesystem Module */ + +#define RT_DFS_ELM_CODE_PAGE 437 +#define RT_DFS_ELM_WORD_ACCESS +#define RT_DFS_ELM_USE_LFN_3 +#define RT_DFS_ELM_USE_LFN 3 +#define RT_DFS_ELM_LFN_UNICODE_0 +#define RT_DFS_ELM_LFN_UNICODE 0 +#define RT_DFS_ELM_MAX_LFN 255 +#define RT_DFS_ELM_DRIVES 2 +#define RT_DFS_ELM_MAX_SECTOR_SIZE 512 +#define RT_DFS_ELM_REENTRANT +#define RT_DFS_ELM_MUTEX_TIMEOUT 3000 +#define RT_DFS_ELM_USE_EXFAT +/* end of elm-chan's FatFs, Generic FAT Filesystem Module */ +#define RT_USING_DFS_DEVFS +#define RT_USING_DFS_ROMFS +/* end of DFS: device virtual file system */ + +/* Device Drivers */ + +#define RT_USING_DM +#define RT_USING_DEVICE_IPC +#define RT_UNAMED_PIPE_NUMBER 64 +#define RT_USING_SYSTEM_WORKQUEUE +#define RT_SYSTEM_WORKQUEUE_STACKSIZE 8192 +#define RT_SYSTEM_WORKQUEUE_PRIORITY 23 +#define RT_USING_SERIAL +#define RT_USING_SERIAL_V1 +#define RT_SERIAL_USING_DMA +#define RT_SERIAL_RB_BUFSZ 64 +#define RT_USING_SERIAL_BYPASS +#define RT_SERIAL_8250 +#define RT_SERIAL_PXA +#define RT_SERIAL_EARLY_SBI +#define RT_USING_ADC +#define RT_USING_ADC_V1 +#define RT_ADC_SPACEMIT_PMIC +#define RT_USING_CLOCK_TIME +#define CLOCK_TIMER_FREQ 0 +#define RT_CLOCK_TIME_SPACEMIT_K1X +#define RT_USING_ETHERNET +#define RT_ETHERNET_K1X_EMAC +#define RT_ETHERNET_K1X_EMAC_PTP +#define RT_USING_I2C +#define RT_USING_I2C_BITOPS +#define RT_I2C_SPACEMIT_K1X +#define RT_USING_PHY_V2 +#define RT_PHY_V2_REALTEK +#define RT_USING_NULL +#define RT_USING_ZERO +#define RT_USING_RANDOM +#define RT_USING_PWM +#define RT_PWM_PXA +#define RT_USING_MTD_NOR +#define RT_USING_MTD_NOR_SPI +#define RT_USING_RTC +#define RT_USING_ALARM +#define RT_ALARM_STACK_SIZE 16384 +#define RT_ALARM_TIMESLICE 5 +#define RT_ALARM_PRIORITY 10 +#define RT_RTC_SPACEMIT_PMIC +#define RT_USING_SDIO +#define RT_SDIO_STACK_SIZE 16384 +#define RT_SDIO_THREAD_PRIORITY 15 +#define RT_MMCSD_STACK_SIZE 16384 +#define RT_MMCSD_THREAD_PRIORITY 22 +#define RT_MMCSD_MAX_PARTITION 16 +#define RT_USING_SDHCI +#define RT_SDIO_SDHCI_SPACEMIT_K1X +#define RT_USING_SPI +#define RT_USING_QSPI +#define RT_USING_SFUD +#define RT_SFUD_USING_SFDP +#define RT_SFUD_USING_FLASH_INFO_TABLE +#define RT_SFUD_USING_QSPI +#define RT_SFUD_SPI_MAX_HZ 50000000 +#define RT_DEBUG_SFUD +#define RT_SPI_K1X_QSPI +#define RT_SPI_K1X +#define RT_USING_WDT +#define RT_WDT_SPACEMIT_WATCHDOG +#define RT_USING_AUDIO +#define RT_AUDIO_REPLAY_MP_BLOCK_SIZE 4096 +#define RT_AUDIO_REPLAY_MP_BLOCK_COUNT 4 +#define RT_AUDIO_RECORD_PIPE_SIZE 8192 +#define RT_AUDIO_SPACEMIT +#define RT_AUDIO_SPACEMIT_CODEC +#define RT_AUDIO_SPACEMIT_CODEC_ES8326 +#define RT_USING_LCD +#define RT_USING_GRAPHIC +#define RT_GRAPHIC_BACKLIGHT +#define RT_GRAPHIC_BACKLIGHT_PWM +#define RT_GRAPHIC_FB +#define RT_GRAPHIC_FB_SPACEMIT +#define RT_GRAPHIC_LOGO +#define RT_GRAPHIC_LOGO_SPACEMIT_CLUT224 +#define RT_GRAPHIC_LOGO_SPACEMIT_CLUT224_PATH "../dm/graphic/logo/logo-spacemit-clut224.ppm" +#define RT_USING_HWCRYPTO +#define RT_HWCRYPTO_DEFAULT_NAME "hwcryto" +#define RT_HWCRYPTO_IV_MAX_SIZE 16 +#define RT_HWCRYPTO_KEYBIT_MAX_SIZE 256 +#define RT_HWCRYPTO_USING_AES +#define RT_HWCRYPTO_USING_AES_ECB +#define RT_HWCRYPTO_USING_AES_CBC +#define RT_HWCRYPTO_USING_RNG +#define RT_HWCRYPTO_SPACEMIT +#define RT_HWCRYPTO_RNG_SPACEMIT +#define RT_USING_PTP +#define RT_USING_LED +#define RT_LED_GPIO +#define RT_USING_INPUT +#define RT_INPUT_POWER +#define RT_INPUT_MISC +#define RT_INPUT_MISC_PWRKEY_SPACEMIT_PMIC +#define RT_USING_MBOX +#define RT_MBOX_K1X +#define RT_USING_RPMSG +#define RT_RPMSG_CHAR_MSG_MAX 64 +#define RT_RPMSG_CHAR_MSG_SIZE_MAX 256 +#define RT_USING_ATA +#define RT_ATA_AHCI +#define RT_ATA_AHCI_PCI +#define RT_USING_NVME +#define RT_USING_NVME_IO_QUEUE 4 +#define RT_NVME_PCI +#define RT_USING_BLK + +/* Partition Types */ + +#define RT_BLK_PARTITION_DFS +#define RT_BLK_PARTITION_EFI +/* end of Partition Types */ +#define RT_USING_SCSI +#define RT_SCSI_SD +#define RT_USING_DVFS +#define RT_USING_DVFS_EVENT +#define RT_USING_DVFS_OPP_RETRY_MAX 10 + +/* DVFS Event Drivers */ + +/* DVFS CPUfreq Drivers */ + +#define RT_DVFS_SPACEMIT_CPUFREQ + +/* DVFS Devfreq Drivers */ + +#define RT_USING_REGULATOR +#define RT_REGULATOR_FIXED +#define RT_REGULATOR_GPIO +#define RT_REGULATOR_SPACEMIT_PMIC +#define RT_USING_RESET +#define RT_RESET_SPACEMIT_K1 + +/* Power Management (PM) Domains device drivers */ + +#define RT_PMDOMAIN_K1X +/* end of Power Management (PM) Domains device drivers */ +#define RT_USING_POWER_RESET +#define RT_POWER_RESET_REBOOT_SPACEMIT +#define RT_USING_THERMAL + +/* Thermal Sensors Drivers */ + +#define RT_THERMAL_K1X + +/* Thermal Cool Drivers */ + +#define RT_THERMAL_COOL_DVFS +#define RT_THERMAL_COOL_PWM_FAN +#define RT_USING_VIRTIO +#define RT_VIRTIO_NET +#define RT_VIRTIO_RPMSG +#define RT_USING_NVMEM +#define RT_NVMEM_SPACEMIT_EFUSE +#define RT_USING_DMA +#define RT_DMA_MMP_PDMA +#define RT_DMA_MMP_PDMA_SUPPORT_64BIT +#define RT_USING_MFD +#define RT_MFD_SYSCON +#define RT_MFD_SPACEMIT_PMIC +#define RT_USING_OFW +#define RT_FDT_EARLYCON_MSG_SIZE 128 +#define RT_USING_OFW_BUS_RANGES_NUMBER 8 +#define RT_USING_PCI +#define RT_PCI_MSI +#define RT_PCI_ENDPOINT +#define RT_PCI_SYS_64BIT +#define RT_PCI_CACHE_LINE_SIZE 8 + +/* PCI Device Drivers */ + +#define RT_PCI_DW +#define RT_PCI_DW_HOST +#define RT_PCI_DW_EP +#define RT_PCI_DW_SPACEMIT_K1X +#define RT_USING_PIC +#define MAX_HANDLERS 1024 +#define RT_PIC_RISCV_INTC +#define RT_PIC_SIFIVE_PLIC +#define RT_USING_PIN +#define RT_PIN_K1X +#define RT_USING_PINCTRL +#define RT_PINCTRL_SINGLE +#define RT_PINCTRL_SPACEMIT_PMIC +#define RT_USING_CLK +#define RT_CLK_SPACEMIT +#define RT_CLK_SPACEMIT_K1X + +/* SoC (System on Chip) Drivers */ + +#define RT_SOC_SPACEMIT_K1X_RPROC +#define RT_SOC_CHIP_MEDIA_JPU +#define RT_SOC_SPACEMIT_V2D +#define RT_SOC_SPACEMIT_K1X_TCM +#define RT_SOC_SPACEMIT_SOCINFO +/* end of SoC (System on Chip) Drivers */ +/* end of Device Drivers */ + +/* C/C++ and POSIX layer */ + +/* ISO-ANSI C layer */ + +/* Timezone and Daylight Saving Time */ + +#define RT_LIBC_USING_LIGHT_TZ_DST +#define RT_LIBC_TZ_DEFAULT_HOUR 8 +#define RT_LIBC_TZ_DEFAULT_MIN 0 +#define RT_LIBC_TZ_DEFAULT_SEC 0 +/* end of Timezone and Daylight Saving Time */ +/* end of ISO-ANSI C layer */ + +/* POSIX (Portable Operating System Interface) layer */ + +#define RT_USING_POSIX_FS +#define RT_USING_POSIX_DEVIO +#define RT_USING_POSIX_STDIO +#define RT_USING_POSIX_POLL +#define RT_USING_POSIX_SELECT +#define RT_USING_POSIX_TERMIOS +#define RT_USING_POSIX_AIO +#define RT_USING_POSIX_DELAY +#define RT_USING_POSIX_CLOCK +#define RT_USING_POSIX_TIMER + +/* Interprocess Communication (IPC) */ + +#define RT_USING_POSIX_PIPE +#define RT_USING_POSIX_PIPE_SIZE 512 + +/* Socket is in the 'Network' category */ + +/* end of Interprocess Communication (IPC) */ +/* end of POSIX (Portable Operating System Interface) layer */ +/* end of C/C++ and POSIX layer */ + +/* Network */ + +#define RT_USING_SAL +#define SAL_INTERNET_CHECK +#define SOCKET_TABLE_STEP_LEN 4 + +/* Docking with protocol stacks */ + +#define SAL_USING_LWIP +/* end of Docking with protocol stacks */ +#define SAL_USING_POSIX +#define RT_USING_NETDEV +#define NETDEV_USING_IFCONFIG +#define NETDEV_USING_PING +#define NETDEV_USING_NETSTAT +#define NETDEV_USING_AUTO_DEFAULT +#define NETDEV_IPV4 1 +#define NETDEV_IPV6 0 +#define RT_USING_LWIP +#define RT_USING_LWIP203 +#define RT_USING_LWIP_VER_NUM 0x20003 +#define RT_LWIP_MEM_ALIGNMENT 4 +#define RT_LWIP_IGMP +#define RT_LWIP_ICMP +#define RT_LWIP_DNS +#define RT_LWIP_DHCP +#define IP_SOF_BROADCAST 1 +#define IP_SOF_BROADCAST_RECV 1 + +/* Static IPv4 Address */ + +#define RT_LWIP_IPADDR "192.168.1.30" +#define RT_LWIP_GWADDR "192.168.1.1" +#define RT_LWIP_MSKADDR "255.255.255.0" +/* end of Static IPv4 Address */ +#define RT_LWIP_UDP +#define RT_LWIP_TCP +#define RT_LWIP_RAW +#define RT_MEMP_NUM_NETCONN 8 +#define RT_LWIP_PBUF_NUM 16 +#define RT_LWIP_RAW_PCB_NUM 4 +#define RT_LWIP_UDP_PCB_NUM 4 +#define RT_LWIP_TCP_PCB_NUM 4 +#define RT_LWIP_TCP_SEG_NUM 40 +#define RT_LWIP_TCP_SND_BUF 8196 +#define RT_LWIP_TCP_WND 8196 +#define RT_LWIP_TCPTHREAD_PRIORITY 10 +#define RT_LWIP_TCPTHREAD_MBOX_SIZE 8 +#define RT_LWIP_TCPTHREAD_STACKSIZE 8192 +#define RT_LWIP_ETHTHREAD_PRIORITY 12 +#define RT_LWIP_ETHTHREAD_STACKSIZE 8192 +#define RT_LWIP_ETHTHREAD_MBOX_SIZE 8 +#define LWIP_NETIF_STATUS_CALLBACK 1 +#define LWIP_NETIF_LINK_CALLBACK 1 +#define RT_LWIP_NETIF_NAMESIZE 6 +#define SO_REUSE 1 +#define LWIP_SO_RCVTIMEO 1 +#define LWIP_SO_SNDTIMEO 1 +#define LWIP_SO_RCVBUF 1 +#define LWIP_SO_LINGER 0 +#define LWIP_NETIF_LOOPBACK 0 +#define RT_LWIP_USING_PING +/* end of Network */ + +/* Memory protection */ + +/* end of Memory protection */ + +/* Utilities */ + +#define RT_USING_RESOURCE_ID +#define RT_USING_ADT +#define RT_USING_ADT_AVL +#define RT_USING_ADT_BITMAP +#define RT_USING_ADT_HASHMAP +#define RT_USING_ADT_REF +/* end of Utilities */ + +/* Memory management */ + +#define RT_PAGE_MPR_SIZE_DYNAMIC +#define RT_PAGE_AFFINITY_BLOCK_SIZE 0x1000 +#define RT_PAGE_MAX_ORDER 11 +#define RT_USING_MEMBLOCK +#define RT_INIT_MEMORY_REGIONS 128 + +/* Debugging */ + +/* end of Debugging */ +/* end of Memory management */ + +/* Using USB legacy version */ + +/* end of Using USB legacy version */ +/* end of RT-Thread Components */ + +/* RT-Thread Utestcases */ + +/* end of RT-Thread Utestcases */ + +/* RT-Thread online packages */ + +/* IoT - internet of things */ + + +/* Wi-Fi */ + +/* Marvell WiFi */ + +/* end of Marvell WiFi */ + +/* Wiced WiFi */ + +/* end of Wiced WiFi */ + +/* CYW43012 WiFi */ + +/* end of CYW43012 WiFi */ + +/* BL808 WiFi */ + +/* end of BL808 WiFi */ + +/* CYW43439 WiFi */ + +/* end of CYW43439 WiFi */ +/* end of Wi-Fi */ + +/* IoT Cloud */ + +/* end of IoT Cloud */ +/* end of IoT - internet of things */ + +/* security packages */ + +/* end of security packages */ + +/* language packages */ + +/* JSON: JavaScript Object Notation, a lightweight data-interchange format */ + +/* end of JSON: JavaScript Object Notation, a lightweight data-interchange format */ + +/* XML: Extensible Markup Language */ + +/* end of XML: Extensible Markup Language */ +/* end of language packages */ + +/* multimedia packages */ + +/* LVGL: powerful and easy-to-use embedded GUI library */ + +/* end of LVGL: powerful and easy-to-use embedded GUI library */ + +/* u8g2: a monochrome graphic library */ + +/* end of u8g2: a monochrome graphic library */ +/* end of multimedia packages */ + +/* tools packages */ + +/* end of tools packages */ + +/* system packages */ + +/* enhanced kernel services */ + +/* end of enhanced kernel services */ + +/* acceleration: Assembly language or algorithmic acceleration packages */ + +/* end of acceleration: Assembly language or algorithmic acceleration packages */ + +/* CMSIS: ARM Cortex-M Microcontroller Software Interface Standard */ + +/* end of CMSIS: ARM Cortex-M Microcontroller Software Interface Standard */ + +/* Micrium: Micrium software products porting for RT-Thread */ + +/* end of Micrium: Micrium software products porting for RT-Thread */ +/* end of system packages */ + +/* peripheral libraries and drivers */ + +/* HAL & SDK Drivers */ + +/* STM32 HAL & SDK Drivers */ + +/* end of STM32 HAL & SDK Drivers */ + +/* Infineon HAL Packages */ + +/* end of Infineon HAL Packages */ + +/* Kendryte SDK */ + +/* end of Kendryte SDK */ + +/* MM32 HAL & SDK Drivers */ + +/* end of MM32 HAL & SDK Drivers */ + +/* WCH HAL & SDK Drivers */ + +/* end of WCH HAL & SDK Drivers */ + +/* AT32 HAL & SDK Drivers */ + +/* end of AT32 HAL & SDK Drivers */ + +/* HC32 DDL Drivers */ + +/* end of HC32 DDL Drivers */ + +/* NXP HAL & SDK Drivers */ + +/* end of NXP HAL & SDK Drivers */ + +/* NUVOTON Drivers */ + +/* end of NUVOTON Drivers */ + +/* GD32 Drivers */ + +/* end of GD32 Drivers */ + +/* HPMicro SDK */ + +/* end of HPMicro SDK */ + +/* FT32 HAL & SDK Drivers */ + +/* end of FT32 HAL & SDK Drivers */ + +/* NOVOSNS Drivers */ + +/* end of NOVOSNS Drivers */ + +/* N32 Drivers */ + +/* end of N32 Drivers */ +/* end of HAL & SDK Drivers */ + +/* sensors drivers */ + +/* end of sensors drivers */ + +/* touch drivers */ + +/* end of touch drivers */ +/* end of peripheral libraries and drivers */ + +/* AI packages */ + +/* end of AI packages */ + +/* Signal Processing and Control Algorithm Packages */ + +/* end of Signal Processing and Control Algorithm Packages */ + +/* miscellaneous packages */ + +/* project laboratory */ + +/* end of project laboratory */ + +/* samples: kernel and components samples */ + +/* end of samples: kernel and components samples */ + +/* entertainment: terminal games and other interesting software packages */ + +/* end of entertainment: terminal games and other interesting software packages */ +/* end of miscellaneous packages */ + +/* Arduino libraries */ + + +/* Projects and Demos */ + +/* end of Projects and Demos */ + +/* Sensors */ + +/* end of Sensors */ + +/* Display */ + +/* end of Display */ + +/* Timing */ + +/* end of Timing */ + +/* Data Processing */ + +/* end of Data Processing */ + +/* Data Storage */ + +/* Communication */ + +/* end of Communication */ + +/* Device Control */ + +/* end of Device Control */ + +/* Other */ + +/* end of Other */ + +/* Signal IO */ + +/* end of Signal IO */ + +/* Uncategorized */ + +/* end of Arduino libraries */ +/* end of RT-Thread online packages */ +#define SOC_SPACEMIT_K1 + +#endif diff --git a/bsp/spacemit/k1/rtconfig.py b/bsp/spacemit/k1/rtconfig.py new file mode 100644 index 000000000000..84932ce28a06 --- /dev/null +++ b/bsp/spacemit/k1/rtconfig.py @@ -0,0 +1,57 @@ +import os + +# toolchains options +ARCH ='risc-v' +CPU ='' +CROSS_TOOL ='gcc' +RISCV_ABI = os.getenv('RTT_RISCV_ABI') + +RTT_ROOT = os.getenv('RTT_ROOT') or os.path.join(os.getcwd(), '..', '..', '..') + +if os.getenv('RTT_CC'): + CROSS_TOOL = os.getenv('RTT_CC') + +if CROSS_TOOL == 'gcc': + PLATFORM = 'gcc' + EXEC_PATH = os.getenv('RTT_EXEC_PATH') or '/usr/bin' +else: + print('Please make sure your toolchains is GNU GCC!') + exit(0) + +BUILD = 'debug' + +if PLATFORM == 'gcc': + # toolchains + PREFIX = os.getenv('RTT_CC_PREFIX') or 'riscv64-unknown-elf-' + CC = PREFIX + 'gcc' + CXX = PREFIX + 'g++' + CPP = PREFIX + 'cpp' + AS = PREFIX + 'gcc' + AR = PREFIX + 'ar' + LINK = PREFIX + 'gcc' + TARGET_EXT = 'elf' + SIZE = PREFIX + 'size' + OBJDUMP = PREFIX + 'objdump' + OBJCPY = PREFIX + 'objcopy' + + DEVICE = ' -mcmodel=medany -march=rv64imafdc ' + if RISCV_ABI: + DEVICE += ' -mabi={} '.format(RISCV_ABI) + # DEVICE = ' -mcpu=spacemit-x60 -march=rv64gc_zba_zbb_zbc_zbs -mabi=lp64d ' + CPPFLAGS= ' -nostdinc -undef -E -P -x assembler-with-cpp' + CFLAGS = DEVICE + '-ffreestanding -flax-vector-conversions -Wall -Wno-cpp -fno-common -ffunction-sections -fdata-sections -fstrict-volatile-bitfields -fdiagnostics-color=always' + AFLAGS = ' -c' + DEVICE + ' -x assembler-with-cpp -D__ASSEMBLY__ ' + LFLAGS = DEVICE + ' -nostartfiles -Wl,--gc-sections,-Map=rtthread.map,-cref,-u,_start -T link.lds' + ' -lsupc++ -lgcc -static' + CPATH = '' + LPATH = '' + + if BUILD == 'debug': + CFLAGS += ' -O0 -ggdb -fvar-tracking ' + AFLAGS += ' -ggdb' + else: + CFLAGS += ' -O2 -Os' + + CXXFLAGS = CFLAGS + +DUMP_ACTION = OBJDUMP + ' -D -S $TARGET > rtthread.asm\n' +POST_ACTION = OBJCPY + ' -O binary $TARGET rtthread.bin\n' + SIZE + ' $TARGET \n'