From 56f7859716b5ab69c7615a65659dd267238ac6c9 Mon Sep 17 00:00:00 2001 From: GuEe-GUI <2991707448@qq.com> Date: Sun, 30 Aug 2026 00:28:40 +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 | 182 + 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/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 + 167 files changed, 53777 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/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..2166defca55e --- /dev/null +++ b/bsp/spacemit/k1/README.md @@ -0,0 +1,182 @@ +[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/drivers/README.md b/bsp/spacemit/k1/drivers/README.md new file mode 100644 index 000000000000..1cb0cab83c43 --- /dev/null +++ b/bsp/spacemit/k1/drivers/README.md @@ -0,0 +1,13 @@ +# K1 Firmware + +`esos.elf` is the SpacemiT K1 RCPU firmware used by the HDMI ADMA service. +It was obtained from `/lib/firmware/esos.elf` in the vendor Bianbu Linux +image and is embedded into `rtthread.bin` by `firmware.S`. + +Validated SHA-256: + +```text +d643349c9705b665b7af438cf8fcd46c1af2ef743f4249155b62ead3efbd8f9f esos.elf +``` + +Confirm the vendor firmware redistribution terms before upstream submission. diff --git a/bsp/spacemit/k1/drivers/SConscript b/bsp/spacemit/k1/drivers/SConscript new file mode 100644 index 000000000000..0022841c24da --- /dev/null +++ b/bsp/spacemit/k1/drivers/SConscript @@ -0,0 +1,11 @@ +# RT-Thread building script for component + +from building import * + +cwd = GetCurrentDir() +src = Glob('*.c') + Glob('*.S') +CPPPATH = [cwd] + +group = DefineGroup('Drivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/spacemit/k1/drivers/board.c b/bsp/spacemit/k1/drivers/board.c new file mode 100644 index 000000000000..bbb3a0f4bdb3 --- /dev/null +++ b/bsp/spacemit/k1/drivers/board.c @@ -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 + */ + +#include +#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 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%0A4BX1)V|eMQ)f&v{Vm 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

OZ8?^C53(?xC@FUaHMikTvpI4k0QU>^|pj+^$ zX`R^+evy0-y|s)f{hm%9I0(80kC@hW2jO$c2cHkR%e+F=az+0|>Bx`Cj(f+|(a4b& z@L^K{m75$g z!29LY$UkTxp0hw5P82>bXAcN8*Qr^yQY&FXw!LIAZbYj)X6S_zxNgbk|Z| zy<*Y$YjW_wH{~n^;&O}EOiH+-h=)LTEoH3&ua|=d-W;^?Wz*VADtsmRAew6#=lxS! zS(k$cj?0lN$3d)iU@eab*T~re0?oCQQ!i8dk%I@GDW||MHxTDoypHDx&kgY}HxTHq zr9Ay(4To~@z#~B$$1Giw7~v_VHHi_Txt1}lI5Q~&+!u5UK51G<>V;1wA4G30<7WN7 zC3)b+pvS;T(>lK;oJu~3-de^b`h98gz$=3u18+2~-cfi{@|^wu)o zP@FeY2KY|UE%>Qv-4rbREcqaMYZ*uM`?=(SF9zL$zcsBr5W?4!52Cl0u~fg8B@etT zXyakidTS_rHu)fWYZ+x2ta+lxd;ZWUT=Dx_)`#tR$13Bh68!2`byx&<$@Jnh5~ULLYr5WTgGrxo^@h}VEef^Na1ru8Hs{37`vdTSZm z*6U$W4jwoq=dJ?cNe5QvE__PP9uR1*r98S$^AI_B;FCccH(I(DLWEmQPaDx(%UGZ| zKS~+kNkO;Z!>094SolctLG;!#-c;ZAR`ze;yFs^L#4qi?5u;GQ=U_z#rw7bQ>T z!;Zg~Bh-_+#?M=hw0#ZiE1EP_{Jv%`*r zFgav^_Xcfj99DLK5zmO;I`zvG=aQ5GULJG{4oqv8y>MUhLG;!#{$KXq2g<8!yYIWm zXvD*WVoF$q5PTm+Dj_nNH>N5kgt92Xlwe9(n2r$)JRaup2qt8T$%J4Y#u!t=!vrgY zPy&QtMIl-WQHY{qLMD__N-3q3QkA8ulu|7gr7TJa)>0|2-_PFr-n$14dK#NPJBhW{ z*5`ZnIcM*4&pr3g@BZ#@s0NgM(tSFQe7Z~zsAR-|_hq(c5ECt-J}-)I$gBdv=yTTR zj3n)WAG~KKDdA)pap5$XB}Ck^3O)W3Z&wuv#-B%WW~rVT$ne4Qu8k9|tu{w|!}}S@ zoMUvU&&G%Wx416hDbxBV!^G3!hvdyM+EktxJ~-L6alL8Xu8JGN56PQj9PQABRfZ29 zcWsDoBN+Ui+^IMn+Y$(v)m zu09hY2Ami%;7Zf_GDKVzen{RNei&Yr+r7oJVp*SHPoj6@({b zmJl(*8tcz%iDP6|fgp2^!nJs@3?E$Px`YQ!>#rz?hr$oZoMXI*qvl1#So9rji_Eq~ zTrSgwZ|R4au$l^;;Kf#%RUq1|qS-fBSLxZ0j41GiYvV$Tt~(mB-E^ms%wJ(f%4REn z@b$ZC+l);)UPO%F^*Pa&Q!~J3W1gvKM&2}TeA=4d^+;Y&j6TikQLTt$u|nW+*Co7c zTJL;{SHcfjRbOF+{7X3>&)K(qn$y*qpEWT@u+w!351H0|m3Solkp1u#=Cn`acoEw& zNaGqDV}rw78&{gvRa0CQe#rKJg>C86`ndIN-Q3HF3-7uv;Q-60-(!daJ$DHi`&Sr8 zpXT&{@*VWt1w87ygrAt!#ap}?e#qGKIOeOoAbfC<>k{rWt-nVp?hijCZ;tVtecPuw z{cNS~W@N;Lh37ENHLWk3#ChR|j6IKIuKLZ37;vF$<0I4h`<&wA@I&(E825f&pDkth z;3L<@+16I??TB-{pOL&d#&hPQPy6;cG5R#8zh7c>YYxxGoWcvPOL)h$ep@2m4L@W* z)nw|*M;uJE2~<7<{r|75s0&T|_X`->h2_s>US9PpUy65cee-|CCE!VejH9>)>g z=N*lEJ@}4m53xkc^iZ|+8K zZ_u{Nhym}qF5%~<^*0N}C*g-rT~}#}Zk5l54_L_Bd{nzd3H3wvA6~Ftz<1$LQ1X(%U$m`8eDRyi5+Vl39t z-VsMXT;aNepPJTRE)nm9A9BXXNB_O`x<{4agO6Mr+pTR^0T+2cBYAU-lYc>P9?0;) zGcubz#HSWe0}=1atO7yi9OcGZ{a8eX58iTZJYmuGLZSG+=}se=d&Kw!#gJJH@wRK@ zHH)Wz_e%UIVng!g7|+==eY#FfSfl$v8FArknKpb+KSZ|;N-xccAIYo&alxQGp%1Ziu1z{$(&Y51Y#Rr~6{b@Fw3eF3{% z8?TzyU)vF{g&&ePkE6fJE#ZTMTpQPz);r_k+VDg2<`~s@vQN5CXZfQW_31-K40znN zv9NqvYS42V8GFt-Q+;Md3^+Gpz(c0>tV=u+en{RNqql9b71C7nSo7VLzsEZRm;RET zSjvbDueml(w~YEXY{eO#-N@*F&`4C@r&+BAm*e&|#yX9?GqweG#kRl;ruCZ}@nZNP z+n;j|Q+as!;3(I|HKw)7#I@mvgR`+rE=lD7K?&&NoOeN=1<92?sL_nX#LLOd9L$o9YJZTavo>Wu{% zabdS><8aHTcag;rp4-US^Eei&PkY3G9T5YbG_40j;s@b}YMqdiWtT z@D;YEPj_c$bw6+}?g`*U*TyZsOg=pk5x1J|G;VWUZEwN-&7p_^kGd}58PobLkJuf4 zNZ!0HBev=%lrns9wCfVSVOsBqi<80+C%dl4QHdN^x=-_QU)%N|whumbUBY3OPyY^` zINWoWkg?~S=hXJR_bcEf*Co7bT5orY_red!n`0bP`R(w*cU_mT+q7<)#k1juceyU%5z~6xT|63oNZuUdMa=1QVw8=)Ibf7K`J3Zq!>{TJDPwGKv+EMRWm@n5 ziu=M3_q(pr6bn>d7(TezbqPC7>z{iU*M}c&a9zhZvrY3aV;u0jYvVj?t9w*&zV|bd zH_z!N_1PRT;I@bXPnp*HW#Z}ZL-OVr{Z(!W9~|h~*kxMp4~iSZ56PQjto;?;4ao4p z4X%xawbg!s-p@$h9OIbQ{@bzs;c=PW*CAG0Ks|O7*T}2_LFOD~vl?%a;e*>=x-Ix$hZF${a{MQ ztirvnjRU`DK?*p;bfuMs3fjjkiP(}-hNM71k|LxkLzhx!E z2lu;nT0H&QMH~>ZA$fC*4sF}A*gm*YrVYPRAa+0@ zMW*#{aEpt>56PTkFhj#)mf#qfB}A;>O=EpQByN^j1!9X;G;>nTO^z(xrxj1ktq~XQ za9zSfruA7@JQ99*)OD4{&X;M>-38)|Rp^FD?5-*hXRV^ynpJ;QCr}wt z;5wN_LCmzq`iFYNSu(3YkUMYx-95U`kl}+5T^m?2|4V z|L^!L@FHTgK4%=s-^}VdZGUIX2keUZfS;Py<5}@e_#tzcx4p^N#O>>RT>N$27s`kW zuevVb8q23o?&4a{T|&m5$8k(;-}Zh5eAjge&ztTl;Dzu*^5z(uRo)UlxZQOLkC@h# zS3DYiNZuTyUFAjLgUei(aHDBmdBsiPhvdyM+EktxJ~-KR2^W~wzicHg3_m1qj`1S) z%OJ%Z9C6_=*Cm`_S`RYC*6>5dp2u-P=YxxJPJowPmvDf!)q70hK<`&V^5z(vQ;vDR z0>0zAgy&3m74UrcA$fBQ&M4>Nd;l-HHkQ9ZTm3Coag6Cs<5<_#R2Db(>260xTzE@n zCt$>izwSZcN|{w4R#`=Jbe#TcI@!sH0x!xqW%Wl~v+(*dLj1_XclSq-J8#dsZ|SXJ z89sPQW>F9ySop32o~ptl$ep89o0feRrKxC6XU|kLThugee2Q2${w7FIf7AZF=K4a+ zH@qw(VS#wZHdKG5Mm!!HS|FH(JoYAI6S-%`A3T!YV%SKUiYCZ26;0NrapTiS(s{TE z($n9x?=8kN37a6#RD5}qzRt-e?S#!T^(){u*Cjk_TK}G-crN^qJxcrPzeOr94j)|R zx`bV(^(jr<7=B3J9Am7?uZ0hecWqo~TJLv@?cs;y%`vL+WS?}|_?t=X>2J2BY1{aE zw*7+`|2ogdmP5L8mT3+OxLsxkC}Q_vD)hJE#XT~sKW$U-Sdho!w<=uV{H7-luw2aZk5@f5sxjn{#h6C zGnrK&$eg1LP~(9zd~k?s;|A0Ew~NKD@Ix}^7%v^rr%)L_I8bH@5&f;P{;^H5MP?NU zGUq78ew8srfdgdL81eLPP|;Puq6&{7caCye*Yz`TZHH%Fm+*;ceY+|?4L`KZ%3A%$ zy}@d)FW_3&#t%*Fua}Ca!Vk%t$I#f{;In_O4JD9*m8bGM8b z@S89uniwegr~{fbX~JN%HmImWr;x`N5@!Aq`<%dD+l1rV2e zKO=c_jB0wb&o;cNXf6}aR5WX(Y25hKxR2kltoXZ{6B%QHYh;SDr5~c(Hck)G#j`T2 zKrjn=^h4Enm<%5rDO2N{1!9?1Xj;VORRx0FIm&ak=t1Rw_Rpi{ie?VF-_c-YM1~h+ zHWtKSOR2vYDGrfY1%fU33S+tXys_kpW-L|f99jBzeYf{7YmCL(1syWx1FmpwJZ)O< z!HQ?X580o2{%-soecF=YgST9lu-)3~4K#6)_bVZJbBy_FyTJPuaFJ`{b<_Iy9mS8r z56PQjw5U8Fd~mR9<6P7F)rdGR{E)mkMsMpwOR~H2KfB^{MYGDTzO4_4G9tr|TstkJ z&eCFk&u(P&c_fF_=SakW$07#2Y+Ap66R(6Hk~hcr?3k|ZGJLT3O*_D@6o>=XSihqc z56ZNeR|*7~bChb^vroEg{LRU+r@xtzJ<7f}MgsS_Ha;?~U*m|6!w(sK&e`N^;`Yq< zgU8XSnCl}h+~~T5yG-j};1PF+A2Rkljs+?&3?E$Vx`b;@>$?(hUHBn+bBs4so)kVf z)pZHynbtRQ;{5PK^5z)BR308aILdVi+f3`PK#CK?56PQjJowvsx+=p5KXYBeA=Xy! zuZTmvUkS;ZW1Lgl^WLw3mt2?do@xDSCF1??L-OVrdsN;VKDgg?3A;_}q9>jWKO}FC zarvl@1{pqh!?kgTwbd5`;%@I}ByW!Kn)-~37;r+wfEP{c?~{p_!Vk%tV_f}PI{Ib! z;76{FW2~+Im1%LT_cM|=$LLa@jS&NGc3r~Drgij-SHcg;n`6A8@}%&=DXvSn-n71+ z5I2M$k~hZ~qVmx2!4a-Y*k)R5Oq>{gNZuUd(h-eWh7VqKUBW@uR{wUMIN1A@ki0p@ z+iLrc_bcGLu1k2qwB9=tFNPnIH^-Qw^3?Fb8Lo{-P3zBsiO0eZ$(v&gQh9Lr;4s%E zoMc+xaf*|}56PQjT-B$?Yw-yZe&o7@1FWr{w2A}0UkS;ZWAF*|E$>&r{jN)R*|gS& zcqROhyg9~;IG_Hj6l1|@o!4c|5nSZjxXZMz4dU+b!#%F6X()!PJR*E>v}@x$(>kw< z^TQ9xoA=9x-_mg?!v{CJHV(D6T?HKG{fy+zF|M7`+r2V;@P^FpV-TGdP_K=M>t$Af zAajl~TaD+)@WJ`6jaN+TFM5hs!w<=vW4!dC?sH`L;6RxY-YgI^t+Bol6lck-0zu{+ z<)eSBZII!EH(i(TscAh35DU*#8eP}>X0YmqSliA54tH(5W?GN)#p~gRN6%{z;O`+wwu=dvbZSxki0p@p?{>iLm57J+_iCp zwbh>`5l4GJBYAU-*VSi2#DEiJwiFNttU`B(;=!r{LFOFg(n+0hWcc7U*T!+yR)2X$ z9Pj;%WX>^WsL#xZ0p~>wc+RxGHxe&~ACfo6xcv|HU8oEnyyx0D&D!eSL~*+JGmi9 z^5z(8RbCf9xWRP^cbL{)nYc6jki0p@Y?bGP56*X8!qukrx|X;m{E)mk#^isXE3ph8 zoG!D~j+kkUbsiFD$*clF<{V}G3H@3}h7Z2s+Sq2%bw4CdGTmt;bB=Lc&*MIdXL9gk z*T&Z@o__Bwj*Hlkyg3HX1vf_wxYczDubS4cJ;ZC_hvdyMsuN@ON%!el$S41Wjtm(w z;HNU1JjBZXk_!D94sn&tDiEu!qWKgzRgI^~hyrK2Hr_C;H`v6F!w<=vM}GdS*0KyA zyzJUI+1hp$aEkXck~hb={m--oGJNo!YvWmqr*F^1a}gVoH^=C0R&B$ZisobLGZoE@ zG>sddvh-=+{HqjWz4pY0*fVgGOp|w|K-{znotnj4RRx0mnfJ}DZuw;R;9Z&R0>nCN ztbff%?37srg4{XE9yQ)8!w2`fF5xGp^_Nz}o8gCK&M{W0ygGbvt?Lr*GOc?}ad-G3 zd2@{6Dvt;s9PPSikL;xO-5Lh|Mq8`XA` z_bcF5*Cp&Wt zZ4rlgKO=c_j7{pZIby(Vu1oliXPep^5z&% z|B3EpE1%fkbqOb$)?Wk_-v~b>Z;o+BF}h{=;5pYN{M@wu)`IvX{E)mk#wL|FhYxOb zUBXkQ_13p|I{c8lImSYj+rtMtT$ixRwB|$H7=B3J9Al`;!@>tgxGv#*)A}8axFGzH zyg9}reMWj5pOfGd*CiZmZS^&TIK=yvki0p@b+!G-`xWpL*Cl*lT7REhd>DR6-W=nk z${&Oeo_1ZrtEP4B7O#aLk~hcLqw?PH!TqjFc*3-PYc0MXen{RN<3(H_X8g~(TFZzF z7szzt+|my*@qeL03ssydvkJsCt7xul_dn9?$%q0U%k1=vm}cR1^Da*J@ZAN1+%I~2 zUc{Wd^gro%l`%FrP^PVUP$2HwX6mOj;yvHY2L*yT$XnBKO<&Z>@WGWbn-j#->s06? zuUL5a?gByX9A%Cg&z0eW^Iey4k!ii>EG`Z|By*0j|9{ZOK^Z=HM5d8kDG;-)vHql| zI9p~F2r}m=53cH{kl}-$xi-FK(e+yxai8f@nrbmWtkG*ED-lBpdK}g z_hnXrAajoL^uN=jT?wDqB2(k;0&&*D>o!k3=i$2x1i5pR_Z8)&3?Dq@x`dyb*4b5j z5`IYL9Ak#cGs6exxHi6LTK`Cpcq06eygA18%Q_>;@WD@98>d-Y9XjH4?`I@$jxkbw zMnw!b#&rp=n${UfycT{)-W=oUCC%!88$PkcbqR-CTm5QN9O3;+NZuUdeZ@E_!v{~f zHhykeb1FUwKO}FCF-7I6;e#_=8{adnITcTYACfo6czRLW^529{Y;kRzWNr17SDftq zjO5KRIu&ER3?JO++W5I?ZHxFM{E)mk#-0CKCkz=r_`tPst+mxRP2xK5XC!ZqaZr5@ zMGSb)IL-OVr=Pu|tl;MMyTpL@gZC3#Yct0a~bBwptXJ5pC2VIx2+qCXh#k1juk{rZt(OYLJ>iGs%`uwoZnm%IcK_h{n68*JA}*Zmx`eAu z>$#b@Cj5}G=W*OWuYD!M2OqgMPPMlBSAE23-p@$h9OJC|oQoLnqU#dgHLV*W@m}~L zd2@^{DsK%R-0r%BXH4s*HL*MVki0oYyUL5g2RmGsaFc1hrzvg@KO}FC(Wdgm@WIKh zOSr(ae)AzN3_m1qj&WblzaGRhF!;!I2`5-v{a!w5 zr{cZvL-OVr@2Gq{eDH+p5}q@y=kDV9@I&(E7^_uY6F%7K+IY;g-r*D94nHJsj`5te z{zHG-HR*x&r;M?|X|7AyVY;h;%fb(ryRJ5&`0&2&TV%w5-L8!jt*t%~iEns6BYE?D zY*(Kh5d-daUBZ*5_17!J55f=0n`2Z1%0B6`@&DlS$FBcNxn;zFdtDp1TE4CVZu8tm z#-4M&b5Cnbh7X=_ZQNn;^!#7k8L=UGbBwM3r*g>f!5yxR$1I-KnD}}!$Q2 z|Dn$(GUCFSu8j|EO!}8e#790pBV*6wc=W&Pxq%EHeB#2PaFc7}d)8L_Ry^VTjO5KR z-umBkuPnm{56WyoBGy?zJueqKWmbV8bB=QNrmjLVeDI;n8YA{tc-=0Gd#msWa_1-? zs_`iqKG^Nr_^E0A23EWien{pVW4p>b!UuP|Hl8%C^Q!nk_#t_7jQJ`r2p?SJx`bOz z>zpWV3qK@pjxk#0GJNng*Cm{5T5qa~^TH3wn`12gUv*8A;e)GO8;4t4ecl#Fc|Rk0 zbBvRpXj^6Y;Az*!c8jMs5yV9i8fbhXV zu1mPswEp!;u_OGDyg9~;IPP9VjQ90y^JF~Vgde&tjW%Yz`z!YM@t2V8&)dTD(diKb z&WsrFJ<~dN#S`I&r;%2y34v0cUtg@YvV|psjdQ!GTmup7W1rfx3?lX zYdt2z2amfh;ry5J>-!;bf$7c?E_7YbM9Xe{%_+UobWV!QVJ@jxHfj0)|*}8`tU>Y<`|zAZLN1?_~3ol z#_`rxe-T)G-TN8In`4~%zOK|VeDJJm<1LG)e{xd19kC&KbBv+tGc01jkr4xaU|N5a zK>RTLki0p@`%iVHli`D>TpI^lTYaA@4)K0Q^5z(G)n{JBfD0oAe9yG5bmEEdL-OVr zxBg#!;*sHlcU>E2TU-4}VR4T4GmTtGha}!}}S@n`7MjfArK!h7Ue+Z9Hi4^zV3x zhaxs4Z;r7|eYQsoxGQ47JErwZRq<~4A$fC*C!g!v85usofE!&KKQrA`z|X@E$(v(LQF&_k;0)J8;9ArAMo3&2en{RNHP{g*R}DgX?^P` zUJpMcZ;tWlztBFE;e+>F8>d-Yefud+_kKq5<`^5)rz>K>%@G6MGOhEecsu-%ygA10 zNAk(=!F#Taoz_;@264UjGmRc0>%g+jR-wF|Bu?#N*+I$>O%~ zL-OVr`@h!KdO(H`9&ug5PfY6^B;E`^yydz&1r~Euo*OHSVtbU+tHrRqJP>T&eueM#&Y; z9qB@CMSE-!>~L-T%(Tu#;^*Oq%tFpOuBEMYybK>~mD%)k=IEBuhWImUs1qpkIz3?F=3 zW`jmN8bXDBpelYYvkJr$t7zu+lfhbzGNQn{u8n&wdRGDWo9;A{IgezX`pl0QusveH z8>aOxwD@uOA$fC*vwx_q^_&bJyy)6E$J**&;S%S1KO=c_j4kT3HDbUW5d)qvt?%2! z?(jqM<`{!i9vnV6OlFgZ*kl#@!cE*PGWLAM7bB;1mjo*;rgHvSI7;)Mv^wWLuOjUs(caFmO@^+l5 z;9b|oR%_c;z&7t^By)~2=Z|V7$?(Aiu7|)*)4KMF>%$K>xUNrImB?|W`*hDbXrxw~ zj2Lj3YvU}-r_;1J+jAQkd(L_Ok7$3$@WD&2jRP#6mYO&)Vng!g7<1HTZp45KA_hEb zTF*1YbK!^N%`v8oXltD+!v|-$HqNrP+7@xP_cM|=$GA0I`&Nbz-j!*EZ0U!XWC3-f zCr*}G1%k{u%8S@D{gtpqMqD_^web_vx{`}G!w(t#iyp`HKdhOQ5f{#OZ7eLGp721= zZDj0UVH{;MPd}WeL@gTofY=r|*mVh~n$~+6;o~>UJ@sp)^DQ3DdC5VJ?Fgn zx{gH|K6po_$-7b@KKYYW=-?G^%B%u$%PN{XqcLhcRz?&!-nH>#(_IDpB>a%fc_ah> zgw7l?d~m31<7jK!Rlw5w8OfVttRJsyj|?B&cZEucQ^iMM1{fgp2^^7!Aqy* zAAU&Q9Anzob%v7RgR^9|HHb$RT=(GOW0_Bu1etS`yFaeYmEnUAT^pxZbiD^4PBqqq;HRebU9)&6{E)mkMw`kL!v`n3F5z6$`XnyS3qK@pjmhKLY5men+#P;M-W=oYKi1azjtn1s&$V&2 zwbgrs;u`N~ByWy!bdP{KT^o;DJpJ_z@mR!$PHY-CzGoW$4x?zS zeY#HcHWJ0?)7|%rh%u*C$A*l#h6`jiBZzt5phAB>L!2+O3d91dXy&lDk*INg6w+f} zbHxuM%J0R@ay`Bs*JOCtwQ-isxIRyavrTsz*&FPMXaCE-7ql&9m4h8z{ioQ;|3eu^ zpH}>1t-H@+?ZKz6jceO{vBGtxJB^*Lt4%CEQlA?U1AgMVgbz*Y+ABT^KO}G72m4gs zA3k`D&GDs}XL!}MakRzLeWF-K zY)IZ5gZ;EVV!(|N1D-dn_dLW4;fLhSG4{Tp`I6y-`&|!#hfM2gB_0VsJnFihk6|hg z4<8)m+PK@aen}wi2|pxn9><}7M>%Bp;M=Z^L#(a-#+x|Q`x(ibV=Pdgg%JZTju`NO zY5l1f@nHBNd2@_=+E4dmU%^MNjq|LnPVVA-?`I@$j!{ia_DT2YxMj`ljd8&JF%Edg zw7w4%?}i^T_MG#K=BGR62%eYe8gsKi-1v8CtjDzC$1bm{HOH9RE7_3cWpdjTJPV9?}s0rbX`qm@pQ88*ejpd;<|(zP3zTY zaZ~sqdGk1qD#kIHZHstZW>;Or=T^~G!Y5S)g3LL}LY3RY2RmFF51H06BOVDqBy*1O z;ZJGyWcXmWYvX)tt1l+R1>Vm{-W+42`fQ3AaI5PQo;0mDMa2)o56PQjj8b`Y_~2OA z#to+Ry@c2men{RNqnxC3lMEjmC)2EU7l;woSPz`Vkus}5kU2+T-QA3}2XDJB;V6sV zRlw1vJ4;CB9AoR0w$^PjeDHuw2_F=QqkozT-N1_{WmbXsz$%&*|5U4{h$yhdbqP0{ z*1sYpZV5jma~=t+_k&n{@RV!g=ce_`O7ThfA$fC*w$=J{Cc_6Oxh~;s(|Tt_oD+UH z*L8i=yrgpf@WFwuOE|%_KAnlJ;fLhS<9N7A=Rp}h__=H2)9>KdkG#dg`#GP9F-v`B zM+`VGV!->Ry9)Rq{E)nP9D`II96mVAwQ+{&t^&>sKO}FCarxVAtyg6D;C0s}9AItr z>|7k^{YpsQ9AmlKuJC>ZT(!v{ZhZS1hN`W273%=;P1 zn`7))(bl?Ch7azM+2Mt_VgdE1@5HMzt3Z%BN7=Mot6GK+Zj-6;%>uE_!gm#LyNAD7 zAjqAg9Q~%wtTKG?xNBpVMc3cY5I36cG?F>Tn7K^*ONI~5b!|Lk@pN7lk3?)p-W=oN zQq8*zAG|8_O_!K%0rkSDI74O?2r}m=yVQ8M3?F>UbqUX#)}57jA^eccImY!4-NDN6 z!B1qC5V6A=>qkZ6PMK98$eg3hRpWUwd~l&_<5kmL1-ur1Nah^l$`Z|k3?KZ+wQ;t! z)pi6|hyf3{F5wB&x(g8B4?iSt zjAs|*+z^($WmRSXY%sI+JHEx&TgB`9**kxKr zp13jmkjyzosq&cc!EvrjIN!AHM#Kf-hvdyMuKk==o(v!S*tKz#wbk`o9PRy#^F=%ren{RNW9rXpK4kddOxMOe)>h|Kaj*9?k~haF)n`n^fa6@3aI$I5 zhd3qtki0p@+5bp$Aj1bQyEcxnw)z+$j`n^=^5z)B)n`P+fTJS@JY!mK1c}|@hvdyM zI_BxzFT)2{x;75AwmM?OVcyS3-W+3?`V5a4a8$&Ai%jcp8i|X;56PQjoc#|qA2NLK zqU#b4v9@|9A`bO_B_wZ-F;i`4dA|bAb!|LjTJs@xhaZwR$Jj7eXHgkGxY@OFy0z6U zl{mxu8OfVteD*W?+#tgTi--X`P3!#|aeeq9d2@`b>US+-z#Fbh_{g-rdJ`XqACfo6 z*sk)9@WI`#jh9X9uWyJ~!Vk%tV=Pm7dHCQe*CpI)TJMdD+rkgYn`5-8JTZK5vTNgF z(|Ye*>IKkTLvz^%L{fy+zG2T+2eGvm5j2Q5mX+4(}uZJI! zH^&&M@~H5^F|JFv$F$BL;@^5z&_e^z%WGJJ50YvXWht6z$WBfOuHyg9~9^_dkh z;M|A-*PGVAB_M7HKO}FCF-YaX;e*3m8>gGrS{G-8ACfo6STtM5wG1Cz?%FuO+Uhf= zIMDkU$(v&w{}0+)-<9Em@4GJHLW`&0Mv3hnyM*M;FG`${A8d798m+C~z7hL-zY>x+$2kAf`lKYo2QRxW;aH2O_h-e|A~qy%jB zcX+=7?si?mv!?aFns_e!ki0p@a+Ozv53Y7y!mXxt+=|=656PQjj92;f@WEEsCG0S* z&ko|U@I&(E7;Q6k?91@M$uiwdZRv-2%^K@ZB8lTP9vFfjMvp?Ld1X*BL>`OT5m*%`@;{(n_~=Bd06=12-hVXXIg(-T^t{NNZuUd z{tP|&k>P`nT$gaLwbie*#3A0VgyhXJE~@P%?^nPpu1k2=v|ck2?}ZNcp?0dygA0Ge_wYUGJJ5X%s#v!TCB0Y9uf!0tO7yi9A(>dtvwk&xXZP1 zghkiAkT}wGr;*G##+hlluFLSj^D;|_*kS?ogCKFM%qkFM&QaE>aiJd6$(&=1Qh9Xv;8@qjHKz4>N?aR$NZuUd^M6lIOJ(?sUSGZ>jxenm5l4m}k~hcb zR{ygR172`l!pEldPfv=Ug&&eP$2g+$(eS}{T$k{)X}!`co(VrBZ;r85_@d2@{2D(?v& z+~>N4r%h|Wh-bnN$(v)$QF(6o;C$D{ou>6mU~yOYA$fC**HxYnKG^2EgtJWREe3IR z_#t_7jDac-3LhNex`g9Q>zpc%4?iStj`7)_*4mZfgHK(Tu*KTyG$ao2ekCMtj=?u0 zA9}w6o_1ZrN2YbhEj|uEByWx}vQx*Q3?Cfh+W5${Vu+8!4?lBVJt`@#{srBQ%7_7P zxHb;Awz@kMM|eLYdGk0vS*JT>89w-_YvW~$r#pY~O2mfb%`xVy&w_{n7ex$s!?eCo z6+aF?ByWy!_ZM^xlHr37T^r|GTfK89&hvgo^5z)t{yDwhCc_6$x;B1l@$~MWcqd{* z^5z&fSL>;T3?IDXx`gjoJpF=BJnpeeNZuUdL$y8S{R()-bqPN<@6d69a-?i~` z)B46vd=h^6)OEd1&;2L5%F2iVFS$1EvbK7=MBMHDjO5MZ*r`6dA_m+WF<`f8{q0Zj zZ1^F0bByIGuLvJp<+_C1O?MS=NBALmbBt2uG2w%+xh`RcY2E3H%fb)In`3Yse;&sn zeCoP{qpYo-35%n>UkS;ZWAy*7&Q~&gaFA=`6w`WFR-77sIL&pvU-oR)Jj#dx_q#S0 z)>hAAq4zVAH;-fYCS6}-_~3q--83O~T0mVK#N9HhK#(~{Ik8cn^e{-Vx^GJNok>k^K#wpy*?Xzy1-^5z)h)%JDoSHL#c z#*aDu(tYyDYkk)BYE>UR;kbGhym9|4EVn3t^%G6KO}FCvHvYC zNf|zP#I;fLhSF%JAyo$6%x;8EAc$<|iiUx-t@pOL&d#;#x2 z$zO&KzUA7u&*JH6inu>wL-OVr=f0;q2pK+jNoFTK#10Fnw+6(WGOIw4IY;SG<7F~@ zaHVTww`tu&h-bqO$(&;hPdx=)eegEM5d6A@=EpdMq2=VVraAajoL#tyv; zCc_7(x;9R-==#a5IN5Zkk<2;9N57^|EHZrXrt1>6S-h?SPW0F%ByWx}?N@cKkl}-~ zTpO=hJbiZ{Uia8W^5z(4w`pT#_~1p?#wiw0cX#5{hz-e`W6V{bc@YCHj2Q5YX?@2f zc84F5H^;cKRi9X7_~0$q#@W_Z@5qRAyq}T0ImSHonIAD=d&Gd(P3!wy@uToV^5z(K zep%;H89w;HwQ-KM)vq$ex!%u6-W+4M`s|4qa9_lLw@vG>?uws=ACfo67^(88@WC;z zjXO>2K2_Wmen{RN<2l!d01j_`gZByWy!Ty5X=eg!p8c0FZ__aImRlLSBDR-bzQ=@P3xN> z@tyF)*CkwGT6bmQ%J4(-=5ahepgRQ_KKN8-dj_%TAQk%C8{%e} zRUo!lMYBc@s_`KiQQ$Gx#)qc$`xNm}_#v6|NH+fs#g*ZM+hukFM(nr7`sYK$12U^X zkU2+LvtM&5!w1*PtTAGvh1W~!;-)G*g4{XEjlZrnFT)3Kxi+q{=z1+oTy473Nah@4 zm-_6E81Su#0k50Zxk&sd{E)mk#zvJlg%56VUBVrvbt@w73_m1qjxkZ?H^K)eyDs4d z(|W&L>aE5E+xx@JNFA<36O?MhExUP?y@#^z>#DJ}?OE}52uHE9~@I&(E zam@Rhy3WY(!FJci*Q~8RABy9=pOL&d#%&!#pT=)u_w6@EzG9HW|;?2|4Ve~)WK@;AqS)3)&`MxQT$k_z)B5|a;)mgfr(9RNpjfAJXZYX-*CpI- zTE9IM_kpqBUK(1J~+m83D=m`x6|U<@I&(E7?b|C&e<}2aGK1n{D|S!ShsfK z2$@wN$eg2m{7A7&BXsKO)2ouiCVgs~9?j(2T*Y+B!Pi=Txb zk~zm%aYT1+GJJ52YvX8Zt7lze>HUo4%`vL^%|7X}@&As`W&bM0_@N(n&HOjVfc8tD z#?hwrFfrB#oaDNM%S`Ld0daZwA!{nHg$KGfdKmXd@UiO>PO!FmzAUzSzY>x+$Kd|z zqW3G{W!ELVXIl4l;{EVL^5z)5&4&)rE&ZB`W}!Y)(ad1exbgLMR`0#7k;)hyeB`=> z6aEf<&4}1)y0e6BuB-ILbhVw~{R%i+W`joDu?qckSiDlX^O4y z>e;%C7;vY|W&|7`tSX}r%w$seDIWO<7SJl_ie;2raO&f&N1d3 z*B!MCA6y_)!tMg`o(0sO5*JU%tO7yi9Hkmj_F3bmqM6udDw^$S8aKXY8h?c-!!_^` zGR6W&xi-!+t+!po+2M!GLLPf>BT;?X_?vX(HvmE@?bqR-CKHXZ0BRqEr z8T(flN1xW%LFGH-xeIvIbqPNjs8vfpa00e82IYps$8+9So|CP zmps#M&==diRJ7K8f28=@_v=ExVp$cd;ZUuVBf52Q^OxEzVX|yZ!UiO^*{RCMej}PUSBJI`K!fD;hT(0Dp|2#@e7Sy z^Mhn>ZCi?6#fGBU!j|HDJ<9!xI&2euQ6t}MWIb{HisVhQqiS2RUy&l!^2=*epQ_!Dn$gq)Yg~1*##PT|Mm;I6y06+N+z3uODvO)s>Aab^Y=cQjf3c`-QC-qMQT2|NW8Qwf|2WJEqS4 zhogou{c~-DO(~wqp6F<#J-Ecth zm-{%GDM~Gy9Dlx%_2x9LFYJgGoo+T2qwC2?lkl}-_jflIBYW1SamR$$U7IXlWrwCj zEuN?j)KYBJDR5*e+dxuzW53T;+GXQ?NJr`rD7AKK13T=J&|e9Uw)o$`u4Jm z>Lv8DCjZOF@Cq$@Ux-Va9KFnUowi?5H|(WDI_8sX8rFS#UG4Qz+Utp>zL+%O>JDFR zyLvgj)tlPuaMM=zF6-{im{P-fc)cFIb>9{pvfu4-%+%A=gsodQt}nED_Lilk;CAWt z!&R4xz27cNS)O;;$f6w^~-y(66X3gXuo$E6Cov_3r(`LQe;4 zI<)!~_3(Ol(-B!m>d~M+PMfVteZFvw%XfcOk9??PUDfv(TQBFK+LdneddS|c8BOr| zB9j(IQ(JF!MmLSm@znezcH#lx%BY2HU1`NFT<#JSc{_WD*jj< zEiKC?K-wwwHLt0y_hPSozkL3_Y-mk}I)CG;lYXhI4xfgWR$$XNHT?1|>?Lo#2AXhn zt1r1e_OemExYEFq{PKo%_GUnJhjautwe@OfTy?U>)yu@xt$KVst-Vd(`uy_Td-i(J zUvkf0A3VJrG-<=q&Td9f@1-6M>v?G!rX;<~dZbOCbhBR94vfzpo6{Xe)1#L;s>d=w zcO}za-CZ=FjhcS-kQ!ILWsR$z?#5MjY$<;IyWi_^SN=Vn0eZU&?rug0PH zXdjo?R}->N;~1>ITr(Ra)Dk~oPQL0A|vT=JodW4k~kM`0Js(R%|`*wNzYJVNj zn6Jxp9=-gMKeeN{P+OtLiEPjslZ(MRnLV}J6i@AN4A!93v|3w|EUPiHuN7OW zm=xJs)q+w3Q*vC4VU|F>$)Sy}p>2~Lk#&O5S@=Y+#=42sbx#_an)wf}H9Gx=b#9NASsC z3Rq=oP%So{;Hz~eFH4LiB`?EVXL9i&;hKA^HKw-J@=BM8*VKKE#b3nEZL>c0RN$s+wu1CZ9!H=f;=IyauQ@kUf_7xo}JsxR1 zRhyyKW(inevYx6|6=#}jDe(C96^6boR@*T^80-xJp$6zdwLhq&M5Mg`RBSU>$7Er; z$$I~>_Hb+BfTykRcP?rk@7Y`~t9B`_k7U(@%FXqIO1z)Q@`K6^Uwlx>8r&t*EfL^Y zeVM6h9#oE(Yqhml3TW|#$z&PMv^ERDPLuUyE>m%%xjMi;ll5d0f1;Qxs zpws5GSAR)QeJK$s-4QKTak;sctQ9txTuP2Oma1tY@Jg#)3yzwsXZ^T}OjUZ?gzE!Y zi}odtBGDgOlZD`n>}$pMst1)6nQslPns$F$tqDI|jp02txL}Ry9ZJ88=BjrnLnE0^ zXyCd`Uwx41F#4{QH|myaydR>45PF@Dmm9nrrDp;d7Jq+9Dcm ztu5eb>jl6y#4jB6md=oChYfuxp!N$}$^~GVwOIs?nXJ#Rn^kCRAcTzoi#y_OJ*P}OB+54lsK6(eqP1dg4E7;^%QLuyOcJGP)k8ZvN5NQ$4yKr|Qx3ZCu_TU5``s=&3diuSeJ8 zP<=Iyq4N9qwY_@Q*`~32JKz4Q-DAz`F&odrnSWf*IvJn0^Kx!CAdMS6sw(TInSSr4 z@=57SsmylGuC`0<*^cpPJ93^$*3WO|(KD*Dwu3yrpS_;AD=n^aDyu(p zGQBFN*9kt;JWNw;o%;Y&qVp!%PP-QnTwX9)G1L|?UFl)N=ZeJa=+LSrNw)^o{76<) zBU#OgBte-Fb(>HJtv?|Xbe08O2sWEsbVxYrvYHoNQtrr8+DI2o7s#RWE@08CLACbf zCF>B&x)3ls@>YvoZCU4|Z37pLi6x}LR(tD-hQ%JzfeJcIb}*Kw?yYu@8mv*Oqc(uW z=LB|)yw(2ExwaWVN41yKV3yh)u(nIj3Z;$ZO~%5KR)cCRixhOT#b3f+S!8|cGvZ4s zk{~~@trGGfdw6VI{=m(#x7s2u9;2?WS-$!l-l{G1W%A9Nl0MDftd3WGKzXdLKB3F# z?#pCZHQYh!!^uI5i1}hsr0Xt+);M$3b3I2zc6i$4g|(}`#%+^pm$j;|KeSqAuB9sl zTBOtdCKb1PE&V)0efFk&P4vtTr7JZ2m%3fKDU&YeIMGyV@rGOvtyR5IT>m&e(jD6qTy_jB9VT$ZXvKn&?ybUc&iKIkt_3Xo zm-Rd^ecYhMUTg6tpv5b+$X`cu0I#(+9pI$NdY$i3@tC=mfGZ~J(G!2MxfU-MR-0Tx z82Y8j*rwu6b1mF295MMO5#vNtZ4+T=tWzS`E#tddo}{8LSXF(tVK|?gs~*yA6(4&m zK&?Mi%^x4G$$Q@#)yw2#6(5?b-uAO9eq^rt4)l_Wbk?SUM>1Z0;GrsdkS3Uyt2U{O zX2PrbY75V)9m&#Jh^Dcdt5)>fW4--80=>`5exHOsn(EP4Q$6~BO!eqHsUH2(2aL|+ zqgPnjtO~;X-Zb0PDA$5MH~ys%4t?%E+wFOM%E?K{#9WZPCif=LY3+@GsTwZY7y}%Za zW*FXcH(-l&zHOGlx7ZR!svLj;sR1beu?1f9pX;_;rW|i+KYwWZ`difyndA)?|Jz`b z?3LozifPlve*G|o9kL(Q6iyjCJhCEpfr^r}yM=u&j|j(IlI@U9P<@^rp-^OKDSp*fE5jUYtJllbZm;UAQ4Ui(M#}c_R^VX@ zvt_Y&el6F1pu%ru$7K~5c-=dPeNC0R!v=4d{0{JGSjzY|n|CRA*W`BqNz@HobT1$i zGYOeKwEz!Heg`~qFJNB#72g3|oFSC2VW_Ky8(9bLN z%`y`<#^SewR@p21iI6S2HWhsP+S$H4GOc$8_s}IHdfi6U4#rr*WsGQp$@XSM?TqM{ zdl?ZYKm}_?w5*zIc0ijNGChRq4830TWwZ(qTI+9*u-D~rg*<6tJF2k6sN&AmV0}q# zvL#jJY0<@(6JnLCDwCI-{fZS;>grrcZW8w^e!j|IEkwq`3a_G6JEAJHQ{I&^vTEH| zbsPiC3w3M=TY;{&rfT=>7IBBENqa+KB>~%_dw)POdBH9Ba_mgDv*)tu!akSatjR@> zgi*?^W2RM@YQy-(Vc2fE^>Bx{HS~6oO{q5NjC8u`?fy{T>R9F_V5P~Ws{|iqM>V@T zRW>_zX*IDrG8p?s?*^{R2I{%iPrlk!{ESYRlyAreXx;wISYA=4^s$T=R=%q;nvHK- zFbAV#InGR#Ps)_>jBwxO1Az(A4ICI|8@F_%z}%>9Gexa7MKj$!OJKItg2`Iua=EZk z#;0A#9I8b#h2J>LGCtvMcKj)qz$do80X?aG{zRsE1BK>UM-&)r@>{^?xV@RwlkMhwah^kj1@4@syo=%Q(R6L7P#ctD{KHA9DCzk zf(a%UHY=>Y^ge8I5_FtJS~5|X=92gynq2r$ATWc1rA7VbSm8C3OMvJ4W|OPF`h2Qf zb1c-)-V)lZj}6LqYyB~bK~3_UV3BNC@hin&EJl8>7_I;BLh=&;YR<`iBG+2OUoS@g ziazS9{g|rbv{%POH@aMs{mCzM<8AFP=}0GLVUl zGvpgyKlI>Ae?u*FF0S@Eu3hF@3%Kgmk2R_YwIg?0td9C71ROG1PwzSvcbn@Mz)_R+ zDkLE*xibpA3IF-R&TOR z*lDtZF~qvAI?j=6z1M;*GJQ_gqlwXn(H~k>{ZzJF#RukE3ZBTmR`1!v6gf?PO(!_* zDy@ja6xo%j6-CzbpuA`6YjIC+HA?bckmDRHM^{7YeQ6%9hCVj6d+su>vEWDnv+V}4l^rl(=m@VT(@a7_D%BvD(1iegU24(eC@c|hLytw+SS+|U=S zs(zV~;sbYqQHu44e4+WTyhb0!#ZC(McVFTmr>{V6ww`HS4gZ>gJ+Zh;0YQfLh&%1o zU)O5~Rq&{b;9kdaAVY8csx+4r+t>9kRI4X_lSS=q8$@%)i@|8+kekcyj}+g1$qp!z zr4`k!rq4ersJ&^i7XpICd$?8Hmlan>MYS2vyroP3J{<<>zM%@4ene3vP2*p#A;m|B zYPz`f+#}<*da|~5sti3>oG;@6+&4xZMlO_TRe^R{zMYy=M`>=c@NJUmCVjK8!)2AX zscokbEfl+H*iQSM?ydTCs<=U>-P8YY<=i62c6Sb_opfVdxg6S z9_>;XD(mrR7l&`tx7el`GTp+=5mvfnL+-i+jIVxtOW~2%0R~*xHKYF)qn~%i0ym@o zRx|qgj_I@loRKkU(5I(kp87AB@npA4WDlX?c9~9kq`2gg6sv85I=0qxRe!!b7-6d? zW(@NKb*#z+@>7aG>a8YrzuJ8$dqwvfwt6Wr-T}qN@4sRmN>^pE>jo%N-Fl)5Z)C@8 z6&7U&8@MVv)~K*PJF21VQ;y@7XDJ}9p3efGucd6$OX{hs1{iPhJAh%x3ud|(Fczj9 zG7Pl<3_yXwI`;y0fV^OW4Hm9H&|~nT0|VEg=r7o#AF} zPPemYy>Kqa0Qq{C(_FRqs`7S4-6`3x$R`v6MK~zhz8c-Ew zZXE7psHT+l=F_%_0WknAKk~nBK^Fni>v=5L;ajl*Rq|_5Xq*{P+<46zo2hj`?Fi;o7B!Gu`TKd*o@wG z`V?9qFC-CcK$70Fl?gd;Ybs$!K25J=#_5}_6+_hwq@N zGj>9H*_-D;m`iC0Qlet=fy$q5kNJ>yEkV59>FTrN6fVqhvfo+Qze+_>U&{ zY%t5fLm59op$WRM-pc?H2Jn-+S9!;yiua=)&z)7!+v+*YdaecIWxleTyafNynlvwh z$aPJoTZAgmB^Bcwom~V>Gk!&_R++2b@)0V|G*>-8xO@h_XPbu}YfV-VZ@SAW4Xvk| ztNwIMtI6i7_w^7JXPc`&P2+lIe7LS!tNPb{?J90IR~;VLVj0u_E1G_^Z`Bg8Mm9hn z-T7s~n8RyT+9peDXqk!|%~fByR;cJ}=x3WXR6hnH;SuXl4<6SuGs&_#X|3w8xc13- z2ZxcO4_cFN9Tjf7tY&hripR}Wf9^h@qK|8BGp>3f2>;Bua6L1F94;PXMH8c5INho} zC;KryX_@wC$Bxm@TlD{*;0lQQy6ne$R_URYT5R)nU#B6BZpi+GHj+D~X=AnUzgvt+ z@xIuJ4otwz=XdHEZJP(|>9oPxAgWossF*ipX@_4{kxBV6-Zj(M^_;BQM%=Xi@t#%R zvlcppY1bqC=W0AaXPZBy?{$A_?3Uu|trM7nDm(F*?3aq4I$X^*`iu2Ho$7zOm-=s{ z`sPnf5uYJ&eaC|4?2)fWID5e>K>sA{IHJF+{fS>V_lYx6(+dMJ-oIZ&_c1BhV8U(b#K*Ygo>kN zJsxztCdcdUY#wy%kt442RcAf{bjhj*9q3I~_6H5xi%q{V;BeJAE$DVtGGtwCtC8#euNt(xjQ5~5 zSO$*C25NQusj*v%KlAF>55KK4o1pbkZHYRu5u{ZpzVg~k^wtL?(Y`Lzn86g2?O?vFfAP=zEjo-^{Qt4{KHyqkSDo(*98OLMC4^AS z&@+^r5{i`2_ne#}BBe+vQltctB0V7oa)Okk6e&ZIQVORGQi_xkz{rir%OGNm3`Rsm zL_|bn7=~dOF2itRWEf<)7`Y5aWFpf0`R={fZ|~oG-jf{CdY@;WD|xyP2s#YwSHFBE~4maS3Fw+y$3#390=$vkuktmC2qXW5Sg51h@0XwM5bmL=20Ic_h-^d z)>5(v=xh>89^_QSCwRZxvDiw)?ap2@)tgz-&FN;s!{@9 zWhUhBeXPoERB4*3vC-9-YDzLH)aW%SE`i)gi<=kK$bDzTEm^XGAnhQf%R5arw+6kP z&>Mlj1syvmUw##`9e^1n)vKPp2D$E86&gSxO*zOQ&klyj6jJl}MHE+phYIxAtW8z) z{-!Dkq}M$PlfRQv(=exGwJfEUTBqF7nB``VC(e?4F8H+zAG|+Lm7+g$<-=g-!`u;&X-~@h zT-h4u%+76r%=N5Qx*d}{QPxW(I-g5>39$4;e3YM-wsKo3Czl@J%GcfWHUGHQzJPo% zE@pWngTI*|Iz3yRI1FTYN{j#x6<*rCqIxuMudm?!VFYSkrlrIX*Vfr;>qXC+_c$TP zC%F#JF5#*vQv)qjNJ0YwAIm^4p`r$M*SHTqKLHqyUQCfh^$_sV34NdHNhtSYoT zt6beM5Tq3-t!~MUhqO<3mG4q`>DY3!;1V*WvQ_l)3TI_1R$P{tJlZX8;4oR>iCG8(w6{}LF9^KXUm=Gz}Xa|o{-C;%Pd2TI^%)DODCwI zQ%Q-_0AnHw65dB~mt4kd5%nB8)`95UTTxP1E^c%gB3r?Og@-yHk*BpKC13TqB2zw* z%T;m?&{eDG*?jg*lJ{ITx3pPB8ZEWPM$J2E19y);PzQ7m-xlYXz}d!f_k>X4{vII+ zqwI6pg|%sOP9iuuaw5Xj05aJBI6x9eKKUKmx@gD(ixCh zUMkY!r6SvaGiMFBO&xbYS7yP}eM@5B0gQ*#=ed&2BCUY8$fnTnqWlpp0W_%i2QU_1q8X z_f?YpxaSGWE3-)TlCSjEfB{}t+gAl;f1|UmB+U(ASmC9c%c~{Dq=+TgTQw#ipUSMf z%DxOnyi0kN)PsY5b(L+X{1)(u!kQJ*kPB;8^bH9dhz6npKA@uptLXOc(*>13@cvy; z(FGrOV=l4^e4_9z-yWfxeyiNkg8~Pz3WerK482i z#~mgIWX+1|zQLR%O7nJN$dD2#W=Bpv8ke;r&Y~2)S#aec{lrEIHe@&mWiiQ=Iu;@7 zF`Y?cZx;o z7-SA+Z!8zH-!<}!BF8`t_bx|2@pTF*bpli)QCj>PKu<7S8@!r1(Sr)Fxu7{qWQpp* zA3pO#cw7P3@4HIWIT0P51WkpZ0bW=ATS3`I#R68a%*3vsTo#==W?6CQMD+PxElckV z80dXQ_oY@Xgf?vqo=Eo&aA6kBz9^=JSTK_EdcD?8P>9P$MO$5r`;tf&6jQ zz2jZ+ulpDm6tL7b#*wE^rHn{sK#T;kU_3g>!pOzAPy_KRvp`^zR0aa;%eRej@7o2% zxE7H0CpBdK>G;fr(4XFgFdQm6+ZF$|_m$jlCoKq4wIC|c1L!C+sAwe?h!&e`)DRIoF&NL^525ob!?N!RAvHk^wM%M<7h2^WMKxzQmV$Oeo4f_AqOmX zhIFAq2eWVJBuUdMghMja@bx}+rpgj)DyHF(eCBrr!A&AN!6ynYt#V<7@TeF-Lfd}7 zAay%Lrhp}MG$&Q`H9%D2N~`5bR7#BeAS_!@X&|T!b5ZFzkp^37T7h#wr^3&O ztYR=(fmfD`Q3U3_Hghg{#ceGnHacrx7U{*3r__bzVtl-EKgdL6TIa8MHFcecMkn!V zjf*NSLyfJVY&|5+{53Bom1&n#O!Ke01!e-j!mNDTYu>iy{Uxhht!%?$W_Hbss$b!{ z0M$?XrZzT3a;ZBr}ycCiq3Y$!*whk#0%YA3!(xo z2!}uweI0OnN5n_y<#A8o8&&#Qy?%90mdx)Mp{VY`1A+ zIShc}1HvQsL&V1v=D(;QvI=ZU{RolLU9${ z4&1ng;&`3a$$YZnf%U~h%T#nX7@J&hOFv9cE?R>r1gRlq1W7VcW$6S+FW=wQny#P~ zIWbk)qO1)g9&@KmB%EB)CBTN0t54|U>Wt~&E6yv>Q80>>$;s8{h9jlhBchFP&UB_S zL#7(7B`4SRtR-hmT(Fh~*Vsx7mgDzE;4==9aEWGkqrZtN>3 zoND-fcsRfG%4Vh=xcZfB()ZN8c$I>9dv=?>QYo9KZN0E5*i+YMvIp_@wC(FwPTMk) zYA@;O{L{`u2}nP8<61*j$p;&aN_jS@8lKs1c$!6C1p31h4UhOGK1)QS_lVE>s=EQJ zA9<}S*`W4Lv)uS9*AD9avmxeJCVg@1VTMMtP3e+N;)gB1hDnfx*M}{}rd*vx2Cy$$@s7FW%djcc0{Hf#^4QI&zpMx|}-*5hq+tTz=k&$(Ul zXG}B_(InTwGei`w**I@5H)Aeg%Hz?P?39~Cf^zGMM7ecEs;u$id7Ma4zLi?OwcL~^ zVoniDuVX~zm8s>GndS8;A8~FxC!#oRKUX6@zio4=-FDlS&_ZwAwk5UO7TLBfp+&fd zEW$}>Gbdl(g3?14l%#4iCa-Fn2Fo@JJ7(EtXGhwnN$YP{g^8K-BFKUl@pe^^YZ7MX5|nh; zNqb|^x49qpOs|g?Om;2_$xzmheK@klJ=2$D)YFn7X$wcQ#@0?T+cSMhl}q=`m_+L8 ztgvUsqPEoBev8=BZt1CBi=)Y&c^{>1eQso>z2+9(vmy$<+B4}-w|LZ{wr5Ia9qjfd zsACdY)sDc-QR?PUw(y3aO>`jMv3YW#&uyXRPi@u)L(r zKNqW$l3^NJNs`L6$*DSRe%^nbHh+oL7!C7R`-z{%R%eo_$*nq*SWQWr-=U~WB6hJl z$#&CUr7fZntCQ@GmbNu=k%@mB@W(46KFqi|pH1X!?K522jCChbTIfDzYEv`D4yoD{ z%)*R>HrMj1no}C}Tvav=;-!i2jx5T=id>8tq)cNJG8A8!sZk-0jrd?VLG9rw(1g z=sm(w&i8pDTBmxiQQNV2ts^%Ubd%0OuFJJgyQ=~d+Qywmdu`L4$Wc|Fr_tW$*hs`^ z?|1Nu(Vi?f-Lt_+qJ5TU!=WZAcI&Euz*Z7p3m6L#jg)1HAK|k^)B}(BQr~sYWc9O1 zbtUT5Eu#b&WP#;WIZG@iAt^Uk*Uf%{QhDNWC7L0oxPN60g3R2es8_XCQeMx*zONOQdsVixN z9YdopX{R>lDq9y+ag)q<35~I6#n4FhyM@O4C~Xr;v!vP0l5Blzj=lS$mPUt{tdu)^ zAe@5oNw-#oHWAeGnh4c=hDO~jeiq=XydrawEb+^ImdG~H-IrQZsQWhWcT2Jd=xaCF zvKM{GElI3V?d`MtD>|l7;RZ!Juklp4L6Lh~#oA66E9SI$Sddc=y&H6G^27`HoN}3E zn^f5ad`>xU+2&eygCeIJZcqd-YzlVF3!9qR4T_xQaDyUPwi(+o%Qllc(mtEub#_-R z=LOL=EE+c=O!0G|BX*^yB{5LDkZgoM77?Gl1)12k<>O*`qEBfpCSS~LOX=E@S4k|V zoWeC4+HW9AxeAHpFUC>9&*id3~6F#1J1@ljvH{Y+_cSxyi%TxusTkgfo@KyVdA#~-VGAbEVV50$6eNJ z5%sg4HB;(4?pgCMxZ|qCI{)jwMV948Ld#b<8XUWC(N;sb3d43?j|Nde{nqBCn`{&l z-Egx)x`D-jYPP|(y9dDMkTuK+SNqUn8qekwVKQr zBV}(72B{l0yD;YN0!lW$Ls6GZ%38LY{qop?(EBT$E|Hyn-iy2j^sPocdli4cWxXKc z!;a6gd7Q0qCQdeCv)dLD+RTixL{gi9S=f=#rdnRrrc|yfn>$(9QF%=g4P#Ez#x>rq z@O_#MTfAKnGHg@`M~q-H3|Wu2&9UB86glX+Ec^DwT9Pk2(QJ_r>F=cX7w%;D7dA$X zc5YWlLv7+*EE3GUlbU-cXHG$>L$@m~V!4}B&VKV*qDw#@h!DLC9^nr&^-)M(zOhe8 zTI>5#`joTqrBu`(QH4?xj{=VegZ!OMwKM50|6=m#NvVwk1IksuRrp2!O-%1o{zH|j zU=ZMM2}BMNciFHnWW7^|a3FY8e<(^@c(v3!pwHzfL!}-s&txM&_vaJuq&5Y7q_QeC zdb7E&XfC6`>wve?M6@ZmdCU1ruOR0alL?c>6wYZ<%`GNVO%_w4np;e!np;dJ)M8RR z%sC~2-gxGVG3XK8RJ{aRGpvg6nzPT#ZQu4{F z&t`~h0K|%5l2^6eF>|+95IF)KvqQUHLW@jL$Z%!k~XrN+kn@gvh zZn$&`x;9Ah0wOY7u%^juM^Y}<|CvU;{LocT%yQc zV1up=h+R`4wxgE&6Uxxsplt({co8m9q#W3wYvb23%Qmiw<)jbt?X%%dbi*Zzya;UY z!e&9D+pb-k9Eon23DyVpE|BU%&-V)e|SoSjG3`i`Jb73Tjkd$ z$!rTnUC=>HvaZc!EQ^ruqqNQDGtAK|Zpt=^=yS3;Zjq27S%TEO=J-|S&m6DADp_LMDc9SKV z3%hOdY$Vj00?p6^3^l>=u5~l3AsQsh5R$yB_)31*;KfIwULUJ4*+bNjw2@WB(X!K?N~FWK_S8@lL@8Gx(JCe_MkZ%Ll-%IQ zqBa*?q(f|JH#f>6-TNqQ6G*e779>mg4s$9jxOU!eNHp5HEiH`>KP;7Uhi^;k6B#Ye z;h7?O_^qFA(W?yhAl!vY9t*oW(3&*cfm^C3ltAO=mMV8(v{aRsTdK%4e#kXo=~5-f z4F_3nII@tL+!oIAtf%F;)|XyY;0B{xYhzqPUJ%h9V_D*7xU41-wX=qE)#xX*MwMCw z9`ddBLJ9P|S#LC8JpTviC3~ZQTg15K{${aE!@7df#(G~L$A-K)~Kx{iZRh3vkb zPFQPz-Pa5E!&JM(Yr&&-v+hz-yE4{+?53Y(dIRZAKdBuAA1Sx<(p%nOs%+!-3I(8D~YGd*bP3Y4*q#e7(U_I1 z)h_1WZ+RPpqcrvw;1npLbN9y!{=R7kzM^Ohl_1TF(S08`p zTp@`2zkc@h>CmKAoGZrPYF8-c|AN~Wvu&V0ZJquM+(p+m+eTW{_J`4-XxJPmla_C9 z%SbKRer%TFexbi8H&62W1Jbbhq`hE!%hSQ9vh4uXAn{h;ea}e^+xGL*_h;BPmoh)t z9#Z4BLz!`vN{$&}lM0fK>|ChwaR@)cI#FH*&jin9JhxZbMrOhe?r&1hDp3VDz_b3d z@p^{wPf<;}uCK75KccU2xKOyp?-urmgM(3<&Ep;ghOt8U(zA%BicX1o14Mjw?S|v- zD$kDp>4A_#cf|vtKgd@+5QcMl?%K`zCd;#i$;WQav32f1D84%&fQj@4h>mQbAEc+*pIv1IJ>_RtO^I&q zDob*^_Gw4ox;Y-~=oRK59>8SBv$%pJb$5kq*>IJGZ7mO9(k`o9h4Fbendp??PeRE} z{8-f113tuAOt$2%wCzsG^X~g7Z9}c`s{_eZmPY^G4|a)0J6BoK&~SC=v8=7r zJnK~X=x^V&X18xfBjdxOBD(y{+~Wz5yDib=@@I-@6YXoScSPRrR1vY?wh!HT-!!3_d8 zvt!a$g`Rrk?^>Xv-5{#AQ?kNci&)gHr=(U(S6WY~x$OHWoeupJ#)em_M8Xp+S8qD! z;u9?IQg#jRC!;w>L$e9jHplAJe46U&%sx`uKr*c1cJ7oU8tpu`l17K`lt@`4*P+K& z^HAOi*iS^V<*L&Z_x9a#4Nr&=F)<`;`-I5n<(8}6StrX4Y}R|p6QV57`fmw7tat9r z7twOyF%W9*u}wHSa?6@uFx57se7T+IutrdKpGNjN)-1bgK?4$dYQ7qm=*k++ zR-J(jx@{kMI5+Jsf-68DP&SlvTZP?fXN!uNT2j86@<$$CTE0akT^owJS&G;#$0XbJ zym~6xqLS>6mbT&134bNv1D7J|{_H-Q9wb=!%I>2{s7_V0dE}7wW%|e=*Yb4rk&(13 zYXYmUEGKnuwR10f$7wdnu=?70&LE8rKShwTu8=zPH@sU>Jmr-|vbDtt!|i$!gsspY zSJJRVE4?rT+uYi+GYV0$&Dv^{XT2kLbiUI&E1dk?S#OtfuUSNA1UGIN&{pEkct>3R zOc6EVQEi1GUq9mP{-!}07r=*-%%J9XAKj3Yg4*jgwqU^@7}2rArB~062&_UhSwPy@ z;QYoLWI;FC*rIOOo?MZ5-1AbmmXeLlmr^HdF}!EVWMiYGo1U?#OD45iwi~0eRro$i zrvs_}WMdNv8=I?_Ua9bEhIc7lTKJqen=Y-g9II2a zsw3UQ$e@$j*~4htP-Oq{S zCPvwIs+cm6kX+a`7m z6GP7l9^oBmH7L9Stw%5t_X8i!XZZ&c=@T9)jcTjtA4#N&R;esc09@INXjlB>N|TeT zJSGzxCI7d-J#PQX86}N&oRb}&fpJEsRleu7y06jC13TUPMWu#>vx+xf-kO++!|pv% z?1s9NMfd%+D^`MWxAMI+>du(=ZVvcn+Hvf!?yH$)XEv&Sx0=4sA&kw*H}(FU@XfV7 z;~(1zO4Q|o2Q3nHk;=_fCnZ;NFj2B*=L#jEia~Z+-$#&3YRg>GYq$>bwD-&6#%-odR+8+W{6~@ZRZ^A7HIaT#vpLszN7|&vjB{az%3|lf-;h zXMEp39~u(f`*S6&S|x)A5|ga>utUyhM||IlKW>YO+gTGeMy@m7XSZ5V`R8u6n`Hi= z`+at6d9?U2e}<`fyx0dH|DI3!jMZXEb0x*^JG{6hLqt%uhCAVN>9)?(0C zegM^WC@jUQEk1qiy{fil^n+Sk(FKcLFLbIf3(}ZUvFc3t&*3bMcCK5>c8S>K7T5l{ z%hOv0NmR>bRobWbw;Q_Nj$LjsZ#X;kQoyG+M08EY3F#bLq)tfw3d&zjhD7_fs|iBv zovw=P_jx!WlaQ) ziFplxU6tf-u9RJ|Bz5GKY zAGhR2f~j!-^O3(+U!QmIeNXN1hwsiqdAAkpFZa-XmL5WmZr{=A3|96Uhv2N~jl`|ILk zE`OGYs;}Ws(RG1VmrcAMawW=EnG~!o?JA^h`S!nPWjYmJv|M?mpR49CuuNnf#-H7` z^T0LHXy>VrG-SF%f7m7EJx;j;f2DgGMRgT72}RVh-)h@OuET6^u~BqAs~lbZ{1e7K zXS_UC)cM(-jobfLPTSPD8hX5Q;geZI#JA1=bdvw+3i(eZ`A_BYuTw|o!c!$tjj+BC zlG^X#*79r<)sfUB=v;U@Q;V|t3bJTUdV^fqVrfKXr!iM%K*$#z4fuMaRlSzv1}B;+ zvJvofX@lQEx_2oQT8ES*-0F2iwgG*oRiQsK^Au(P_isctgT%}O&WwbwcpWRI&U9_U(_xv6SXcd-RZ)hPKak{YFC>!Bc-fv`$~fuMU7&fZid z$so|9u%fEuildBNvLS7>B^e5O7B*FVgVC*{h}W020X#$wK6s%7jX@pZvQPr^l8z`> zmtbVMP=Zk)@3thP0dCi%Zc8?{jkYA?0DB~B;3K&bl8T@?Ub&`Zs{auztSUGI-M;rJXGCH-QeLFoovysx^E7{HMGdO= zp+fW|b0p}P7dahsp+_O-K*{RQDW{dcLT$WCFOskL69Zkv=Y772>WFs8uUIK^Rk|8r zS48d4l}qbifMG2`(WS1gnX4e{9Q&-udeEitjTI#^@{wbJ$acrh6xjv36jrP#iBbPB zS&l(Y0T~zd4Vfi!0bsFHNz7I7fkLD8_a_F{I{#ap|Fc9^f-Z&DP9-tEU9;M2f~F#W zC?9*^XHBz6;b8#RM23SNh1CUjJsLI+$;NmUk#V4!(_y-CY(%!jtBAY;q7}byNVe0f zh`a{Mx1R&Z4to`mBcR-hWGB6f$SI&dvyd<1PXjKUw)kx%+(XQ^hU?_s1Dy*ogpXqu zj0b7FZ6dwsN4!k574R35B3FZ0^p+F1i1Z%rwMFXy7k47pe$=hhGeAy@9{HpbpNHH45{usQ;vS=jPk?Gf#sg`H&i7)G zsh{#<(Plt{Ma~DY=tU=P5h;xJ+M?Y64Hnt><6bPf4N#>>-!Wb+ItU;ZnH0pLO!VC#yf41S)glSWugA@ zlGxckM`RCBZ;9^r;zN+*L3|Q=#*0PH2eGZL4a}rtZWLx~aFm^#+V+xr!%d>+HHmJz z8S=blh{n28;dvWpSQQ`UM(cSE;$+WGgY0&r^8D+N-mc4^9|GCxS@r%c&%O;A;ClIa zb^g*%yDFAJE_?PCWV7q!=eIxxxn6r-eLTjq>euU@T{n&@0G_Fre8Zl%X78b4%l+!m zqB-wbwXwfj94#V#oy-(@%&(1=5G@skP@OQruK_KMrExjz_v}%6$oEo9?4=g<(iPX= zZmN%Qz0@)mGS0J_=_fpU8uFHBZ$jSjY%jX;xa(0j&wY=!s7E!Y@k~A1%}-W!<0#K+ z-Y)U%R=RP2oU8XdTcF=GZLwgpHkqlgnw`FLThzJRUFWvg6huMO?x>qUEjHDVT9@CV z%ZJdx)%?A)qM`VauHRqSL0`V=y7dLMuGY2gg^9Go*Y`rK?}Z&ypsCL5pqk=-TwkzC zZcvE=BC)~ZVol+tiPiN3e*B4&M%vHjxf*H3CG<2R3MsG_Sz-|dm^WC7WX4&Py>8u? z5z$=NCD0wAmm!?+eLN|wI zifE-)6}sJ9Q4*&KMlG*Hd<>f_q9x3!LS%+pvvakQwQd>itB})S2NU(XS$(OIfm`DS zZ)T4$V$}1!6(y}&ObxUTnk@>NZCAS% zy;eNdMf{{_iIZaPd1itJS|e&(ldne0T!ZRU;! z84oSv?gg&$xU6g5RKKnsVg|TE~8(y4ktP z&CZ!3exlCMMD>wnh9b*7uOL#(=26YQy{1rG(nc}@&;y!~nvIqfXQrEucm2#1@iX%o z&CCUElFk&-c2kYfm6+8L>@}Yya>lXGyag$^sr-!XL{^z?N0zod$FJ^4fiU?K640i6quF`*9LlRi|fEIil~PlDJ=BoeS4Jtv25(5 zz16Asuho7nJ}!`WJK**5ohz!p7H;>$X1BYQyC3ieRfu(O$G?-C>X=(+7`O|dhHDRh zt!z1?kWO$pHT{>lE8_*Emggkpx?QNNDJt~Pga)1$RGnDve>cDiYx=}T2YK#*R>*K7jOXq>fLxwWG`?Rg7Rsr zo2<`?Yy({i-|SQpQEGR$`ocXuvi zx2WzRsz&q(cMqlQU)XR@Xe6!yeK>`@^lBLJB;P8mVfplQD`}2MBj8@m_Hg$vyf7B0 zq11bWNAysF8kfXrDDh*0yLq@IOv7*=(fOp@p@3Q`G^vN%vCHhWg8TOlix6-i~O{!waSYKk0l>!h8QdqvCB<7Bn*HYgA zAmgImjpyXXA<(JtoXBC|=BOC&UN%R|-BWLKZio%ZPO}ThS>kfDX)94Hc!bOSvN^B{ z@n)wz-8ynL$@NaV&5V|K1L#xun!8irW>b=Qns<%Rnt7|Y_N?ZN9qSE!WrR}2H(spHSX}b|*X}iX@v|adGT4&@f z?)>y@JR>)sL83#eY1v53rMKpRu7x>z2qShes8NzL@}?@K*5)KiZ2%7jou*AyN@_e3 zQCfkr?CWFx?^Rq(F_lGRuLioO4cX|}nIalzJ(n`g^+Cp8@+)gQ(EZoe!s8|JJ3%tb z_A?6(gSO|fI;4#*r>6fm+<9yoso6P+)oHq2sfhEKDTZXKHI?$rDrvmz*?8rZZErF+ z2q+$j7M+gk})2V_yy*ZrKx7T^wHa%3D}gA*AK z+y*DcUm9i`T)Bh$vB4oMHYMB5PLOj7_(ys*V$Xx@kzSQjH*ylC-UbiG=Xpx%Vl@$2 zr>X*F+1v^D!qc1f=TNx@cr!xewqu(`?t*mg+zK-0j?2PsH76R)ozC#8CwXh*Rg$|w z*TNUIF2wE!HA?DnWtCE=auTJ^f(L^R>q1Edl0;-}Qw7R;go_0o1(H7rGnIX0p8$9) za?Y_cMcx2u+s*_Tn##HY^h7~z6R&!bSGD>Qk?KI(1LC3(!E_SjF}NKNEt-{y%}*=U zjgxmMQ?eqdEY)A-f@8DDYR5h!vfE2l_>O0FYgacT6Zci!QlR-Ry54Edcp0+Iu`@-s z0~fHx$RI0IWUpgqh#UZJk%>9z>u)nIc;N#yge7c=xgeUhbZH zTeq(=&Fp|U1W^%$^&@r!i0enGDLIK!(?POWlw6V*DXIE+KkD@r_GsIBU$siXCSJ0r ztlXnvPTI9}E?N(#>_os~5ovO4v&bxv&dO;)#;jD<9AGO>ygW=+Torp_4G6sC1)g}FY{QRq;7DA-arqb-SK=__YGEai)2%k&(QtP zt$71V>P}hCfOV(bo(d|&D2Y{hFS|F9bhSCv+wyXKZQk{x~c!|31fb?1^%A)Zoi^g@0 zrJHchpcF2b8Jb3oO`vOmeP~mS*g2p^$$45lN-Z%7D`!)cQmx=Y=^$a%DXCldCYryg z%FdgK$a+h4?g2I}{U1ZPnJ2LfWoseHGm909ndKIW$~`8m$ZE&V5?Kq<@m&^V{6@I4 zHUj-f+IJaW@$!N9Rjtb8)m3@87lgSh_7I43SE*AuiBe}lGEtRO9f`==U|sMobN3)6 z&jIGH$OVwL?M#p{ca`-fu(>PVw=J8yw-DV19IHjfyLT(#iQUkwmrYv=5cUPY&s&g%6d)uS@df$0B*%~Dv43e$#HHWmSwSq zTUq%V8fwZypdQLjmbE2`)WTkF(A>n$PO55(W@A|qo1m47sP1i`Ql7QUJV{Tp=ElRe zdTa`t52>;_&_>y6ZRAmgImjaecSfg5o7v;}Ym6nVwTdEZOS zHZO0_S2dMDC`U9$U}ek~%I@P=aZgeYs}v@6cXPaZ?)r?LL!Jc^i=GGU9dAJV1IFz2 z{O-X351m!WD`wB1EmuvnZ1LuE%&$-K;|+_L|8$Zc?=C98r*oe(Lh!_G=~h|pz%UJs zX21bOWR7E-Mdku~byK{$q!(9!FOByP3jFQnCo{i0(@iz5tC~f+0p4y7N5$~UoP@o- zj>u!6nm@5jufDI-V>eybHjCT>iJ1r7yVerk^*SO|?j}_J&AZ;n`T}OANG)h%M#6z! zM`RGNSMS8@VKXny9q>m@3TI? z4mu<7Ezn(o7u^GD_{9w$@6C!HORaz zZxpM~8pOLZ^Ze^J)}$IW$-RJMJ&3wGQk@vpm0AYK6j2LfrnQ&f{0O$J#ZkxFTvMRU zu0CsZ)UkGRgFWb2%cG9kuEyeswX-K8n+8Sr5umH??0mQ+R*fMpZ-Z#)VP!*|=E6zn zyd-juC3_m^$>YLL4Om`yd~xA%KXoLX4nANxUMx`);3u`^bOd(gwrcs4bHX7FGu3V9Fui09xUz{@6)ZVPQ%19eqvbMG< zVGZq3$ThQMt#tC(#*#I$T;JN~009vKqKkj+l*JE+UtuE*B4a@iEASAQrvs#UfXL zJN(F#x4m4%Pw{v-&}gTQD4!3>nx6_VAN4^-bdZHx$7m|GON0NN;f12crubn7+zP$K}F754GGpt_C1=TqhaQszu z15uY)bPQm*j)TZbI&*rUIt;igKwi{UQC|~R(WI@WcR~w;b#L)`Ssd?-KQE$!53+}h zeWKg<9*AY%qU=EIa_$$Aqf9W>G~AW_f{08ZH6PJUtA5OtnJF?9FcYVW%G3i?IC8+q z*vXu!tv_Mab&byUOp%d5rDHuat)4*`8xDvdcOmyYYh9mz32{7`YC!ie;N0s>UP6>5 zxz@QbG3&r6iwDjqi=jla!LIC6CD9>{Zzzct9bYVo%6{&WVhsYdn>YH8K~6ZfNkmOZ z-t*spXd~##Gc$G|u?GO1FCr6N3#;nMISG5t=ZL67LXKE(H9Iw#RqgV!Tbmiy-IK3# z@5QW3L-uR43QWUli5gasY1mk)wu68*D*-8zhH#Pm!!Hu#wxKS1dSF#3IwxJ|C%JE!tLuE5Jpju70gMw(?=hWU= zBGZ9ZvFKbc7FjjPi$z~`e0@oDAE2bjDJSNSy`VR|Sftm}Dp_9=t#y2{B-#Whxf=3H z5R0DhVv$pzE6*qSTNSZqe2#Ti3x2mc(HCUH=VmK=6}i5K=_0ED7acQni6mYnxI}X4 zSUTG}R#IC1!czm^HatU-TtZQAfq9pdF&k<4Yg&dn)1cTT~&sZn%bG_cZZiSJxC3Vz#*HO=isI!6< z>$klAtk7YaxYkvQst=T`x0IuP>f_qY8gK-n zeuK3R>xYki89h4*R?A0sU?6HOtPLuxR>*mv7b7P=v8>QI;PH~u7XZ%>XIGn0f{TFG zO8C;;YN<-1wqR)(WRzz|Lne7vO;I~gPy;r4R!hn|o$X7}>88n<(@oLors#B&oIVS> zu_;b`;+xKCrM=UVarGhhBzP0x^jtaZrIK6&L_`tqf71YbQX3xRp3x)U``-7y-nXRW zc)+nuWU^zQ6;ZRgqWIJkC9y3&M=jj!*d~pTTA5g@&}fB*H9)7Vtx)wzE;{zdzrmpG zs}Gy$q{?kY}_J2^e2w8GtW-6uze$?lYG2AT1&d79-13ud=u zW`l;=H6lBK zyDk#5+spSuj(Aq&7;q|LPI>uFh*~0xj=Bn`$)_sd_FgePg+gP}RQ;*2q7?af}l7>MQs=UuYZk{$xsy+lTW8g6bh4$!MK zN{w}yGeuPPL9Je&Yu#vjWO_#>%Hq*3%3}4lBhl^Cu|CID);ymkDD-KojX|%zr0BI1 zply|#Do@!=GkM@Y-v$m=-V(Dl8A!2oZdu)XYV?XAx1S$+0;;|Ac>VIq<_<3wg&P4&ew6yawSehARxAo@Kk4xfR9G|GW6v1I4-ETE>>u&10ehjs zH)Ps8TG}F4445G76)vF3U>lt{#>yr^m^K3 zCsbH7#bY;AIQP@hzWBETdQUADg`ojcp~8h}9<|Tl8yGgjW6`sW2k1Q0qd!!5>^YAj zRCs%~$F4c_3E22TtY7@jfWuJX`imZ&zZCVvPYhTM6(-E{m;n`D3uvAn%ZXndZ~`iH z|2dB-P+@++TBxu;;4)O`yuhOlDhvyl02P)6Y=jE02AqWocLQd9rC1a$2h=Pi4uI7G zv;GzN;7-7yMa819;j12vUn>@cWdS#!!lghYG8{>(R8K zSQK__j^iVKU%+Lk(D|1<>Y&1nfPOC*i^7C}*PuefFMI5P3X`^YY=sJSuf+Pq&kNWE z6<+)mk7ZEdWI*e$#&Y6&Z1Wfa70w3?DiL=id4X8bnm3@rYgs4xCtz$K_KVz0+#sIc>QJuX0nmVF*Opu+KhD^Q{8_dM#L z!kB>NP+@;S^?r^JpijW$-zWZp*8;8`B*udwf8??;;2XS zu~^Q=MY27>(&Fz1?E5q3HfTK_^G(mF@_PKa$1ri3PWseO|YlrzE+4g|f zp~8`XGf<)TfA^RU73K%5g9^t3?m^9N@Be`w*a!9llS^md6_2@4VRyhesIcg-JdQ(! z?pHl#L50_WwZo`nhpu__`o9@}a5~`Hb=D)O`D>2}P+>YSzr?o&9EA$k1A4s0yauNO z-hm2}|Hfkv)cg?N`$kNQznY}QFZ_REzW6r+y4@@mg=N6(iSKzqsqIO zfz=~^+dp``dAC>;y8olchI{NWU|6BvVPjQ&QFybfN3pt|z+PXxSyP|c z7eD#I`pmxgIRRUs!hmib>!HFPVE%}|8PNDpeNku%*Z~zrb@!MG72X2YKC>g)ln+F? z_(e(D^o=TSeGiWw57!rk1p#NFLa&}4jZiCR^+`7B5synyp|MxgGkwVp1)PEkZ+y^W zTA%u&@LE9OhuW5xY-%DGe=T77WA#O$$A@Bn&Vzp)oUE-co(AUcU1TGJ>}(=m120|4 z&Lwj5|9+`_c_XnSzV%;vOzKx(6cz!qE584SJ;p+XIl%npzU%kIw<5bMd4J{4ox zw+`^QG>CBkr-pdE_+))i=rz=%_s3&7t6#FCz|!LH1~e6!i(pm2g8Hau`bL$vH{flk zaP=vV(?7;ofV%;^M@B!yp9|>w$@-!&BA^K>EDYEM6?%{I81$+7qA=yhJ&r+z@t^kC zKenDf+^sL(_>9NKpI|+M;h*(roxr$&eLv|jY-03F{GNc*P~k>E-P83&VQ0XS$@N8H z#7}wbfC_7;M0?`T1XTTWeNosFFn4NwQP}l)kGG-1m}wrfex|-C>pJ}7Tu zz@0DD7lk2B9xp#WJ(fU)!vVu* z(cj=IF#F<%KNr*DmjzU{P#0(drvFb(t^ZW#_J9G;6Su+qfNitmc#6LQ%rEhSe>SGY zj|?~h72X1--yW6Dq&XgUpu&_d#&Y6c3Amid#dn_@^~ArJq^&;5c2tmCzESC%?SP)? zms6E(dcmXN#psvmS$`{UNx=3*PyFOB#s0Q(lFbQN1r@FVvnPJ&JdcZCj`fPaINxL6 zS6J`htwkO)zFJ=tt^=#*|0}9G=P!=+ia!!?1uEPF*1mGTOfH?VKOgOwo@CP!x%dMC zeV0Ui@!OKLm6xpd*P@=uC0h`1szSbGF9u!U19n1%`TyFZ zY87z|EDJac6{h}z$6~0k1(-eYBUgJYgbHs0%NJkut>};WUrtS5y3GOW*3=h;ZfiYO z|6+Yn==GgwUwrHOm=?bSn0>P=*@=Me-zD~d24H&Prw1&D3OfT%LWKnzqQ3a+N!sif zRo>i}JSJ?cFA7J2`6GV7rkJ*J-!GNTrhsKo;W+51UFq)L+*V(*L%-y4@nzx?nET7o zfANO`3R{qa&aZgX{7QXMSQ_xouhtiZx!XKip~A*ewAY@$)_?Q=Epu@XYYFTCCU38t z$yLYMfbQFw2Vi8tE~s!Spy$7-FABo~mOzEG0Rwl`7lqRS8-A_6C>#s82^D(p^cV&e zrUop83LAj=C;m>77Qbzm$62UQ{ToqV{FH!;P+`Wa9!H>N_r0ied;MnA7e71T*lSU4 zb|jnqTOO}Mg|`BZG9E(pZ+k3*+W2faK%f6XeenXg2uv=W^8tfj=WGH-{Eo+jy{sQF zKVThH*d1^ZD)jtakHt{oO2F8C>^0z2z>weLd`W&h+3R43%K&@Tk_XV7X3U3GW`Xl-rObb{B6%Gg7g9^hBdn|(ry94_C zG4+C_0mq<1pCcY~p~8lM%TQs_pLkq>+IYSfmG1GQ9;5!0>uB(1z>9wt?O3}ddo|z$ zRJak)aGcl+rU$e_g`)vCpu(6x_m~eg|HN+$*asEP0?QYFGoZ%_#t{q-m<<&+2ONV6 z-Ts}&FsQIK;2Km|c+%q@R2X^6V=q*=7tr@K*Ms1Ez}WxDyaRg!?m>m)|HNjJ)m6vQ*z&@xj<1an> zU8*k%Qvy~)g#!WCp~B|>=CSB9^9k(z?;dYMtsbM2js7c-+gD@0_`TOWu0c)TsAMbu z+T+!?m{VZg-*~LP5%t9%2pE2o^#WRe*)eMUqr8&={r+cLJ=0g-`de{5i$5Mv{kOz7 zFfL#&)XG^slC2Kd4Hc%m?QsPvEdD!>t59L=ZI263VaMNljC_ZA2Nnk0g$k?w!Q(Bc zu>G#btbb&T!DV26wMV5h>7K`4sL<(;o1+3oW-N*~AAuwm^l;!0H#@*v;bz zR9N_sM{W0pqOduj`v)3|LTkWLs4%&Q$D2^$m4`j<_Kfw2AN5G|PyFP7n^2+gQIAtl zhu%<7{Xvg0(DL?4R@EoU#a~X+;zvH_G4Wr}58!w}_rA0TO#DzRFMctw{^|E*Lvh>C zhT`duHx$nTlkY<|I>^o^a>=AC*@Z+dn>}kic0h$)|I%ZAzlNf)A)w*I4Mkx}z;&oF z`f-mtbqz(~m5+Gbh6*=6>T%_V8;ZiB!5-Z{)=(7chIm|p3YQcA#7`{7ekku}OG{^J z{d?<~zV(;Nyc}==D%=iO*zn%=%#L(V2Gl)8dqB5Fj}1`M6aN-4Kg3V{gvU0h(0iE2 zMyRj@Sb6b>1K#|RC>P&v0k)+z9CPnTDb;B;XaO&@j$p@J}=pg_eNTP~mvMpz*{rQ2kkt*Puev z1dr}N$$ACj0+v99z7st*Lxl?g4WFZ4Fe_j+R5%-O2P!O{tycNG7U>j68 z7tp_n`oXk-Wl&+>Gair4XebIT0h^)1zJN2&HWYOaitZ#4ipw02M9;?EX?iQMmqP zk0}d?k>JgMvtMCsLEnWQcc5lheE)yt(E=6L1{{M58y0!ogIYQ9gTLx=2`cno>~RPx z%wOU$=W7i`VcSxV*P+7tWgZ)rV;@wl@E8rXdc@BScnvDt2AA77O?KS%pdT|OCF;(GXKHJfGbepZos%ru^r;q1k`ONzJo0RbAO3G0{a6RUS|G) zJ;3@={LO&IU*j&e!tH?8tN-_e)i_?%#O40~Ln{E8*a{Uc0kbE*@2fE_zL=y<8=4X3$-YfsT%H3~y zv-dJ%ENlTiUgz8n-ufM4GI$%9-X8MLf~MalHUX1QgO}`XC};BSlDkm4{GHP!CwMnf0w-(n7j$T1;wD30dNEy1y-(7-rXc$ZA{xUjkdiA7XAU(Ou+1HK(-NV1=oPdJMZUg z1=gdxA<-X!Y$Rv}r-A7gexG=U-aMc>4*Vf!Yhd|9$R7blfmgxnU>~>*?f}zE^KK>b z!U4|Yphtk|4W>uD!O5`d(6f}Zii5<>{`fY7)8XNcF@E{lG{t1@sxaYcQ%JuI&XmbVpwqj7k0OFv zVEU4usHZ*P9Jm190GGj4km@Z!cOh5~)`IoG@+;+?O!CFoJjvgtgC4-jrLwV!T>NUV z2CPlwsq9Q57k?4F0WN_%;4ZLwD&^fHzt2#<^ zf%%cjW+!s-i@;*A6s!ju!C`O&90w=CS#Tbhy|m0)X|Yjv89UC3SqyMgLfS=D_Jya8n6D!2h|fwzI#OUtIds4eovY{-Yy#vRi4fZ35v zlMOEN*(T5cEI*YsBX0q-ll)Y+5&6qtOOl_;P9$>iH^5DBFOjFR?yTR(KwmHdi~$qC zBw+qYrw@=$KQIIg1;asknJLJczzksJRaSMRWmP`aZAtXa_H1M?f`wptk}qA$n;-Hv zL$`pf!0J_=%BFe8lYH?ViEHnwL!9gksz5i;3t0Uv@N>XQuq}~`-ws|OhHnQuz~LmG zA0+P#xBxBzvv(Vvk^ElgXfP3&dh|OEsa(H1{|>kZ%JaKX zraKr2^qcZlPW*VV8=Ot#+7tE5?53yR*4B@Y_Tl%j9s|AjrIy~n@|AZAoCD{bFbv6Pbs=Hhwd1JJ2sO?E#DV4G#V4hn1IZcl3IK-e43zlQd>#8>L*UC^b?Dq2heZI*8=^%soAtP>qj8<)6VvLyZSj( z{g&wxpdT?^1=a#{y_dc@0FHoT-~>1cPJ^>RACuM(Zs{jzj{xf*{f4WxQ$Go6 zKVexZU%zsB7M!o3HMy6Y-}v_gK*a8HaBk|y9wR_ z1?Ha3L0cmeStnD#NanwOhHX5U1Z+*%+_o`16vpfzzm#zV=;y74yFfp}WQ(3!vb39=#hDSs>F?2|TFN0TrepuY(Hm@wkSje$u_o7-R!!ay zzCRcM^pV#gpa@0*eb&|VBx?jCf#q$4x6iDao_t8_)kj73QPOTd$-V?kuP1zO&l;}Ufj+V|8Km-Y$j2+MLjEFTi$N<`304Dr?r#H-EwfW8UtjF10|SA5 zw#)SO(JX^LJ7;qBY1&Sc=c)fY-Y)LT6NN(m9lm^*LT9HoBTIL2=~-F2%BAOK>8>ul zs!OA*ze}OorPn-aX@2-X|2}Bx8lV1*r62U^BOedtyZLnZf0x2TW$Er^=?|2pdz7Ug zE=%_;OFvSU?p2n4v@G2_^q3b{75?YN{GNe)UU*g1)15kOyfh{~x|uD2#fD z@Am}#l~8?GOMWW5PS>)aKb*9_)n)!nBCYRstq%D= zOIqLVviw%k`i|F+nPV%_Xhxip^!I zE8R+3-xcc|^1nm+TA`7T0s8*hMq1w*n-KEVpR*3e{`>)U7wi1KF`X?-Wn@~4y5x6&4e{BMxf zcheSx^e>avx6>^B$E5WgwGkozDrtR7O@7FJXF~Xb2EOMJ^6NtIca^1t$}fpy}u%@@3NVGm+C@6 z-)37M@;^v=?jLg2!#}Ohfu!}_wt*pE^KB9NwtkN&^Hj?u8PxDRj zRo{A>0F^%zWS{+u=8}4#Fpc!OB;7)Kz=s-(<6S<#iAP%BiE9Yuf1b3y6}K&A{v*FzbHqkjWP*OE5> zhLB!B+WZ?sx_4r4y7Uu!^GUZR_EwSJn%G-M`etHp2kHKay#u5NCH78}F8p!y?+WQ! z(&pb=q!*Aj|2lI78j{$1jC5mSZz$>3#NJraTN8T|N#9KDwU8d3*jqw+bYgEk>B5od z-%irCq|LwGq!*Aj|BjL#o7lTRdSYVl2Io{`wwNqTl-?;z>c#NHXwTN8VKN&04D@9#*@P3%3y z5p+Rf?{OVTk4FD~gmf)w^Y1g#CvE;cLwZqS@BeM=T;Qy%%Kg7pR8%x1G}6%~BO^nc zJq#C(2o(*CL#U*tHp{s`xOnC5Q?g0le*`5OV3;E=yD@Tw@jsqmU8zPa#Eo z?ts@t@!bXQi{je`?~3Ak3f>dNw;#^^D9zu|EQlK5kiQY|-YEPScz+arDqM=f&xKb- z;pf3GMd8bE?$C6;Sqblo!mo!9MB#6Phu~jgTJzZ!cvuwvQFzX_H2-_x9ysKGAG{R~ z^?L+AhDYHW;76kH&G6nR{4{uEl>TLKLlnLTp7x(<`q#tr;E?`mxG@U6yR|0~U37hH|v`&W2*6yK-eM*N5T{Tn<54*A;xua4q-3|6@_07Z;8Tx6@DNJe;>Rn3jcHXKoovAJm-jwrt6@UAGnPr?VH_-=*g{4CASci<Eba*Tr{9gsnfP?=ocw|)GW$?Nv{3qZ|aLCW? z@K!kF|NHQEIK=-ryax{P?}DfNBF)eLz_Z{G-*G3?9&m{7jc^Yf;+q1mghPB6!aLzm zU+;zY!XdsYoO>dT@1yWAIK+1=JO&Q&ZGxA>A-*5NtKbmdlkf&O2S_|XN2_?Ez1;E=zM!`tBy-)-oHH6Yy3z#P=t7I~?LW;#B${9O4@e zPuZEq_a=B29O9b_&xb>N?}mHe5MK|x5)Sb#f_K6pe=Fg=5q}Xr0EhVRfrtM(jsL&k z1~|mO8=ee@`2Ps6fx)@TSQB zEAY0+|IpVH|8LXyUk8tcL;Mrr8E}Yy8oVy@e>uD<^4|wU&a*T9=1|Ks3ok^jkX!?S7p?}Ep|A^uKy1{~rq!RsRbABHzY{@26XBLBC+4bP?V ze-9oDhxm8EGvE;aZ{T&2{}pbBjaQF-7TMh3_&$D#CH6>#0|IdR_16+9R|H~fC>BgT_ z`tUsC+hEy;Sx-Dl?_02J#4I;{0G7R&Tg?9sSTTp;$VNFJUcF}EzkalRUX-#3FSGF@UlM>$}<{ni1g29ST<>Hu>73| z%RbHYAwIts%l}oxXZh)XWv^zc@e)`zYi>6FC@lLmOdGDe>tScV#`s&XY}h<-n0J3j z;iLNa87%uYcUgS9VcEFZ8`a-R{Ie`}_4hxxhd#rp|QZn_$`3xzPACux#vTyeNO)fMstd@WZfd?r40-{dchJ z?*#rU&t-$B(cCp24lSj;5C5Yh{afdKEBA7zkAJnE_#5u0;eVusKkQBPhlr1bFM^xR z{Wb7%m}RHS&uQ>25uXX)4xeG}li^1r{ulTF++ptX;V~ag+kYWE|61-ZnEU(TDUtg} z;HPmX+b;dj!b8j0Ju&_Ud?Wm%@m6?#1-m=OJK&e#(B99$vLUp?++TuM4`7eQ`tv9n zRyKuZnERVy*%vAsx4^P7G{<-vEPF%ijAz5LIkek&9xVGqJ=XvGVA&wL-S{S0_K1d9 zfBpizj`5-Pk$m|#ST>46{XPiGUQwveU%_*zFSU>SKMQx@9_sU-a2M_@Tb=t+Z|439 z?jgS?!7FeN^6ZVUY#xRC3r+A1H_*Q7K+OOKnoLUsFUTX=WRkn`I|g^zXBubh#v|Nl z?8f7#Qr7qz`N#CUeG=hi!)d$uzW|m!rzYd8VA*sE$nmHsc=tl>fKE ztE2k|^1m-C@2ooinlEG2e`jyX+;6JOkNS^nPBohQ8r)@nD#+iBumW`{?#(nTZaL_ldfOo@<=3atj|0=j&56cEtaM$>1 zd?_7Y8*rC>tSJ`$o3LzTO*VcIz6TES`w3V!vxb}df5Wn$bq?{WJ#%LwU%#E!#|g0P zX-$pvpW)Ou+sgPpBzFexvafZ8#rJ~_fIVcE3WYCP;L z`UA|cboo04mW`{>|C-_Or}QV+vFb-Qo%w0NZ;Q&? z4sVZmA>49Gi_?$PpBKT8MD8o#9TDFQKN0a-cxS|4hId8$@9^%3zYFh)_(6DY#6N-e zMf@vx?y2ODN>cuI!?Ha^HM{!!Gc4Ovw;?Cg{(pzVpX&241kL^^zGEbK>`(5hU)hq1 z>sNNALj8`w|JZ0f()%|07x`I19Lmod6+fIC?s)<%+fzY5m;uWURha+Y3x_|KejP7? z_m6978grhj5pjq%i(p zc^~rkZG2~)K+5loWfLis=W^U-A1UO2 zL56?XHVXbrxXaGbCM%D^%hpi{e;q8lM`1p`36|}nJ1jq+hh_U{zVRKf>>ZVi?}o!) z$ggYzh4jCVyX*wrVE%W&vK4fZ@t-ro%Vtmre*kyc3<|9M7TF9MVc`|O><5MTwce2p zp&);?et%$fx_;1l{fUUR-rNgw%&qdZNY|&0<5}-^<&*Wx*>Ly^<&|xokiY45 z?n~j3(Rg?lJSyV%*7;X^%QjDlPwgi=J)!*;;D6Zo7F*8_&0PyOMDbk*%Z3kyasBO! z;y!F1Sby9C%brhYza4P+3+0iGoRGfiTefjReg78!vW?S5Aob@X=t#0P^Sq@un(-3; z6yKY1myH>sasJO%$Fo1V*UyL2_hl<)I(`(t^nKZl3E|&P_?AdM&xB=5=3(QgplLVc*dWM3w(FWHz0?hoN#Hf91p z3CrG0;BByM&IH~G%l=H@`t<*Td-zlNhD=~Qe^PcJeS4h@%MQ$G##*n+7EBoL&GH}h z*XeNhQ+$`hvgtCHhidgQs2XIS9`3L|MmIgeVnhs;ZO111IzZxG#)Cx zAH%Z467~mv2g??VCP2CW1D0KuYm8Ojvdt3eL-j2?Eg?VZpR&~w++RyY$ZkvMZ)$JZ zZVBzJ^2v@%D4*7=vgH!yQ>|BJ*X4doU+Y!bc2Tt}e`APWc3y&fdn+tkFQd)#7`Zid0U;|{RE=?>r3`oLVX=Q3HiS{-!$Ch%_vy*S^{gmE}Jc( zKD1t!{gzNZt=DD4rIAEcpIWcWo=b3l6Y#5o z%o*lhfIAo;>dzVMybr6Z(t#hit`!`cVIn-I&1Y|FRtu+E4vo zc4XrIFIzI_k*Mld<4<;FrWtGe$+k=we;VJiGZW&|c$BS~cs$DPOc;+VDUWQ=bXa_! zgJp;2BIC`lY|&g|{Gj}AP5BqF?8z)K_dmnoPxX^K8~x|OR3ADNmOYt9JgGdA2eK&> z%B%X2eVLGd)rV}%1ou}HUiM~CGhBGd2icqn_46j&?}zDz&Rz0BHfTbB*Lasbn&7VX zlP#Lj=3nh6yELKwG~Q*KCbXB@Q?_XWt373>Ch%m^m#vxxi*Gh8yEUPGI$_za3GMNI zSaxgzuZ3mH=0XeqZCG|~LVkY=%a+Ye=Kee^yEdzgk02r0wh8BZuZLylW|6s1fo1Dv zmhn~c4>#EOUk1ze%@%Y2G%PzfVSH|ZWeX?puVC553GuxM%Qnt7i|@5eShACIhVk2A z*~$s>c^)jgId@xn*TJ%#Ga{r9%Z|>*Lw$RG1C}kFy%yg#IQ*%sDV`-ormbpjuOpplK8W^+FU zmc5<8EwF6g>^ApvVcEv{oRx1bEW0=_n|n7byE&&@d6&bokF&yfH7pxBL0%n#ybFJ- z56wTak<(@Isl2k66UzHV!iPWk$9wW8z619ulUkapq$hpuPIwIZ1_&RS+bVbTN6&}n z9*4)`KGfWQ3%5l6{{+i+&TY7B{2$7Gfb8hpVmuO-EuFwku6=Gwso#Ho(Ide z&cnuKSaxB;G?FJ--sJv+0+U3KOR2)(3EGxvau7~i?HnNg#5h^md%|I|0iJC+PT}> z|I2XrQ+sWOH&1S{`xrxWKZIpNC&;&7z_O=vr{(|mu(OwAydMsKim#V}BAYpvnEN4b zr#+A6yQ9X(z_Oupm+|l`kiW2v3XFGiSha@V~+QPlWfu(=EMoVcFqX zYwj~)+2SEGm)>QtZ0tN`?pn_dU6ZbV-FgN-0e9&K+HY@x8;rXNFZ(+|o_8*#zE9>` zq!!w`bR zvb%GuxeuGh{Q5e+Cv5x%Sax_qeN2O8i{~<{kN3i|%X6=B4=md}A-?y)vePp!=j-n# zShjjzvh$D6!m``*qJ{q&EZaS+&Hufy?D%}zcpEHRKBLV4lW_P`eLYjhe}ZLu=R7>A zzYIB-{kVuvf@O>6RC8~J!=K`t0?XzO-Pnbn1IzwS;36y=JbTQ2d0qGq*YR3dwsq7W zl%H?bxvPK6#!krZ7Tjk<{r88k?C%_~@Y`Y8-_bBte7}TcgJ-?*bFl33%rbrvmQ9|} z9>YjT_IXyA`x}(7{i*zUST=et;+f)~Cjama#;?@f*HQjuvq#a$zs9HR_k{5|69?Jw zInCVP1CNCpjl1AkF#ovl*YHF3eVUD{@YaYw2+Q8jCFXt$JSFPi8{laXZ-(bY_4xx> zHi8;0{G+h!1%>|b3@n>Lf&U6`i2NUUKKX&qvGAwDvL|$!@g%rm8sDcjJ{OjKq1nc> zVc8gZ=n!9C?VoK%UYvrvNEa6EE_~& z{5}cG9??tY{v0fuM3aqk)6rMpX~rkQvQN}zJPwwPqNj|{g=Md3qwyuMY!+=cZii*R z=q}?5EE`6lzE;ArXB66ZJuI6>x0?U&z_M?&%=mFw_KmJI-UG|V(KzFO!m@Wnw{!jH z#0w}79Qyw_SoV*C`%G9iklt_p7r?TI^oVg4mQAGP#;ai2M+*Jz%dl)Dh4FDGEPF}! zn*SfbvYE8W_-TcQuRhG@Pxo~mp}oC6aY*h3++|ZK^tZpmvab~6?a>#qUvpXNuKm?r zgg=q^)n7*AE*ndWEWL@aY%I+;o-TKIhVjL)Y$ok9?uKPQDdcwrEE`Ipe4mG9Pbsw5 zov>^wHCp)pgk@hTtRFN#zC`}yuKfKTciCJD_5BZ6_Lo*#_}9FH^#y#7aWgD?OjC{L zz_Q5{+M^$qeWrOfer|+iqv=WW{~1{JnuZs#~ls86Ny^&Pm&hSMx_|1Ke{n@(YWMDzVv;y)R8m3NdX+WsU@bzUnQPc)nBpE?hfy{Gex zb>1SIPr-e3MtIqB3hoLoyH0U<*>(!<`MU7BKPa0{V=cXNaF;!&b;g&&vgZ`!!+cma zoSw4!U2!fR?Jtx^wwuQAO!8jxUv`{AessPnTTTp1=dSc+*D0jmL;TaD^}q`Fiby`M zhUZ881-L8XJ7C#Y{;fPe#a*_at~U4Gu|sMvtZeVT4H|zSHN7OR#J_h4Feb zEPGEu{(K#l&8OMs|J!i*Q~j&HW%DVnZ`pqe^{w*`*?_vx!fQU3J*W}JAA1wy3l8x= zK>V@^HNwif6PA6bQ$u~gvJn;P_b3Sl`%`{iUB~M0vIRx8C;dZqp+bI7!N0Q)W$tf* zOHunyg!iG(=Z0xK4b4r1Wee&)^RM}GMl_x;#a(uyo-p?=Shk@;{SUyh6Lp%oe-I9T z%D?2pJmL%b`)b@}x9JY^e@C5vl~1;sLiscvWw$AmPyJuEn?ieRCcJDnon!I+5SHzx z6OA8-mqg|NEi4;N6V3evSaz90|2X=cIM|=^U(X}!+)t_F)9bjYj_c!_TIc?bI-Xs} zbL+TJ$HhACtK-FWyrPajQpdlqT&j_;WtP8D&h-&>JOvpxUr7kT*vu3 zKBtb)hgUt1tsu+KJL=r$)bW*d+*Zfez)Swb{AuxB3$KJ5j2FQhBlqjzyWvK2{~){r z9&7v&IJYkyFRS5+@Dy|Z3|xj8maab6!)xJ2fMO>dz^E zAD#w>`RD=oZaAd(WB5rpr1vQNGJK1r{{+11g;byZHQe-`Tqla-u`qx z`3t-g4)SdX=cE6GLwc`)PyK7EzmA4W@YF+neT;?g{2y!&S^N{=^Il5V=jXtaUq)Xu z|8Ix49!T}w+3=ioe0P)Z(tqZ{RapBI;;Y~#Ur6sC&WBgQ!Mzh+y*_pCfy1Br^FSS6 zU&kM<<4@J`hC05zjyKowckB3vb^Kp-{EIrSAI}=UjT>smFCU~&^#9+~g@3k=_to*= z>v)JJa{E(#9b3mI)^UCQ8tdHOQpc0(czPXQT*ve3xT}uq=a(gQ?knneWgV}sWVr9QH2swJ-Vi zDUOFvfS)?tpRdXNb?`>|%P`tl?w4PMzRdkk=?`*m#=W#U@7BxWbKymA;M>^d{!aKO z4|x4g?w7!;Zt?FsD84IL*sZ-Z@AM0~pN{*Ow{xDrco&!8XUFH8_8jT?gK*Ou{rh`z z|0q1-Wq+Sj{1v$Rv_F3me;1a`^7}16+u;=t@xGbyFW^y}FN}tdN8fu2-r3;qizxh` z;M|dX8`=E71h208{SLVwGY9!H$DhxLN5ZmEbU^-jiKPJ^%KfrqUHpgSCcv`ctn}o6 zIy~-g{`;`v%i+C$_vcaK9yolDcR2ZbAN&OOsc~}c@o{*{jsCud{C^#mz4-Gi{(Im# z+=tTqqWXRi9&t3^EjRc7f@QO5znJ{~9G1;_%_oZQMdZgu+V2eGUAXTVihj)BaQf2= z@SWU0)_PU`hh0p6SekeHed5#Lai{TJX>&gluKpnJ&Qs)mK77FLcOK7q&Xw?S$M6km z^WO&N{^0ksL8_{R!?v(fN+^67q1No%AH_88N{ri}T z?|bmbD8G-vYi}Okbd(E!NNx|jeQe(CZ_58);AiKj{p+Dt$s+;l{~X{(Kg55X@*^|co1TKe1JTf6-EuHt(dp2c~&$_Lt zX`1n>cGes82bKk{d}rbQli&OII~D&_c*6nmYwnlA>;F!8%g=mx%PxPvTK<>8Ya;nG z^=kChbGiR#{y&0y_1L_7e^mb0!m{Tq{Yv~bc*#({BX0cfuf;xubILfy4LBRp0aB^-KKy0mZ)r9(8>>em()uVSh#I6}jIDKhJ#he&g5m z(_i1_?~}>>LEITpCcn5p48KhNLx0{4|74cGA0q$%4PSJNzh5Fg>N528#s0pe_+)q+ z?{|$PR<+j~;qA1~3C2_4M`#bFs`7lN%zo4b%rDlzXW>5F-ltOdK6uK@sXV{2F8msJ zF86mr|NkaDhW;1kul3x=IQ7rSSBw8^Y@D1#`5Q@J`Q3{D4R-%g>HPve?p0}do`r`+ z?X?%)`$Ut|&lP^kb?ndl(Cgj`#N=6kjhqG^+o5-phFj^&RSO z1@5v@ctG(n->ihYn13&{_`d{Sg1kJ2*-*))KUp2Y!ZOi{B5p=R;Kh@HE3is2-`u$D0?}s;%Ua0@WRbQv%n|@;T zdm$a|#P|695BVRB`<2~!xBn@g06$HCIK%w^3%vCZFK^|(wiWp{9QkkMdoS+0Z{d91 z{13nl(Rlh-c=A{M`<@EF8a`vdpVx>_Vm$6Y+<(77{3YDia9$VW!BXVyZ5O8UVhirW zqxiSM_peCx_s8H}QGGrKhxchDzyArJi2R*u`8{PG=P~FXEyizzJC`y(tbV7!W0?<* zz+LS>8(#5CzTa>D3-B=Xy=BHF`1Y&viN3G`zW)Y)ex>q#2A)Uz9Aoj_3Ezu;9o94V z!dq`o`|G3dedwPd{{MzA zee^KA|KB+uR(#029q^P<=qDC_A3P8Js?p+q34ZpEY5g9FKDn3s$&XuqYlL&rc$@@p zj@tVj@DQ_qqV?9*@cT#Qn^s%+GJL~dQu%T{{Ll;eL_hu*Jcsz1-dz2C1HR`|{`^qo zdjQ_e`xqx#es{q`qW-uSmQDEiR^Auk+rG~Gk(U191?FqyL!*U%6}$<3bGY#duxtlA zeUtin1H3Pi2h-rWA4=zki{XbEe<44e@O|iijaI)Ogx6f=_ZyY}Ps1IYug)Sp_2;j_ z_eT217Wmz{`bJcH#Q~n(?8+)%)fIi|HsW|ygh`yY2y>%>Fjq0 z`EUx{M0{aAJrTZhCiXQfzcb*;t^WS5(w_@I^vQhFvpL_t+Tq=-Kc6;U1V6(2u0dXW z93I8{#aEd77vUD#Q}v_#e-Hi%`bg-{PrxHtKTpG5{qwi*cGi>2#Q4v((q8NR`=jEK zu=GLASBh^8{3QKp3SQ+t5qA18d_4N_1#r_5O@4ie`(<#jUnBn=@G#bQbQ2eTIs7R4 z+%)5x;XP4$cfz@7{`^mP9r|ww|0FEi*AFN><=G7%%KA_frqX*69*#Z|`pe7kL&$^4 z=6*~YKhzoBKYxDZweW3x-+*O+3qKaVeiQr8hj^X_pTzm{Q|5k&!Y@ztp%Ofi`^M5= zq?^E())aV6yG_pY>2u22kL7&{9-;G?^nS~UPphj@?Hb) zMSoOz6#hE6^C*8mSNsw9?g#z%ImBz=4)l-t7Jef<5Bc6<;qQT+zU%UTbZ#qLipu{u zyeJy)d*B1C7w1@fFT?xaoz6GM6Y-wclA zc`jo;@G#%sxX0qZ822ZUAN=FWyMP~ii>dy-3=a0Gw4Zb%EL-MN_3y{wx$GB_9hctk6+Y^(`{3zUr2AQ~!271B{ppw@^CRo+(=7a} z;i<^SFkinB-iiJd(mxB{8|icB!)4YlH(B_L;hspJZG-1?ANYE6e;+*TB<44(uQl-c z3I2Ru<^3w$G9q0M-3Pb5Bi%pz34AyEK?JA&9+`U@K7c+N#`BodSr1?1?Heh+eYkHS zJ`GXvk#xjcm!<777QS*d-ya&{-KWCSKE!=4Yu`)Zqxbpm5h;8-{0Q>#WS9OSxqpRM zGapa1_-}-dLmv<0?H2eh^o8@x{Z9DK%kzo6{XQJ8Z+0zV|KNP?`&<3|2={ou@~7}L z=7W&_9(W`B8O`Q@Kg>(eiTrs1eeebLuY&v@v4HZhzj34Gr}rA>k1sbjJ#FEeaDRmL z@@U*8uipvZNqbK<|8wCNpXGf8^WP26MqjI%`;G9^XZiC>)z|0Xmm+=R4#I7J-hW?1 z`<4HOdl&T?()%fVfc}Tt?%M08>_0a$AIe?vJ&XGW-dEjhoMYj&=lOL1@MQQT_D^mw z_wjI*_qY9i#n9Y|@8iBqPm{aPt@tj$eJ%1R^!Ll)x%9`7ei7a`)ZbT^|30|P{&SDT zf1})^{f{revK_cc^}~4nI=o%|?=YYLt?-sTsXp}+$LW0Y3;3l@|GtFM+Y9eJA)Q}` zbd&!d^F68~e0;~l>zFTQS$@XCe|#eE?qewY6!;3{!Rh9HK0Nf*-rknnFNPmL-fcJc z4tU6Wd0)xecR9Qy+RyzIeB8;bkIelJ_~{e5uVVatc+5?yzVu_b;ZN8;#9i(EOZbWB zn%(>3O8*(Sh58Hn#{a;Vu%8*)<7oQl3ib!zO#aj#PlH>&#r~JdPyN0He(Hy`pQS$q z9(}Zb-%9bn8y*s^$FG6+a^K`aEAKKm-v3w)$MX5}@Xen^V8wzbB*TzN4W3&lm8xu z^8X9?LgaCfmw$yDsh?Buul7EwhyKa_$r%>@4R96rP@ivwA4fk4?(c$ci{|%E_$kI~ z=>IF=o9Q3QkMygx@TP_Sd|vtaI{dxW@BEF{*^rb(+ zw|pgCKOBJPqTdC5@8n*}&w8N4!cTxlu-{0x@a+i?`x^US)}JqjZ+?OGrMb7l9jt#F zjZ1I~{bdxa`uYGo{g?Ts114|20AIp>_)7DCkKB2GXN~bs;m<|;Sx?eFFetwt#{({2Kgj%Scy@v(G%TLSNn#=|Q3K&0Q? z0iXC+)`M0b_rf>q!`80JlWp(=kv{MwT#ClqU*P4ek3#tmV}E=F`}HFzpW1&Eyf&Jj z-URPp{XWae|M@HFU-WO?&r^BM!F@=iZ?>>MJ9#Gif#yC7_c>qi_haS19q!ud-=7p$ z;SuBb9*Oz?SGbY=xiG(d2A1vlla9q7o;JYC(LdIj|2yIR%$Khxe`@a^z_-wU$fnER zWANtayzCkH1;%4&&%eW0b6>L4{10bf59> z{El>gZ4%t~!Bl^KH~jJ!{QHV3ZzsGP`F@P$_d0kl`9IQlHGBj8xyADHS$M^I-bb|Z z-U{CymFEZWR`iosS@@lB3;WgEV72F7xcNHdn}t9ATIQpuKb!)m`)#phiZ7)11FnQ$X8&=M`R|8^M(gL*@SP9%?{BHTzl1)v;v&uyt^PiT`&9M^ z&#~}dgJmmw`3T>i?}B$krc!hOx{4%W(6j)Ai;s z#^0)=>koeA%a(tA662K##>EWWw$qu2WT`l|nKcq8*oqq#4IZ)85z{GsxG z41SXOoM!Hyg7?3a?hoDuFS#Zi@85zC{aoJNcUJrl!w2~O##q9?9(`yhJTj`^e~K9| zN8qmV4@a?nAnL!bgLg*ldk%c_a@K#gUYP^$_^$uHlG5vf{}|1mABL}{{pMKy*T6%W zzruL`8oc(f^t^Bjyc~TX)c@mf3-?31Ed1}_u1}= zcik%OM*A6me&tN~YQCq}V)2~~-xJNhv*7i&r}t0Z3!irx`ybZc3*mKiZCw=v#7m4;t~`w;X8rfJu|Ho?oI`u-ujGUAVFqP{S!pO4D@4EHNo zf8S%_pM-DxXsVC?H{8g1OjsZO4PK3WxWxP)y$Jcleq5-}li}6xPuEjt!7FY~^FI~d zkNgYr^t)};*L3s)tB-f%erI%^I}g60iStHFuNNK_weJVumB=%kX^$gvH^UDwKj?jO z)!&!lL+?f2SbJ`Pr!hW5`j5d|m@h(kcETgs&s|~Z?SpSVj`ydHbBh^|?01Cu?kIRU z^Vf;yJ_?@tBi<)D%BTNEcvLh#&V^U8{*`}?kN3cLAg?d8@cr;{+*b|y)N**_Rq1_) z55rASfBG!ECaTZP@G8dNFpGa1yqxv@NQ?g`@;}VKf1vvLH9REB-{0VoFQ6}5{ToM9x@aRNM&^N&X@|L4MG))%4u-vzHjUfpW$^Wa^P{2asn z&@T2z6u-*kglg@!AnLpCHo!kg@>ZQQY|jO6?pAY>3+p3cve$$ za{jpve)o6K-}uvh<8AOp&Ko{w;r|`J|IYOM;9+=2R6o1nX4WfrnEwNCiT(CA<6-Ql z42$~zSa{8E^G&6oS@{cqua>!MV@{u%uEBaB}LkQ={nLo}ZM0MCl_`< zyZZN1_)he*pr3yjp7u;W*A{9c}UbZ4vVG)9L-nIk+G3jr6`&4?N-(|2-4c-)gvp{kIT)IlO}PLePh9 zhMz)T4)e>W*@cYeg6aA$as1!`B8t#RjRG!>OiTmpuK%uf38p{F6pl3 z78T2t?*6_)cgMK)TyJZ4AOE!Vx0Zzq^Ggb)UVfBIy_E%pO0lnlV3mPNiC=}*N^haF zyRW;_l?#t5t&56<_DZ>uJSi6|)&8Fn<8$8%3lu8;o}TtUnJw<@4m&J9csPx%#|?&kJ07v_DL z6Hh!WbQBk*q4YqR|Rutwcgh9!a{j*p|hv8uCbC_`SI7w_;DSpqb`Ozf0Z5yp4N_zsADO=skgTNj=Jhg z-TI145CfILvQpc6t|O@4=n@RFtS*syY40yB{olRRM(+E3p;)dfM?4;Cs=K|bzrW(! zvC!LJUrTCz*T#iXYq_3l9uM$+Xv1JC>v%Z(loJ@8MGy{8d@@& zyd|^TEuqOLwiL!s&aSbR%vxy4Z1|SUg11=1w+?g^np-B6vOQ(i!-UNCpO9Jb3D*8T znNnu9CuCN`gv{ojkR5|-{_%y5>^x+aZ9-=AO~@?qL@&7q5wH_8Q=OREsqS?05Y7@u4i-!!R|omyraot;_o zv(Gk(&2n1of$Z@8)%@xiU(%t+AbTnFeK-;r;oWRnJIu52wYpRMNQ(etuO zhJxpN+u0Kf%@YPoDZ5shvpYs}b|s+d`IPc!^MZ79wsMotR{iqXx?djUFRM_fd$maw z7PH*T^qE~NLrp?8d*+)|i0NRQ9f1M}I6AO?Y~1d}ErsRrrV*_vQJTNTWs z3tFX27>^Vfq^SoHH`(f79(~Zqi7;(0G!4?G+4^A~1u?5OTS7mXR2a{w9z@J!tBCn* z9Wfu2#EyxDmZq}@DSEb+n9o)d^Vxc0enO~`d~<=f3=QlmRzTUN@e`usbtoH-fGV*OLoc8S(Qr5psD0DMQwAo_S%g0nw2>Es#2LS zcq-X-kgd5k=d(-B4y0005u&ps8f*s?FKDYV#nQkw|%!W%A&u zWYh0fM&o3nR1o3mBfW>i_9+#s_|GfHjNU`LCMr^a$6bCuGZt<^T82)a3H&|ujT z28C8Vxv4N{xNHf7YO8Sh!NXG33a!F%;x$OP>}}CzR9l5>89ZEe zy`a=8+=RiyW!DSpt-^83V6c2<*9)qx!c7`HTz0*nsoc+7zV25~4~Mw+OZN)=eGJ_%(*2)B?c8K37q3lx*maE%pu=uz z1m=>3JMB&UbMK(FhbtkR0H@E~0dVrDx4ZTn8O~J~SGsjGW3oW_Mjw+kLI=(LrKM9Mhtt{wcmwY*@U7d;}wiOXCIiyd;H0xRvVAfLJqrtaw-?o(c@1)k85b7XgOV?0Bov2Dx`uchg&+Dq*=R^&Yc<{}Z)<4@eWH$Day7^++@RqkQ^7R{W zG{9}f!h%wFzb{^QU+=&YcY96lR&s`ou23aCFFX!y8dx4`;tvjFEkv)H^!+aB(TOkh zMzu|i-%xedC!AYrPfvflZo&|>P<0pFlwEmIQCv;s^viD6Bq9P4$ORwg#|ds-1WJUy zdu&xw_f-9_?omfK5>f3)_mkwQjV5*NAE+MetO}_OpkmiPL1-=Mk+7En9|D8Xm zs*AeI)s#wIyq)G_(PkDTd25p9pyw{EL`}7*3^>7F=;eY}^i28CqXPd|=8|5y?P9ebm=q?Z)C;iB3ahQvJ*j8Y7f9@)=x9+~&-66?;m>GR>haxsLK8e)&a3 zls`EQ+U^U}NtAoZRo(OJ<03X)u+q=$YxU64y{KC^`4)DU3a!=t?p&#?`+t1{y=_dT zJE_45xmmg zRqPnx&Z>%)%;;_sxBiwq<*r|;x>UZBKm}yX!a^VNF&8~llXi74=#to^6#ZPiUTTT* zx-&QO`j~<$BJ*J^!FC}%9Oafq|s8~pF)4z zHAo!Sb^QaUqS!_C=n2G${pn|rf!O+{f z#QnQWb6#t?%*9~$(@DhSSD_sR!cnDrS<(OM>E>N*4dw{APcmB;r$0L zha)r?5QX*u-gW4$c}Ab~UXWpWN5O^TNI|+UVR}&Z?U`Nu?V{&Pe0q;1T|Ezv+I#g* z2DR^ca!;|(dM0lHaH%!to|0IH@AD2d{xo!mu77c1aVyt>(P0LPIp17`>e5n?j#bX} zR=S9r|664GrNE?_<7#x5YkWueR@Qan7B!wg1^%&_q);L%VYy#*(^2KtoJxw8?|jjr zSy3UTU5z-CR%q0R#iXf>)dZE(&qfl$LPeY|Gazo1XwX`5km}rKK9`SNjf2lQo!qDmGtBsK#-$j#J zkDW}7G(9c~`0#sh)}4I zN?99tpik4Yds`^HYGTnQtsc5-rKeadv9K$KvFjxrTaZqx^<&6A>+IG(r%%#aU)g54 z7(|Obt!YBNDjE4snzrtF)C!S{EkhLEb;3|NN*9fZO(S$&6}>iFh`50=yGQ;7wVE6k z`+RTCa#O6lo;a8jN=ufL>*Kz;-3VeO;NB0lLKB2JvZsTNfw0typvJkYAE!ZL4qYH| zW{*gMx;BP`eAPPF55cH*t-PhyrJBz(3#V7wq|WFi(7s|18PH2ywJC%Q3{rLVQSb(8 zZFs^Z3)-5xq1@RH+W!hm;G}Obmb|caGTQ&_E3y)5yzVr#XWuWx6FJ&jDwU1So zB1j)9bJ_*f(+clfvbOYs#JzSGCC2K5m4lW>&aaQG#xM1oChMjkEyU7CejciQrZuOw zsa*0-fJto^l?QlPncqH&&^2AI4u0g8wc#iJ4RrU|*1zkmU4qR7cS?yKyvfSBUaU16cKV#LP zr7?m&34pF$UZnjs*R9xQ^YyI_H($+EY{98DIrkzsSaBQRjDRwdj5QH2z7Mo%b(JDC^GUaxQMQOP(xa6721J3~V5ZB#n1-j8lygmlo#k*e1Y<{*#dv0y`5BGW40 zhlw58FEz)InqrNzEhO6{XT^4+Dn%A!E;HuJJ_WBar_QdiQuHmBau^hPWxSmoQL0xz zS=_pc=BMtY*;>~(yxgOQHq`2#hIn;##Yd)JQ7{)*-7_Cm-NQI0%ONLjI*%)MoT-yY zGO8muf8gfcSEYW_lgplkK7F@=Q!%fuixUbbsRFr0;kP#W6Y`n_{ZsKL%8~b)>tI!$ z@t9|4`t3)pY@E{WS35lPs2?+D&zxJBF>B_fa|^TIHT{BIms6Go`np=#wb1bM544s@ ze))BTN6jBvM7!dY`}_TlhNJ#+3E}G(#0(?l5xrOYp{zSS6}2jN+l@632Hc9yJ@V%_ zsTbqOhnj*!`W8y9)&5`E1$2+`R^#B-xXOw5!VBHnwMhM!`bz^kdC-cG(eF;Pe5LpF z_b=2L%|M$ZRvN-TmzeO&8{+1R8d};~ku~Nxly$mZD1JDsjom^(RgB9!j%hOT>3Wpu zP>C=1ka(+1VySocbfE8`=X&JoJoS3egK$iiBwh=T@k&MUf;La+!on6EG2Joz@h61@slhRN!-`Sxj!fOVKx4fahnJO-~V03h3E@Dt~>(x$5nt!1{e(&w&KOsH{{BlJ?=DF+t1)0Wy!sN)k3Hj!|(zF7rY z$3(y+PSITncafsLqa%>4-qSD~_AKV>HhyHd8zxD%TpT`ge$|mAWM%N5vN>pk5R1?B zLBp++Q$)6hyq|xc(7eV~s>IR)y)t%m{l*?eG_2C;>DCdJOOa6)o%!oP zy5b#FRqmIb`R!$Gtf!AOrIP{Ilp*s;Am`+cw=KOh`;|D8o!CXG@D!HLt(rq?#2r1) zb~3ez;PyRv)S+eJBBz?Tc^JP89qp9oTwvYC;=?S(1>E1#hPdlXQbSD@(z zCJoe?j?VG?=pE?sKhVTFIxG6dQYU)^)q%cBcZYJ@T0uwE7P5|H<=Uy0YG=1QoRx=8 zw{+EUtR30+ws-mc;okP%5*}!__R>=SL)W0rtW*b7^(@}}bAF(k`zL)q43GK}$G*h1 z+V7VV)iS>d{6>p$2PWwKi#n4m@vW{l54pCU*1m<6arxY`V!6Ml?_@1z%nT@Bt!@68 z%qic>u{)OL-%hu?t{)7RPI;|VJNQiVKy|T>Svwawl~=zOx4O$^Jss74wH(KCT!G24 zjlIbKUgm!De@fMxD^|KX`ttf`pydAP=$q`x{+Z~#@DKe${#k$Jdh-+c*ppWZI-#$8C#!gp1qh z6TRwJi`(_XMeQ0&!8%xYD>o^X+}T3za*o@ zkg;YzUFqz%3hWm3aPit|XEXm2iTjsBPxmi1TXkbkGokyz*sDfkuhLyr75PHPg&5H&*VN;a4$EibmE30b{GOHpc)4Kl@T{zLD1g=#=NnGLW z<9Xp`os=Nu#g!?|xT`cx>pVKB0*KEY=V@a{HJ|ESGY88(nbzteNK*W-22(i>DINSWC`L zTR()+#HPWOs3?j0;6k`#k8nPn+()G{O^b0_sJqY5t$T&Uh?~>(wXH^C-0|i~aGqfHOnY%dnE9V+J!wUE&BfJlQXT4qXLhsQvQkQQjM7hFwULw_I-W|5N_R;k%CtUeFANM8L^ei(y=uBOs zpF>sWOZO1$UWO*&Za!65L3v|Y;XbPv@)Cb%cTFJdMFT|B&lUGgP){M&C&3%O_7kTNTmAxXwr($a$PS-gaZuN6UtZOh*+FjqZ)q`|eHyrrk1cN`lSy1Gf8BHf= z*I5djsBsm}OR=;V;c6WBb^JIxIJk7+fj+-ju&XE`qd9j$)>oi!BR3JaVP2#;_VCX3!~Fhy+BL!% zg_{vb$mEiW<1bFBITP{2py&!CpjtBm@a4o7|1x(*?dv)T;=o^*B-53kRnxT=%|Tzj zRLb*QT~M4EuDU5vI(@8JFzuola>dct3AI*pztuM*Jt*lq>JpOgIu$>-38j679dj?6 zd`6STaaHOiErSzfF{%i6SkGOk65ZdM z>83#PD#gl%ia(ZdnxC?C(5&q8g@d)ElQQXypljJ(EGSqWcJms8Q)#qI#hI8J4DL9I z^`{Mgx7mTa8@t-8E%2>kCy#XzA+2mb&!K&4`B>X};fTvRkw37a5tEtAeYsT1Fc+Jw z5*M+Z%9`9QjIDljW7rEsX;E(8ter6F_ih}xS-P8DDOWoth!p1F-AC3U+772HQNQ+v zlh1|bvgj6uimw|fy4SU+l}c!hhuv=G?qt^A&unjk@u7K|+kKp9Tf?;GUDTYuYzdqf}t}K()!HvyLZpw9ERoXQ^(a(tPeEnn;ez zE2oZ9JVFMTn$qq}mbE=&^M1OMr1rLM8+MD+UG6Y-mcmr#6;1cp4@0i6^m9TSZbGV1 zWG~G3HRJf;8yr-bKAs#h6}lZA#J&4tE#vQug^IMnVFyh#Kq7M8y;dooT+?*Zoo;;w zAroEI(QFj=2QSoI`~|;M)rd&0!?_V1x-?hEOubDM!1(PcYY$110!=2V8tad)IdBAl}Wt!&VD^?}iJ5&c{)dQ)&{z|ZJM}#XoE|=~mgf2XXHC&B|7pT#k zqzb1gNjG;JXh9*pnnn)o+sX<0yIbit+(Hfx?h&pR+I;1=bKLs~$-tutJ1dp$=2}^u z^b{J;uMU%C9mHc=8^EAI;Oo^TjoetvUmrpoSK3kvnf16!J^%Gus! z`_@Ti<=2XhK4q^S`L`dV1$U6>Nz&F#x^}9|Y%Tyj%Pm(rKg``p`EaRg^HCHh7hKYN2h7)GfH?W8r5GTG{kI2hg9kW%BOox*7pZBj|J8_4SiZs$!C z*)ok*3$1yX7|54XYyFJo`klXKMPRa}yrg=d*JZp^rW19R+);iZ+)LL%OP9aVLCoqF z%$>v|{TI2U6}#JP@n@HEcPsCp)*uqSMD#i>ce!}8M+;bYk13rViP33aF0K&xVDY7m zi*U6pwF+VSsfxzfHaiDS;J9&q@T*Rda;Otv*H-p^N$B3D)Keh0TJp`C=(eT_rtPDG zC*3|sNgV+4eo!Kl^ro=u2w^OS)+f(yC(FMQ5GHtEBWWf0OMqUFaQo421aYH;Y<1SD zOkOJJdfI|&m(%UsdkSHF#vXE2JH7=D%Kg6w>Arsc({8LwK)R#r;%Oat1y<&3beGd= zKf2fzMt`JSy9Q5n6Dv!H-xW-izMwHQ!A%!}{Hfd3J!`UUB%5>AOwP@B)?g~1ol=cZXX0>(YUtYY_&9^fzac{oO zM7FBRoE$?f#;?Du=VvFs)bo-_uR=PFCFw_6Pq}_%gC><=q0z_`&Ek%E4r;a_ihTZ2 zE}6pINfu3<6xijR!D}tc&`;Z){a9X7W(Sc^i&R4QtC^s@gt1x5^cweU5iLS#bcman zu<@@Q5m_WIwWg}ycuiK%ZY`v0PsW+Odrcfw1?Z~ zjQ88HVVLY# zGu7_%w9!*|FR}JypY#aN^vx-L)xAIE_dNVoCXF7Jv{=}2t1*9-@}Sk7WUQCW{L%UK zYfbLe$+{OhQ=#DZ%ls-anLkNg^;x$$t{S!%Z>1E;$HG=G$2xttHKB=vm$|0MC;i_k zVd{|HaFiD}p%QF!-t`DSG{c5;?Td6yrmD(unl)x-lQqHjH68Ow!%T%Q|x07 zbT~~T?ansKQwdflG_y|Q>C5f{SrGc#7fp{jLKmb{DR-_zWhr&;L#JVP&#%DPI8d*4ge6NNLi~D9K_zYNdkgll5zAj#hf2}PxC;mn^&2vsMz+>5VC$C6lQvo);S{I`ulN2(F?zCWq% z{4n ?1|$#(Sh4=$t3N7_>B!s$vj=SD4u|Hzrb|}`kuO$-!E`aQt>I|Jr{k} zA|2v>R7gu?d*0oHbfMH{#a=Clbv`4(=`Ta6Cfto6encw1-{Nu_R_(z}=oZKqe-e|7 z7Hw`xZ42E$Jz^(q$#D&8-PzzfW+WEmq>3LW?dBF2iH5w3gj~CQamADFiF9zij1hxM zK9O%VE08~YuNjhFF2_;0t{%0ojR>pVr0k5X zxP1GbrX5Lyj>|VsykZe*MpKRLnWc|>^O}+t^o>L|xqU<;a;reZf4VhgQ zPS!WE+tzj!e`z@IzQFEw6=q&?@eI4TMJ_azMw?baFFWXCX12j0Srm#-`$|06fUi+a zlD!)DQ8O)m{p3?lwmsBuy{HTu-dtDnMr6rV&^se35N$=fz8Sxlt6i|0=;{~H^-d3_E+w_yoh4(i?ZYcr+&z!8kn}% zlJknRpV@$nT2WV;d?rF&YdqW0iAyB36XMVg$E1SWOc1^t>n?S)X{*HP<;eu$w0Vw= z-9Eb=ct)3!sDFur5Sg}7!r7r^$88Damgw@*T&}KP>fgaWD1I-c{0W0g#(zMH_`?LO z$~3v)I(AS`>1MHV>c)SNBN{`tdaSKlbsCPak~$`C6Rj#vsIhRa6<8bk>eWf^opvu> zzwVKhCOL!)8;DNqreC$SQ&`RhI9+#rNVjCD^01Mv{Xf0}L7A46!uA%5qx)#C|L&x& zRBK&PH`4qJkz7soM+&vq-a_A2fk>69#BQf5{JoG$SQ4NN`U_STPzy8d zGTICFToz1j%cm6+dXn39$6qg)J@=CL6z05Z=IptCoYm~x*%pGXVZ~=xE_?c_ zgWZTwc95l7xq5v`^MaITzgTj6IOnN@gxYcv&>G&2DUFQujZ5po&X>B9>sGmOeqV!s zIm>3{I8p3+Dx4MN z#<~9mfz9nK5@De*4$UZO8^`+;7D56ew4H~llje!qo(gTHzBn}@&P7W%w0{D`0;i%v@N%w<;=kZ;<*U8F2b_!l zU&yPH2>x;>cz^rOiac6`ojlS{S7R4oz@bPCAu)Nk-%DbDThD6BDQ_A6R@&nx{&jzy zLvpI4@TVa9?-Tq-nx*i31pZnA@NbCv%h7K+&%oc-3Hs&#R7U;X#eX4;c<8zzxuz9| z>!2ZtC_#oxhE@zAAU%mkQzk zLWpNT#TV*j!}8&|*Zkf*nVa1A+3(=;?c(vd4Ifvp^?xBxe+R>Fxm@wrSLfEw^nUdJ zP%rY6h9>^0BXiR}n9H5W^G>Qq`5VrENAaKQ1N^JMru#?c9(lk2t^bF#j^}smFL&+< 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'