From 214c06e79ae9c65c64b66d8f5fa7ff1f19b705d6 Mon Sep 17 00:00:00 2001 From: GuEe-GUI <2991707448@qq.com> Date: Sun, 16 Aug 2026 00:24:26 +0800 Subject: [PATCH] [bsp/rockchip] Extend platform and peripheral support Add support for audio, display, Ethernet, PCIe, PHY, SDIO, UFS, hardware crypto and multimedia accelerators. Update the RK3300 and RK3500 configurations and validation applications accordingly. Signed-off-by: GuEe-GUI <2991707448@qq.com> --- bsp/README.md | 10 +- bsp/rockchip/dm/Kconfig | 5 + bsp/rockchip/dm/audio/Kconfig | 48 + bsp/rockchip/dm/audio/SConscript | 18 + bsp/rockchip/dm/audio/codec/rk817-codec.c | 426 ++ bsp/rockchip/dm/audio/codec/rk817-codec.h | 83 + bsp/rockchip/dm/audio/rockchip-audio-card.c | 641 ++ bsp/rockchip/dm/audio/rockchip-i2s-tdm.c | 515 ++ bsp/rockchip/dm/audio/rockchip-i2s-tdm.h | 99 + bsp/rockchip/dm/clk/clk-rk3568.c | 10 +- .../dm/dvfs/event/event-rockchip-dfi.c | 2 +- bsp/rockchip/dm/ethernet/Kconfig | 5 + bsp/rockchip/dm/ethernet/SConscript | 14 + bsp/rockchip/dm/ethernet/dwmac-rockchip.c | 959 +++ bsp/rockchip/dm/graphic/SConscript | 13 + bsp/rockchip/dm/graphic/framebuffer/Kconfig | 94 + .../dm/graphic/framebuffer/SConscript | 35 + .../dm/graphic/framebuffer/display-rockchip.c | 741 +++ .../dm/graphic/framebuffer/display-route.c | 205 + .../dm/graphic/framebuffer/display-timing.c | 178 + .../dm/graphic/framebuffer/dsi-rockchip.c | 1027 ++++ .../dm/graphic/framebuffer/dsi2-rockchip.c | 703 +++ .../dm/graphic/framebuffer/dw-hdmi-regs.h | 256 + bsp/rockchip/dm/graphic/framebuffer/fb-vop1.c | 1113 ++++ bsp/rockchip/dm/graphic/framebuffer/fb-vop1.h | 101 + .../dm/graphic/framebuffer/fb-vop2-vp.c | 1142 ++++ .../dm/graphic/framebuffer/fb-vop2-vp.h | 121 + bsp/rockchip/dm/graphic/framebuffer/fb-vop2.c | 2769 +++++++++ bsp/rockchip/dm/graphic/framebuffer/fb-vop2.h | 300 + bsp/rockchip/dm/graphic/framebuffer/fb-vopl.c | 641 ++ bsp/rockchip/dm/graphic/framebuffer/fb-vopl.h | 49 + .../dm/graphic/framebuffer/hdmi-rockchip.c | 1090 ++++ .../dm/graphic/framebuffer/panel-simple.c | 428 ++ .../dm/graphic/framebuffer/rockchip-display.h | 93 + bsp/rockchip/dm/graphic/logo/Kconfig | 5 + bsp/rockchip/dm/graphic/logo/Kconfig.path | 10 + .../dm/graphic/logo/logo-radxa-clut224.ppm | 5139 +++++++++++++++++ .../dm/graphic/logo/logo-rockchip-clut224.ppm | 2181 +++++++ bsp/rockchip/dm/hwcrypto/Kconfig | 20 + bsp/rockchip/dm/hwcrypto/SConscript | 7 +- .../dm/hwcrypto/hw-crypto-rockchip-v2.c | 2728 +++++++++ .../dm/hwcrypto/hw-crypto-rockchip-v2.h | 326 ++ bsp/rockchip/dm/i2c/i2c-rk3x.c | 256 +- .../dt-bindings/display/rockchip_vop.h | 19 + bsp/rockchip/dm/include/jpegd.h | 40 + bsp/rockchip/dm/include/rga2.h | 94 + bsp/rockchip/dm/include/rockchip-hdmi.h | 41 + bsp/rockchip/dm/pci/Kconfig | 23 + bsp/rockchip/dm/pci/SConscript | 9 + bsp/rockchip/dm/pci/pcie-rockchip-ep.c | 676 +++ bsp/rockchip/dm/pci/pcie-rockchip-host.c | 1259 ++++ bsp/rockchip/dm/pci/pcie-rockchip.c | 528 ++ bsp/rockchip/dm/pci/pcie-rockchip.h | 364 ++ bsp/rockchip/dm/phye/Kconfig | 17 + bsp/rockchip/dm/phye/SConscript | 9 + .../dm/phye/phye-rockchip-inno-dsidphy.c | 566 ++ .../dm/phye/phye-rockchip-inno-usb2.c | 677 +++ .../dm/phye/phye-rockchip-mipi-dcphy.c | 495 ++ bsp/rockchip/dm/pin/pin-rockchip.c | 44 +- bsp/rockchip/dm/sdio/Kconfig | 8 +- bsp/rockchip/dm/sdio/SConscript | 3 + bsp/rockchip/dm/sdio/sdhci-dwcmshc_rockchip.c | 629 ++ bsp/rockchip/dm/soc/Kconfig | 9 + bsp/rockchip/dm/soc/SConscript | 9 + bsp/rockchip/dm/soc/io-domain.c | 15 +- bsp/rockchip/dm/soc/jpegd.c | 412 ++ bsp/rockchip/dm/soc/rga2/SConscript | 10 + bsp/rockchip/dm/soc/rga2/rga2_drv.c | 498 ++ bsp/rockchip/dm/soc/rga2/rga2_hw.c | 170 + bsp/rockchip/dm/soc/rga2/rga2_internal.h | 22 + bsp/rockchip/dm/soc/rga2/rga2_reg.h | 67 + bsp/rockchip/dm/ufs/Kconfig | 4 + bsp/rockchip/dm/ufs/SConscript | 13 + bsp/rockchip/dm/ufs/ufs-rockchip.c | 451 ++ bsp/rockchip/rk3300/.config | 231 +- bsp/rockchip/rk3300/rtconfig.h | 132 +- .../.ci/attachconfig/ci.attachconfig.yml | 37 + bsp/rockchip/rk3500/.config | 150 +- bsp/rockchip/rk3500/applications/audio.c | 143 + bsp/rockchip/rk3500/applications/jpegd.c | 704 +++ bsp/rockchip/rk3500/applications/main.c | 4 +- bsp/rockchip/rk3500/applications/rga2.c | 502 ++ bsp/rockchip/rk3500/driver/board.c | 15 - bsp/rockchip/rk3500/rtconfig.h | 86 +- 84 files changed, 33630 insertions(+), 161 deletions(-) create mode 100755 bsp/rockchip/dm/audio/Kconfig create mode 100755 bsp/rockchip/dm/audio/SConscript create mode 100644 bsp/rockchip/dm/audio/codec/rk817-codec.c create mode 100644 bsp/rockchip/dm/audio/codec/rk817-codec.h create mode 100644 bsp/rockchip/dm/audio/rockchip-audio-card.c create mode 100644 bsp/rockchip/dm/audio/rockchip-i2s-tdm.c create mode 100644 bsp/rockchip/dm/audio/rockchip-i2s-tdm.h create mode 100644 bsp/rockchip/dm/ethernet/Kconfig create mode 100644 bsp/rockchip/dm/ethernet/SConscript create mode 100644 bsp/rockchip/dm/ethernet/dwmac-rockchip.c create mode 100755 bsp/rockchip/dm/graphic/SConscript create mode 100755 bsp/rockchip/dm/graphic/framebuffer/Kconfig create mode 100755 bsp/rockchip/dm/graphic/framebuffer/SConscript create mode 100644 bsp/rockchip/dm/graphic/framebuffer/display-rockchip.c create mode 100644 bsp/rockchip/dm/graphic/framebuffer/display-route.c create mode 100644 bsp/rockchip/dm/graphic/framebuffer/display-timing.c create mode 100644 bsp/rockchip/dm/graphic/framebuffer/dsi-rockchip.c create mode 100644 bsp/rockchip/dm/graphic/framebuffer/dsi2-rockchip.c create mode 100644 bsp/rockchip/dm/graphic/framebuffer/dw-hdmi-regs.h create mode 100644 bsp/rockchip/dm/graphic/framebuffer/fb-vop1.c create mode 100644 bsp/rockchip/dm/graphic/framebuffer/fb-vop1.h create mode 100644 bsp/rockchip/dm/graphic/framebuffer/fb-vop2-vp.c create mode 100644 bsp/rockchip/dm/graphic/framebuffer/fb-vop2-vp.h create mode 100755 bsp/rockchip/dm/graphic/framebuffer/fb-vop2.c create mode 100644 bsp/rockchip/dm/graphic/framebuffer/fb-vop2.h create mode 100644 bsp/rockchip/dm/graphic/framebuffer/fb-vopl.c create mode 100644 bsp/rockchip/dm/graphic/framebuffer/fb-vopl.h create mode 100644 bsp/rockchip/dm/graphic/framebuffer/hdmi-rockchip.c create mode 100644 bsp/rockchip/dm/graphic/framebuffer/panel-simple.c create mode 100644 bsp/rockchip/dm/graphic/framebuffer/rockchip-display.h create mode 100755 bsp/rockchip/dm/graphic/logo/Kconfig create mode 100755 bsp/rockchip/dm/graphic/logo/Kconfig.path create mode 100755 bsp/rockchip/dm/graphic/logo/logo-radxa-clut224.ppm create mode 100755 bsp/rockchip/dm/graphic/logo/logo-rockchip-clut224.ppm create mode 100644 bsp/rockchip/dm/hwcrypto/hw-crypto-rockchip-v2.c create mode 100644 bsp/rockchip/dm/hwcrypto/hw-crypto-rockchip-v2.h create mode 100644 bsp/rockchip/dm/include/dt-bindings/display/rockchip_vop.h create mode 100644 bsp/rockchip/dm/include/jpegd.h create mode 100644 bsp/rockchip/dm/include/rga2.h create mode 100644 bsp/rockchip/dm/include/rockchip-hdmi.h create mode 100755 bsp/rockchip/dm/pci/pcie-rockchip-ep.c create mode 100755 bsp/rockchip/dm/pci/pcie-rockchip-host.c create mode 100755 bsp/rockchip/dm/pci/pcie-rockchip.c create mode 100755 bsp/rockchip/dm/pci/pcie-rockchip.h create mode 100644 bsp/rockchip/dm/phye/phye-rockchip-inno-dsidphy.c create mode 100644 bsp/rockchip/dm/phye/phye-rockchip-inno-usb2.c create mode 100644 bsp/rockchip/dm/phye/phye-rockchip-mipi-dcphy.c create mode 100644 bsp/rockchip/dm/sdio/sdhci-dwcmshc_rockchip.c create mode 100644 bsp/rockchip/dm/soc/jpegd.c create mode 100644 bsp/rockchip/dm/soc/rga2/SConscript create mode 100644 bsp/rockchip/dm/soc/rga2/rga2_drv.c create mode 100644 bsp/rockchip/dm/soc/rga2/rga2_hw.c create mode 100644 bsp/rockchip/dm/soc/rga2/rga2_internal.h create mode 100644 bsp/rockchip/dm/soc/rga2/rga2_reg.h create mode 100755 bsp/rockchip/dm/ufs/Kconfig create mode 100755 bsp/rockchip/dm/ufs/SConscript create mode 100755 bsp/rockchip/dm/ufs/ufs-rockchip.c create mode 100644 bsp/rockchip/rk3500/applications/audio.c create mode 100644 bsp/rockchip/rk3500/applications/jpegd.c create mode 100644 bsp/rockchip/rk3500/applications/rga2.c diff --git a/bsp/README.md b/bsp/README.md index 9fd1e080c2f9..b7bd5ddcc75f 100644 --- a/bsp/README.md +++ b/bsp/README.md @@ -348,11 +348,11 @@ This document is based on the RT-Thread mainline repository and categorizes the #### 🟡 Rockchip -| BSP Name | GPIO | UART | ADC | I2C | SPI | WDT | HWTimer | PWM | RTC | SDIO | CAN | PCI | -|----------|------|------|-----|-----|-----|-----|---------|-----|-----|------|-----|------| -| [rk2108](rockchip/rk2108) | - | ✅ | - | - | - | - | - | - | - | - | - | - | -| [rk3300](rockchip/rk3300) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | - | -| [rk3500](rockchip/rk3500) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | +| BSP Name | GPIO | UART | ADC | I2C | SPI | WDT | HWTimer | PWM | RTC | SDIO | CAN | PCI | DMA | Ethernet | Audio | Display | Crypto | +|----------|------|------|-----|-----|-----|-----|---------|-----|-----|------|-----|-----|-----|----------|-------|---------|--------| +| [rk2108](rockchip/rk2108) | - | ✅ | - | - | - | - | - | - | - | - | - | - | - | - | - | - | - | +| [rk3300](rockchip/rk3300) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | +| [rk3500](rockchip/rk3500) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | #### 🟡 APM32 diff --git a/bsp/rockchip/dm/Kconfig b/bsp/rockchip/dm/Kconfig index 36d8d27cbbcf..434c1c556d5a 100755 --- a/bsp/rockchip/dm/Kconfig +++ b/bsp/rockchip/dm/Kconfig @@ -1,9 +1,12 @@ SOC_DM_ADC_DIR = $(SOC_DM_DIR)/adc +SOC_DM_AUDIO_DIR = $(SOC_DM_DIR)/audio SOC_DM_CAN_DIR = $(SOC_DM_DIR)/can SOC_DM_CLK_DIR = $(SOC_DM_DIR)/clk SOC_DM_DVFS_EVENT_DIR = $(SOC_DM_DIR)/dvfs/event SOC_DM_DVFS_CPUFREQ_DIR = $(SOC_DM_DIR)/dvfs/cpufreq SOC_DM_DVFS_DEVFREQ_DIR = $(SOC_DM_DIR)/dvfs/devfreq +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_HWSPINLOCK_DIR = $(SOC_DM_DIR)/hwspinlock SOC_DM_CLOCK_TIME_DIR = $(SOC_DM_DIR)/hwtimer @@ -21,7 +24,9 @@ SOC_DM_PWM_DIR = $(SOC_DM_DIR)/pwm SOC_DM_REGULATOR_DIR = $(SOC_DM_DIR)/regulator SOC_DM_RTC_DIR = $(SOC_DM_DIR)/rtc SOC_DM_SDIO_DIR = $(SOC_DM_DIR)/sdio +SOC_DM_ETHERNET_DIR = $(SOC_DM_DIR)/ethernet 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_UFS_DIR = $(SOC_DM_DIR)/ufs SOC_DM_WDT_DIR = $(SOC_DM_DIR)/watchdog diff --git a/bsp/rockchip/dm/audio/Kconfig b/bsp/rockchip/dm/audio/Kconfig new file mode 100755 index 000000000000..61eec170edc8 --- /dev/null +++ b/bsp/rockchip/dm/audio/Kconfig @@ -0,0 +1,48 @@ +menuconfig RT_AUDIO_ROCKCHIP + bool "Enable Rockchip Audio" + depends on RT_USING_OFW + depends on RT_USING_AUDIO + default n + help + Rockchip I2S/TDM audio for boards such as ROCK 3A (rk3568): + - Analog output via RK809/RK817 PMIC codec (I2S1) + - HDMI audio via I2S0 (requires dw-hdmi display stack) + +if RT_AUDIO_ROCKCHIP + +config RT_AUDIO_ROCKCHIP_I2S_TDM + bool "Rockchip I2S/TDM controller (CPU DAI)" + default y + help + I2S/TDM block driver (e.g. i2s0_8ch, i2s1_8ch). + Uses PL330 DMA when RT_USING_DMA is enabled, otherwise PIO. + +menuconfig RT_AUDIO_ROCKCHIP_CODEC + bool "Rockchip codec support" + depends on RT_AUDIO_ROCKCHIP_I2S_TDM + default y + help + Codec drivers for analog audio (headphone / line-out). + Not used for the HDMI audio card. + +if RT_AUDIO_ROCKCHIP_CODEC + +config RT_AUDIO_ROCKCHIP_CODEC_RK817 + bool "RK817/RK809 codec (I2C PMIC)" + depends on RT_USING_I2C + select RT_MFD_RK8XX_I2C + default y + help + RK809/RK817 built-in codec on ROCK 3A, routed over I2S1. + +endif + +config RT_AUDIO_ROCKCHIP_CARD + bool "Rockchip simple-audio-card (machine driver)" + depends on RT_AUDIO_ROCKCHIP_I2S_TDM + default y + help + Parses simple-audio-card nodes (e.g. rk809-sound, hdmi_sound) + and registers rt_audio_device instances. + +endif diff --git a/bsp/rockchip/dm/audio/SConscript b/bsp/rockchip/dm/audio/SConscript new file mode 100755 index 000000000000..9d0f9686892c --- /dev/null +++ b/bsp/rockchip/dm/audio/SConscript @@ -0,0 +1,18 @@ +from building import * + +cwd = GetCurrentDir() +src = [] +CPPPATH = [cwd + '/../include'] + +if GetDepend(['RT_AUDIO_ROCKCHIP_I2S_TDM']): + src += ['rockchip-i2s-tdm.c'] + +if GetDepend(['RT_AUDIO_ROCKCHIP_CODEC_RK817']): + src += ['codec/rk817-codec.c'] + +if GetDepend(['RT_AUDIO_ROCKCHIP_CARD', 'RT_AUDIO_ROCKCHIP_I2S_TDM']): + src += ['rockchip-audio-card.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/rockchip/dm/audio/codec/rk817-codec.c b/bsp/rockchip/dm/audio/codec/rk817-codec.c new file mode 100644 index 000000000000..15bf1892260e --- /dev/null +++ b/bsp/rockchip/dm/audio/codec/rk817-codec.c @@ -0,0 +1,426 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-11-26 GuEe-GUI first version + */ + +#include +#include +#include + +#define DBG_TAG "codec.rk817" +#define DBG_LVL DBG_INFO +#include + +#include "rk8xx.h" +#include "rk817-codec.h" + +struct rk817_reg_val +{ + rt_uint8_t reg; + rt_uint8_t value; +}; + +struct rk817_codec +{ + struct rk8xx *rk8xx; + struct rt_clk *mclk; + struct rt_ofw_node *np; + + rt_uint8_t hp_volume; + rt_uint8_t spk_volume; + rt_uint32_t rate; + rt_bool_t powered; + + rt_list_t list; +}; + +static rt_list_t codec_list = RT_LIST_OBJECT_INIT(codec_list); +static RT_DEFINE_SPINLOCK(codec_list_lock); + +static const struct rk817_reg_val playback_power_up_list[] = +{ + { RK817_CODEC_AREF_RTCFG1, 0x40 }, + { RK817_CODEC_DDAC_POPD_DACST, 0x02 }, + { RK817_CODEC_APLL_CFG1, 0x58 }, + { RK817_CODEC_APLL_CFG2, 0x2d }, + { RK817_CODEC_APLL_CFG5, 0x00 }, + { RK817_CODEC_DI2S_RXCMD_TSD, 0x00 }, + { RK817_CODEC_DI2S_RSD, 0x00 }, + { RK817_CODEC_DI2S_RXCR1, 0x00 }, + { RK817_CODEC_DI2S_RXCMD_TSD, 0x20 }, + { RK817_CODEC_DTOP_VUCTIME, 0xf4 }, + { RK817_CODEC_DDAC_MUTE_MIXCTL, 0x00 }, + { RK817_CODEC_DDAC_VOLL, RK817_DEFAULT_SPK_VOL }, + { RK817_CODEC_DDAC_VOLR, RK817_DEFAULT_SPK_VOL }, +}; + +static const struct rk817_reg_val playback_power_down_list[] = +{ + { RK817_CODEC_DDAC_MUTE_MIXCTL, 0x01 }, + { RK817_CODEC_ADAC_CFG1, 0x0f }, + { RK817_CODEC_AHP_CFG0, 0xe0 }, + { RK817_CODEC_AHP_CP, 0x09 }, + { RK817_CODEC_ACLASSD_CFG1, 0x69 }, +}; + +rt_inline rt_err_t rk817_write(struct rk817_codec *codec, rt_uint16_t reg, rt_uint8_t val) +{ + return rk8xx_write(codec->rk8xx, reg, val); +} + +rt_inline rt_err_t rk817_update_bits(struct rk817_codec *codec, + rt_uint16_t reg, rt_uint8_t mask, rt_uint8_t val) +{ + return rk8xx_update_bits(codec->rk8xx, reg, mask, val); +} + +static void rk817_restart_dac_digital_clk(struct rk817_codec *codec) +{ + rk817_update_bits(codec, RK817_CODEC_ADAC_CFG1, PWD_DACBIAS_MASK, PWD_DACBIAS_DOWN); + rt_hw_us_delay(500); + rk817_update_bits(codec, RK817_CODEC_DTOP_DIGEN_CLKE, DAC_DIG_CLK_MASK, DAC_DIG_CLK_DIS); + rt_hw_us_delay(500); + rk817_update_bits(codec, RK817_CODEC_DTOP_DIGEN_CLKE, DAC_DIG_CLK_MASK, DAC_DIG_CLK_EN); + rt_hw_us_delay(500); + rk817_update_bits(codec, RK817_CODEC_ADAC_CFG1, PWD_DACBIAS_MASK, PWD_DACBIAS_ON); +} + +static rt_err_t rk817_codec_power_up(struct rk817_codec *codec) +{ + rt_size_t i; + + rk817_update_bits(codec, RK817_CODEC_DTOP_DIGEN_CLKE, DAC_DIG_CLK_MASK, DAC_DIG_CLK_EN); + + for (i = 0; i < RT_ARRAY_SIZE(playback_power_up_list); ++i) + { + rk817_write(codec, playback_power_up_list[i].reg, playback_power_up_list[i].value); + } + + rk817_write(codec, RK817_CODEC_APLL_CFG0, 0x04); + rk817_write(codec, RK817_CODEC_APLL_CFG4, 0xa5); + rk817_restart_dac_digital_clk(codec); + + return RT_EOK; +} + +static rt_err_t rk817_codec_power_down(struct rk817_codec *codec) +{ + rt_size_t i; + + rk817_update_bits(codec, RK817_CODEC_DDAC_MUTE_MIXCTL, DACMT_ENABLE, DACMT_ENABLE); + + for (i = 0; i < RT_ARRAY_SIZE(playback_power_down_list); ++i) + { + rk817_write(codec, playback_power_down_list[i].reg, playback_power_down_list[i].value); + } + + rk817_update_bits(codec, RK817_CODEC_DTOP_DIGEN_CLKE, DAC_DIG_CLK_MASK, DAC_DIG_CLK_DIS); + rk817_write(codec, RK817_CODEC_APLL_CFG5, 0x01); + rk817_write(codec, RK817_CODEC_AREF_RTCFG1, 0x06); + codec->rate = 0; + + return RT_EOK; +} + +static rt_err_t rk817_set_hp_path(struct rk817_codec *codec) +{ + rk817_write(codec, RK817_CODEC_AHP_CP, 0x11); + rk817_write(codec, RK817_CODEC_AHP_CFG0, 0x80); + rk817_write(codec, RK817_CODEC_ADAC_CFG1, + PWD_DACBIAS_ON | PWD_DACD_DOWN | PWD_DACL_ON | PWD_DACR_ON); + rk817_update_bits(codec, RK817_CODEC_DDAC_MUTE_MIXCTL, DACMT_ENABLE, DACMT_DISABLE); + rk817_write(codec, RK817_CODEC_DDAC_VOLL, codec->hp_volume); + rk817_write(codec, RK817_CODEC_DDAC_VOLR, codec->hp_volume); + + return RT_EOK; +} + +struct rk817_codec_rk8xx_find_data +{ + struct rt_ofw_node *np; + struct rk8xx *rk8xx; +}; + +static rt_err_t rk817_codec_rk8xx_iter(struct rt_object *object, void *data) +{ + struct rk817_codec_rk8xx_find_data *find = data; + struct rt_device *dev; + + if (rt_object_get_type(object) != RT_Object_Class_Device) + { + return RT_EOK; + } + + dev = (struct rt_device *)object; + + if (dev->ofw_node == find->np && dev->user_data) + { + find->rk8xx = dev->user_data; + return -RT_EINTR; + } + + return RT_EOK; +} + +struct rk8xx *rk817_codec_rk8xx_from_np(struct rt_ofw_node *np) +{ + struct rk817_codec_rk8xx_find_data find = + { + .np = np, + .rk8xx = RT_NULL, + }; + + rt_object_for_each(RT_Object_Class_Device, rk817_codec_rk8xx_iter, &find); + + return find.rk8xx; +} + +rt_err_t rk817_codec_bind_rk8xx(struct rk817_codec **out_codec, struct rk8xx *rk8xx) +{ + struct rk817_codec *codec; + + if (!out_codec || !rk8xx) + { + return -RT_EINVAL; + } + + codec = rt_calloc(1, sizeof(*codec)); + + if (!codec) + { + return -RT_ENOMEM; + } + + codec->rk8xx = rk8xx; + codec->hp_volume = RK817_DEFAULT_HP_VOL; + codec->spk_volume = RK817_DEFAULT_SPK_VOL; + codec->np = rk8xx->dev ? rk8xx->dev->ofw_node : RT_NULL; + + rt_spin_lock(&codec_list_lock); + rt_list_insert_before(&codec_list, &codec->list); + rt_spin_unlock(&codec_list_lock); + + *out_codec = codec; + + return RT_EOK; +} + +struct rk817_codec *rk817_codec_find(struct rt_ofw_node *np) +{ + struct rk817_codec *codec; + + rt_spin_lock(&codec_list_lock); + rt_list_for_each_entry(codec, &codec_list, list) + { + if (codec->np == np) + { + rt_spin_unlock(&codec_list_lock); + return codec; + } + } + rt_spin_unlock(&codec_list_lock); + + return RT_NULL; +} + +rt_err_t rk817_codec_hw_params(struct rk817_codec *codec, const struct rk817_codec_config *cfg) +{ + rt_uint8_t apll_cfg3; + rt_uint8_t dtop_digen_sr_lmt0; + + if (!codec || !cfg) + { + return -RT_EINVAL; + } + + if (codec->mclk) + { + rt_clk_set_rate(codec->mclk, cfg->mclk_rate); + rt_clk_prepare_enable(codec->mclk); + } + + rk817_update_bits(codec, RK817_CODEC_DI2S_CKM, RK817_I2S_MODE_MASK, RK817_I2S_MODE_SLV); + + switch (cfg->samplerate) + { + case 8000: + apll_cfg3 = 0x03; + dtop_digen_sr_lmt0 = 0x00; + break; + case 16000: + apll_cfg3 = 0x06; + dtop_digen_sr_lmt0 = 0x01; + break; + case 32000: + case 44100: + case 48000: + apll_cfg3 = 0x0c; + dtop_digen_sr_lmt0 = 0x02; + break; + case 96000: + apll_cfg3 = 0x18; + dtop_digen_sr_lmt0 = 0x03; + break; + default: + return -RT_EINVAL; + } + + if (codec->rate != cfg->samplerate) + { + rk817_write(codec, RK817_CODEC_APLL_CFG3, apll_cfg3); + rk817_update_bits(codec, RK817_CODEC_DDAC_SR_LMT0, DACSRT_MASK, dtop_digen_sr_lmt0); + rk817_restart_dac_digital_clk(codec); + codec->rate = cfg->samplerate; + } + + if (cfg->samplebits == 16) + { + rk817_write(codec, RK817_CODEC_DI2S_RXCR2, VDW_RX_16BITS); + rk817_write(codec, RK817_CODEC_DI2S_TXCR2, VDW_TX_16BITS); + } + + return RT_EOK; +} + +rt_err_t rk817_codec_start(struct rk817_codec *codec) +{ + if (!codec) + { + return -RT_EINVAL; + } + + if (!codec->powered) + { + rk817_codec_power_up(codec); + codec->powered = RT_TRUE; + } + + rk817_set_hp_path(codec); + rk817_update_bits(codec, RK817_CODEC_DTOP_DIGEN_CLKE, I2STX_EN_MASK, I2STX_EN); + + return RT_EOK; +} + +rt_err_t rk817_codec_stop(struct rk817_codec *codec) +{ + if (!codec) + { + return -RT_EINVAL; + } + + rk817_update_bits(codec, RK817_CODEC_DTOP_DIGEN_CLKE, I2STX_EN_MASK, I2STX_DIS); + + if (codec->powered) + { + rk817_codec_power_down(codec); + codec->powered = RT_FALSE; + } + + if (codec->mclk) + { + rt_clk_disable_unprepare(codec->mclk); + } + + return RT_EOK; +} + +rt_err_t rk817_codec_set_volume(struct rk817_codec *codec, rt_uint8_t volume) +{ + rt_uint8_t reg_val; + + if (!codec) + { + return -RT_EINVAL; + } + + if (volume > AUDIO_VOLUME_MAX) + { + volume = AUDIO_VOLUME_MAX; + } + + reg_val = RK817_DAC_VOL_MAX - + ((volume * (RK817_DAC_VOL_MAX - RK817_DAC_VOL_MIN)) / AUDIO_VOLUME_MAX); + + if (reg_val < RK817_DAC_VOL_MIN) + { + reg_val = RK817_DAC_VOL_MIN; + } + + codec->hp_volume = reg_val; + rk817_write(codec, RK817_CODEC_DDAC_VOLL, reg_val); + rk817_write(codec, RK817_CODEC_DDAC_VOLR, reg_val); + + return RT_EOK; +} + +static rt_err_t rk817_codec_probe(struct rt_platform_device *pdev) +{ + struct rk8xx *rk8xx = pdev->priv; + struct rk817_codec *codec; + rt_uint32_t hp_vol = RK817_DEFAULT_HP_VOL; + + if (!rk8xx) + { + return -RT_EINVAL; + } + + if (rk817_codec_bind_rk8xx(&codec, rk8xx)) + { + return -RT_ENOMEM; + } + + codec->mclk = rt_clk_get_by_name(&pdev->parent, "mclk"); + + if (!rt_is_err(codec->mclk)) + { + rt_ofw_prop_read_u32(pdev->parent.ofw_node, "hp-volume", &hp_vol); + codec->hp_volume = (rt_uint8_t)hp_vol; + } + + pdev->parent.user_data = codec; + + return RT_EOK; +} + +static rt_err_t rk817_codec_remove(struct rt_platform_device *pdev) +{ + struct rk817_codec *codec = pdev->parent.user_data; + + if (codec) + { + rt_spin_lock(&codec_list_lock); + rt_list_remove(&codec->list); + rt_spin_unlock(&codec_list_lock); + rt_free(codec); + } + + return RT_EOK; +} + +static const struct rt_ofw_node_id rk817_codec_ofw_ids[] = +{ + { .compatible = "rockchip,rk817-codec" }, + { .compatible = "rockchip,rk809-codec" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver rk817_codec_driver = +{ + .name = "rk817-codec", + .ids = rk817_codec_ofw_ids, + .probe = rk817_codec_probe, + .remove = rk817_codec_remove, +}; + +static int rk817_codec_register(void) +{ + rt_platform_driver_register(&rk817_codec_driver); + + return 0; +} +INIT_DEVICE_EXPORT(rk817_codec_register); diff --git a/bsp/rockchip/dm/audio/codec/rk817-codec.h b/bsp/rockchip/dm/audio/codec/rk817-codec.h new file mode 100644 index 000000000000..33be4d1c913e --- /dev/null +++ b/bsp/rockchip/dm/audio/codec/rk817-codec.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-11-26 GuEe-GUI first version + */ + +#ifndef __RK817_CODEC_H__ +#define __RK817_CODEC_H__ + +#include "rk8xx.h" + +#define RK817_CODEC_PLAYBACK 1 +#define RK817_CODEC_CAPTURE 2 +#define RK817_CODEC_ALL 3 + +#define RK817_DAC_VOL_MIN 3 +#define RK817_DAC_VOL_MAX 255 +#define RK817_DEFAULT_HP_VOL 0x03 +#define RK817_DEFAULT_SPK_VOL 0x0a + +#define ADC_DIG_CLK_MASK (0xf << 4) +#define ADC_DIG_CLK_EN (0xe << 4) +#define ADC_DIG_CLK_DIS (0x0 << 4) +#define DAC_DIG_CLK_MASK (0xf << 0) +#define DAC_DIG_CLK_EN (0xe << 0) +#define DAC_DIG_CLK_DIS (0x0 << 0) + +#define I2STX_EN_MASK RT_BIT(4) +#define I2STX_EN RT_BIT(4) +#define I2STX_DIS 0 + +#define RK817_I2S_MODE_MASK RT_BIT(0) +#define RK817_I2S_MODE_SLV 0 +#define RK817_I2S_MODE_MST RT_BIT(0) + +#define DACSRT_MASK 0x7 +#define DACMT_ENABLE RT_BIT(0) +#define DACMT_DISABLE 0 + +#define VDW_RX_16BITS 0x0f +#define VDW_TX_16BITS 0x0f + +#define PWD_DACBIAS_MASK RT_BIT(3) +#define PWD_DACBIAS_DOWN RT_BIT(3) +#define PWD_DACBIAS_ON 0 +#define PWD_DACD_MASK RT_BIT(2) +#define PWD_DACD_DOWN RT_BIT(2) +#define PWD_DACD_ON 0 +#define PWD_DACL_MASK RT_BIT(1) +#define PWD_DACL_DOWN RT_BIT(1) +#define PWD_DACL_ON 0 +#define PWD_DACR_MASK RT_BIT(0) +#define PWD_DACR_DOWN RT_BIT(0) +#define PWD_DACR_ON 0 + +#define PLL_PW_DOWN RT_BIT(0) +#define PLL_PW_UP 0 + +#define HP_PATH 3 +#define OFF 0 + +struct rk817_codec_config +{ + rt_uint32_t samplerate; + rt_uint16_t samplebits; + rt_uint32_t mclk_rate; +}; + +struct rk817_codec; + +rt_err_t rk817_codec_bind_rk8xx(struct rk817_codec **out_codec, struct rk8xx *rk8xx); +rt_err_t rk817_codec_hw_params(struct rk817_codec *codec, const struct rk817_codec_config *cfg); +rt_err_t rk817_codec_start(struct rk817_codec *codec); +rt_err_t rk817_codec_stop(struct rk817_codec *codec); +rt_err_t rk817_codec_set_volume(struct rk817_codec *codec, rt_uint8_t volume); +struct rk817_codec *rk817_codec_find(struct rt_ofw_node *np); +struct rk8xx *rk817_codec_rk8xx_from_np(struct rt_ofw_node *np); + +#endif /* __RK817_CODEC_H__ */ diff --git a/bsp/rockchip/dm/audio/rockchip-audio-card.c b/bsp/rockchip/dm/audio/rockchip-audio-card.c new file mode 100644 index 000000000000..6b9ec4ba87fe --- /dev/null +++ b/bsp/rockchip/dm/audio/rockchip-audio-card.c @@ -0,0 +1,641 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-11-26 GuEe-GUI first version + */ + +#include +#include +#include + +#define DBG_TAG "audio.card" +#define DBG_LVL DBG_INFO +#include + +#include "rockchip-i2s-tdm.h" +#include "rockchip-hdmi.h" +#include "codec/rk817-codec.h" + +#define CARD_PREFIX "simple-audio-card," +#define CARD_DAI "sound-dai" +#define DEFAULT_MCLK_FS 256 + +#ifndef RT_AUDIO_REPLAY_MP_BLOCK_SIZE +#define RT_AUDIO_REPLAY_MP_BLOCK_SIZE 4096 +#endif + +#ifndef RT_AUDIO_REPLAY_MP_BLOCK_COUNT +#define RT_AUDIO_REPLAY_MP_BLOCK_COUNT 2 +#endif + +#define ROCKCHIP_AUDIO_PLAYBACK_SIZE \ + (RT_AUDIO_REPLAY_MP_BLOCK_SIZE * RT_AUDIO_REPLAY_MP_BLOCK_COUNT) + +#define ROCKCHIP_I2S_DMA_BURST 8 + +struct rockchip_audio_card +{ + struct rt_audio_device audio; + struct rt_audio_configure config; + + struct rt_device *dev; + struct rockchip_i2s_tdm *i2s; + struct rk817_codec *codec; + struct rt_ofw_node *hdmi_np; + + rt_uint32_t mclk_fs; + rt_bool_t started; + rt_bool_t is_hdmi; + rt_bool_t use_dma; + char name[32]; + + struct rt_dma_chan *dma_tx; + void *playback_buf; + rt_ubase_t playback_dma; + rt_ubase_t txdr_dma; +}; + +static struct rt_ofw_node *rockchip_audio_parse_dai_np(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 rockchip_audio_card_getcaps(struct rt_audio_device *audio, + struct rt_audio_caps *caps) +{ + struct rockchip_audio_card *card = audio->parent.user_data; + + switch (caps->main_type) + { + case AUDIO_TYPE_QUERY: + switch (caps->sub_type) + { + case AUDIO_TYPE_QUERY: + caps->udata.mask = AUDIO_TYPE_OUTPUT; + break; + default: + caps->udata.mask = AUDIO_TYPE_OUTPUT; + break; + } + break; + + case AUDIO_TYPE_OUTPUT: + 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 = 48000; + caps->udata.mask = AUDIO_SAMP_RATE_44K | AUDIO_SAMP_RATE_48K; + break; + case AUDIO_DSP_CHANNELS: + caps->udata.config.channels = 2; + break; + case AUDIO_DSP_SAMPLEBITS: + caps->udata.config.samplebits = 16; + break; + default: + break; + } + 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 = AUDIO_VOLUME_MAX; + break; + default: + break; + } + break; + + default: + break; + } + + return RT_EOK; +} + +static rt_err_t rockchip_audio_card_configure(struct rt_audio_device *audio, + struct rt_audio_caps *caps) +{ + rt_err_t err; + struct rockchip_audio_card *card = audio->parent.user_data; + struct rockchip_i2s_config i2s_cfg; + struct rk817_codec_config codec_cfg; + + switch (caps->main_type) + { + case AUDIO_TYPE_MIXER: + switch (caps->sub_type) + { + case AUDIO_MIXER_MUTE: + break; + case AUDIO_MIXER_VOLUME: + if (!card->is_hdmi && card->codec) + { + rk817_codec_set_volume(card->codec, caps->udata.value); + } + break; + default: + break; + } + break; + + case AUDIO_TYPE_OUTPUT: + switch (caps->sub_type) + { + case AUDIO_DSP_PARAM: + card->config = caps->udata.config; + + if (!card->config.samplerate) + { + card->config.samplerate = 48000; + } + + if (!card->config.channels) + { + card->config.channels = 2; + } + + if (!card->config.samplebits) + { + card->config.samplebits = 16; + } + + i2s_cfg.samplerate = card->config.samplerate; + i2s_cfg.channels = card->config.channels; + i2s_cfg.samplebits = card->config.samplebits; + i2s_cfg.mclk_fs = card->mclk_fs; + + codec_cfg.samplerate = card->config.samplerate; + codec_cfg.samplebits = card->config.samplebits; + codec_cfg.mclk_rate = card->config.samplerate * card->mclk_fs; + + if (!card->is_hdmi && card->codec) + { + if ((err = rk817_codec_hw_params(card->codec, &codec_cfg))) + { + return err; + } + } + + if (card->i2s) + { + return rockchip_i2s_tdm_hw_params(card->i2s, &i2s_cfg); + } + break; + default: + break; + } + break; + + default: + break; + } + + return RT_EOK; +} + +static rt_err_t rockchip_audio_card_init(struct rt_audio_device *audio) +{ + return RT_EOK; +} + +static rt_err_t rockchip_audio_card_start(struct rt_audio_device *audio, int stream) +{ + rt_err_t err; + struct rockchip_audio_card *card = audio->parent.user_data; + + if (stream != AUDIO_STREAM_REPLAY) + { + return -RT_EINVAL; + } + + if (card->is_hdmi) + { + err = rk_hdmi_audio_configure(card->hdmi_np, + card->config.samplerate, card->config.channels, + card->config.samplebits); + if (err) + { + LOG_E("HDMI audio configure failed: %s", rt_strerror(err)); + return err; + } + + if ((err = rk_hdmi_audio_enable(card->hdmi_np, RT_TRUE))) + { + LOG_E("HDMI audio enable failed: %s", rt_strerror(err)); + return err; + } + } + else if (card->codec) + { + rk817_codec_start(card->codec); + } + + if (card->i2s) + { + if ((err = rockchip_i2s_tdm_start(card->i2s))) + { + if (card->is_hdmi) + { + rk_hdmi_audio_enable(card->hdmi_np, RT_FALSE); + } + return err; + } + + /* TX reset in start() clears DMACR, so enable requests afterwards. */ + if (card->use_dma && (err = rockchip_i2s_tdm_dma_enable(card->i2s))) + { + rockchip_i2s_tdm_stop(card->i2s); + if (card->is_hdmi) + { + rk_hdmi_audio_enable(card->hdmi_np, RT_FALSE); + } + return err; + } + } + + card->started = RT_TRUE; + + /* Prime the first replay block; later blocks are queued by DMA callbacks. */ + rt_audio_tx_complete(audio); + + return RT_EOK; +} + +static rt_err_t rockchip_audio_card_stop(struct rt_audio_device *audio, int stream) +{ + struct rockchip_audio_card *card = audio->parent.user_data; + + if (stream != AUDIO_STREAM_REPLAY) + { + return -RT_EINVAL; + } + + if (card->use_dma && card->dma_tx) + { + rt_dma_chan_stop(card->dma_tx); + } + + if (card->i2s) + { + if (card->use_dma) + { + rockchip_i2s_tdm_dma_disable(card->i2s); + } + + rockchip_i2s_tdm_stop(card->i2s); + } + + if (!card->is_hdmi && card->codec) + { + rk817_codec_stop(card->codec); + } + else if (card->is_hdmi) + { + rk_hdmi_audio_enable(card->hdmi_np, RT_FALSE); + } + + card->started = RT_FALSE; + + return RT_EOK; +} + +static void rockchip_audio_card_dma_tx_done(struct rt_dma_chan *chan, rt_size_t size) +{ + struct rockchip_audio_card *card = chan->priv; + + RT_UNUSED(size); + + rt_audio_tx_complete(&card->audio); +} + +static rt_ssize_t rockchip_audio_card_dma_transmit(struct rockchip_audio_card *card, + const void *write_buf, rt_size_t size) +{ + rt_err_t err; + struct rt_dma_slave_config config; + struct rt_dma_slave_transfer transfer; + + rt_memset(&config, 0, sizeof(config)); + config.direction = RT_DMA_MEM_TO_DEV; + config.src_addr_width = RT_DMA_SLAVE_BUSWIDTH_4_BYTES; + config.dst_addr_width = RT_DMA_SLAVE_BUSWIDTH_4_BYTES; + config.src_maxburst = ROCKCHIP_I2S_DMA_BURST; + config.dst_maxburst = ROCKCHIP_I2S_DMA_BURST; + config.dst_addr = card->txdr_dma; + config.src_addr = (write_buf - card->playback_buf) + card->playback_dma; + + if ((err = rt_dma_chan_config(card->dma_tx, &config))) + { + LOG_E("DMA config failed: %s", rt_strerror(err)); + return err; + } + + rt_memset(&transfer, 0, sizeof(transfer)); + transfer.src_addr = config.src_addr; + transfer.dst_addr = config.dst_addr; + transfer.buffer_len = size; + + if (size % (config.src_addr_width * config.src_maxburst)) + { + LOG_E("DMA size %u not burst-aligned", size); + return -RT_EINVAL; + } + + rt_dma_chan_stop(card->dma_tx); + + /* The audio core submits one block at a time. */ + if ((err = rt_dma_prep_single(card->dma_tx, &transfer))) + { + LOG_E("DMA prep failed: %s", rt_strerror(err)); + return err; + } + + if ((err = rt_dma_chan_start(card->dma_tx))) + { + LOG_E("DMA start failed: %s", rt_strerror(err)); + return err; + } + + return size; +} + +static rt_ssize_t rockchip_audio_card_transmit(struct rt_audio_device *audio, + const void *writeBuf, void *readBuf, rt_size_t size) +{ + struct rockchip_audio_card *card = audio->parent.user_data; + + RT_UNUSED(readBuf); + + if (!card->started || !card->i2s) + { + return 0; + } + + if (card->use_dma && card->dma_tx) + { + return rockchip_audio_card_dma_transmit(card, writeBuf, size); + } + + return rockchip_i2s_tdm_push(card->i2s, writeBuf, size); +} + +static void rockchip_audio_card_buffer_info(struct rt_audio_device *audio, + struct rt_audio_buf_info *info) +{ + struct rockchip_audio_card *card = audio->parent.user_data; + + if (card->use_dma && card->playback_buf) + { + info->buffer = card->playback_buf; + info->block_size = RT_AUDIO_REPLAY_MP_BLOCK_SIZE; + info->block_count = RT_AUDIO_REPLAY_MP_BLOCK_COUNT; + info->total_size = ROCKCHIP_AUDIO_PLAYBACK_SIZE; + return; + } + + info->buffer = RT_NULL; + info->block_size = RT_AUDIO_REPLAY_MP_BLOCK_SIZE; + info->block_count = RT_AUDIO_REPLAY_MP_BLOCK_COUNT; + info->total_size = info->block_size * info->block_count; +} + +static const struct rt_audio_ops rockchip_audio_card_ops = +{ + .getcaps = rockchip_audio_card_getcaps, + .configure = rockchip_audio_card_configure, + .init = rockchip_audio_card_init, + .start = rockchip_audio_card_start, + .stop = rockchip_audio_card_stop, + .transmit = rockchip_audio_card_transmit, + .buffer_info = rockchip_audio_card_buffer_info, +}; + +static struct rk817_codec *rockchip_audio_card_get_codec(struct rt_ofw_node *codec_np) +{ + struct rk817_codec *codec; + struct rk8xx *rk8xx; + + codec = rk817_codec_find(codec_np); + + if (codec) + { + return codec; + } + + rk8xx = rk817_codec_rk8xx_from_np(codec_np); + + if (!rk8xx) + { + return RT_NULL; + } + + if (rk817_codec_bind_rk8xx(&codec, rk8xx)) + { + return RT_NULL; + } + + return codec; +} + +static rt_err_t rockchip_audio_card_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + struct rt_device *dev = &pdev->parent; + struct rt_ofw_node *card_np = dev->ofw_node; + struct rt_ofw_node *cpu_np, *codec_np; + struct rockchip_audio_card *card; + const char *card_name = "rockchip-audio"; + + card = rt_calloc(1, sizeof(*card)); + + if (!card) + { + return -RT_ENOMEM; + } + + rt_ofw_prop_read_string(card_np, CARD_PREFIX "name", &card_name); + rt_strncpy(card->name, card_name, sizeof(card->name) - 1); + rt_ofw_prop_read_u32(card_np, CARD_PREFIX "mclk-fs", &card->mclk_fs); + + if (!card->mclk_fs) + { + card->mclk_fs = DEFAULT_MCLK_FS; + } + + cpu_np = rockchip_audio_parse_dai_np(card_np, CARD_PREFIX "cpu"); + codec_np = rockchip_audio_parse_dai_np(card_np, CARD_PREFIX "codec"); + + if (!cpu_np) + { + LOG_E("Missing CPU DAI in %s", card->name); + err = -RT_EINVAL; + goto _fail; + } + + card->i2s = rockchip_i2s_tdm_find(cpu_np); + + if (!card->i2s) + { + LOG_E("I2S not ready for %s", card->name); + err = -RT_ENOSYS; + goto _fail; + } + + if (codec_np) + { + if (rt_ofw_node_is_compatible(codec_np, "rockchip,rk3568-dw-hdmi") || + rt_ofw_node_is_compatible(codec_np, "rockchip,rk3588-dw-hdmi")) + { + card->is_hdmi = RT_TRUE; + card->hdmi_np = codec_np; + rt_ofw_node_get(card->hdmi_np); + } + else + { + card->codec = rockchip_audio_card_get_codec(codec_np); + + if (!card->codec) + { + LOG_W("Codec not ready for %s", card->name); + } + } + } + + card->config.samplerate = 48000; + card->config.channels = 2; + card->config.samplebits = 16; + card->dev = dev; + card->dma_tx = rockchip_i2s_tdm_get_dma_tx(card->i2s); + card->txdr_dma = rockchip_i2s_tdm_txdr_phys(card->i2s); + + if (card->dma_tx && card->txdr_dma) + { + card->playback_buf = rt_dma_alloc_coherent(dev, + ROCKCHIP_AUDIO_PLAYBACK_SIZE, &card->playback_dma); + + if (card->playback_buf) + { + card->dma_tx->callback = rockchip_audio_card_dma_tx_done; + card->dma_tx->priv = card; + card->use_dma = RT_TRUE; + LOG_D("%s: DMA playback enabled", card->name); + } + else + { + LOG_W("%s: DMA buffer alloc failed, using PIO", card->name); + } + } + else + { + LOG_W("%s: No DMA channel, using PIO", card->name); + } + + card->audio.ops = (struct rt_audio_ops *)&rockchip_audio_card_ops; + card->audio.parent.user_data = card; + + if ((err = rt_audio_register(&card->audio, card->name, RT_DEVICE_FLAG_WRONLY, card))) + { + goto _fail; + } + + dev->user_data = card; + rt_dm_dev_bind_fwdata(dev, RT_NULL, card); + + rt_ofw_node_put(cpu_np); + rt_ofw_node_put(codec_np); + + LOG_D("Registered audio card %s", card->name); + + return RT_EOK; + +_fail: + rt_ofw_node_put(cpu_np); + rt_ofw_node_put(codec_np); + rt_ofw_node_put(card->hdmi_np); + rt_free(card); + + return err; +} + +static rt_err_t rockchip_audio_card_remove(struct rt_platform_device *pdev) +{ + struct rockchip_audio_card *card = pdev->parent.user_data; + + if (!card) + { + return RT_EOK; + } + + rt_device_unregister(&card->audio.parent); + rt_dm_dev_unbind_fwdata(&pdev->parent, RT_NULL); + + if (card->playback_buf) + { + rt_dma_free_coherent(card->dev, ROCKCHIP_AUDIO_PLAYBACK_SIZE, + card->playback_buf, card->playback_dma); + } + + rt_ofw_node_put(card->hdmi_np); + + rt_free(card); + + return RT_EOK; +} + +static const struct rt_ofw_node_id rockchip_audio_card_ofw_ids[] = +{ + { .compatible = "simple-audio-card" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver rockchip_audio_card_driver = +{ + .name = "rockchip-audio-card", + .ids = rockchip_audio_card_ofw_ids, + .probe = rockchip_audio_card_probe, + .remove = rockchip_audio_card_remove, +}; + +static int rockchip_audio_card_register(void) +{ + rt_platform_driver_register(&rockchip_audio_card_driver); + + return 0; +} +INIT_COMPONENT_EXPORT(rockchip_audio_card_register); diff --git a/bsp/rockchip/dm/audio/rockchip-i2s-tdm.c b/bsp/rockchip/dm/audio/rockchip-i2s-tdm.c new file mode 100644 index 000000000000..a27dfef1046a --- /dev/null +++ b/bsp/rockchip/dm/audio/rockchip-i2s-tdm.c @@ -0,0 +1,515 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-11-26 GuEe-GUI first version + */ + +#include + +#define DBG_TAG "i2s.rockchip" +#define DBG_LVL DBG_INFO +#include + +#include "rockchip.h" +#include "rockchip-i2s-tdm.h" + +#define I2S_FIFO_DEPTH 32 +#define I2S_DEFAULT_MCLK_FS 256 + +struct rockchip_i2s_tdm +{ + struct rt_device parent; + + void *regs; + rt_ubase_t phys; + int irq; + + struct rt_clk *hclk; + struct rt_clk *mclk_tx; + struct rt_clk *mclk_rx; + struct rt_reset_control *rst_tx; + struct rt_reset_control *rst_rx; + struct rt_syscon *grf; + + rt_bool_t trcm_tx_only; + rt_bool_t playback_only; + rt_bool_t running; + + rt_uint32_t mclk_fs; + struct rockchip_i2s_config config; + + struct rt_dma_chan *dma_tx; + rt_ubase_t dma_addr; + + struct rt_ofw_node *np; + rt_list_t list; +}; + +static rt_list_t i2s_list = RT_LIST_OBJECT_INIT(i2s_list); +static RT_DEFINE_SPINLOCK(i2s_list_lock); + +static rt_err_t rockchip_i2s_tdm_set_mclk(struct rockchip_i2s_tdm *i2s, + rt_ubase_t rate) +{ + struct rt_clk_cell *cell, *parent; + struct rt_clk *clk; + rt_err_t err; + + cell = i2s->mclk_tx->cell; + + /* Skip pass-through gates and configure the first programmable clock. */ + while (cell->parents_nr == 1 && !cell->ops->set_rate) + { + cell = rt_clk_cell_get_parent_by_index(cell, 0); + if (!cell) + { + return -RT_ENOSYS; + } + } + + if (cell->ops->set_rate) + { + clk = rt_clk_cell_get_clk(cell, RT_NULL); + return clk ? rt_clk_set_rate(clk, rate) : -RT_ENOMEM; + } + + /* Rockchip I2S muxes use an internal fractional clock for audio rates. */ + for (rt_uint8_t index = 0; index < cell->parents_nr; ++index) + { + parent = rt_clk_cell_get_parent_by_index(cell, index); + if (!parent || !parent->ops->set_rate) + { + continue; + } + + if (rt_clk_cell_round_rate(parent, rate) != rate) + { + continue; + } + + clk = rt_clk_cell_get_clk(parent, RT_NULL); + if (!clk || (err = rt_clk_set_rate(clk, rate))) + { + continue; + } + + if ((err = rt_clk_cell_set_parent(cell, parent))) + { + return err; + } + + return RT_EOK; + } + + return -RT_ENOSYS; +} + +rt_inline rt_uint32_t i2s_readl(struct rockchip_i2s_tdm *i2s, rt_ubase_t reg) +{ + return HWREG32(i2s->regs + reg); +} + +rt_inline void i2s_writel(struct rockchip_i2s_tdm *i2s, rt_ubase_t reg, rt_uint32_t val) +{ + HWREG32(i2s->regs + reg) = val; +} + +rt_inline void i2s_update_bits(struct rockchip_i2s_tdm *i2s, + rt_ubase_t reg, rt_uint32_t mask, rt_uint32_t val) +{ + rt_uint32_t tmp = i2s_readl(i2s, reg); + + tmp &= ~mask; + tmp |= (val & mask); + i2s_writel(i2s, reg, tmp); +} + +struct rockchip_i2s_tdm *rockchip_i2s_tdm_find(struct rt_ofw_node *np) +{ + struct rockchip_i2s_tdm *i2s; + + rt_spin_lock(&i2s_list_lock); + rt_list_for_each_entry(i2s, &i2s_list, list) + { + if (i2s->np == np) + { + rt_spin_unlock(&i2s_list_lock); + return i2s; + } + } + rt_spin_unlock(&i2s_list_lock); + + return RT_NULL; +} + +static rt_err_t rockchip_i2s_tdm_grf_init(struct rockchip_i2s_tdm *i2s) +{ + rt_uint64_t addr; + + if (!i2s->trcm_tx_only || !i2s->grf) + { + return RT_EOK; + } + + if (rt_dm_dev_get_address(&i2s->parent, 0, &addr, RT_NULL)) + { + return -RT_EINVAL; + } + + if (addr == 0xfe410000) + { + return rt_syscon_write(i2s->grf, RK3568_I2S1_GRF_REG, RK3568_I2S1_CLK_TXONLY); + } + + return RT_EOK; +} + +static rt_err_t rockchip_i2s_tdm_set_fmt(struct rockchip_i2s_tdm *i2s) +{ + rt_uint32_t val = I2S_CKR_MSS_MASTER | I2S_CKR_CKP_NORMAL | + I2S_CKR_TLP_NORMAL | I2S_CKR_RLP_NORMAL; + rt_uint32_t txcr = I2S_TXCR_IBM_NORMAL | I2S_TXCR_TFS_I2S | I2S_CHN_2; + + if (i2s->trcm_tx_only) + { + val |= I2S_CKR_TRCM_TXONLY; + } + + i2s_update_bits(i2s, I2S_CKR, I2S_CKR_MSS_MASK | I2S_CKR_TRCM_MASK | + (3 << 24) | (1 << 26), val); + i2s_update_bits(i2s, I2S_TXCR, I2S_TXCR_VDW_MASK | I2S_TXCR_CSR_MASK | + (3 << 5) | (3 << 9), txcr | I2S_TXCR_VDW(16)); + + return RT_EOK; +} + +rt_err_t rockchip_i2s_tdm_hw_params(struct rockchip_i2s_tdm *i2s, + const struct rockchip_i2s_config *cfg) +{ + rt_uint32_t mclk_rate, bclk_rate, lrck_rate; + rt_uint32_t div_bclk, div_lrck; + rt_uint32_t fmt = I2S_TXCR_VDW(cfg->samplebits) | I2S_CHN_2; + rt_err_t err; + + if (!i2s || !cfg) + { + return -RT_EINVAL; + } + + i2s->config = *cfg; + i2s->mclk_fs = cfg->mclk_fs ? cfg->mclk_fs : I2S_DEFAULT_MCLK_FS; + + if (i2s->mclk_tx) + { + mclk_rate = cfg->samplerate * i2s->mclk_fs; + + if ((err = rockchip_i2s_tdm_set_mclk(i2s, mclk_rate))) + { + LOG_E("set mclk_tx rate %u failed", mclk_rate); + return err; + } + + if ((err = rt_clk_prepare_enable(i2s->mclk_tx))) + { + return err; + } + } + + mclk_rate = i2s->mclk_tx ? rt_clk_get_rate(i2s->mclk_tx) : (cfg->samplerate * i2s->mclk_fs); + lrck_rate = cfg->samplerate; + /* Rockchip and DW-HDMI use two 32-bit I2S slots by default. */ + bclk_rate = I2S_DEFAULT_FRAME_WIDTH * lrck_rate; + + if (!bclk_rate) + { + return -RT_EINVAL; + } + + div_bclk = RT_DIV_ROUND_CLOSEST(mclk_rate, bclk_rate); + div_lrck = RT_DIV_ROUND_CLOSEST(bclk_rate, lrck_rate); + + if (div_bclk < 1) + { + div_bclk = 1; + } + + if (div_lrck < 1) + { + div_lrck = 1; + } + + rockchip_i2s_tdm_set_fmt(i2s); + + i2s_update_bits(i2s, I2S_CLKDIV, I2S_CLKDIV_TXM_MASK, I2S_CLKDIV_TXM(div_bclk)); + i2s_update_bits(i2s, I2S_CKR, I2S_CKR_TSD_MASK, I2S_CKR_TSD(div_lrck)); + i2s_update_bits(i2s, I2S_TXCR, I2S_TXCR_VDW_MASK | I2S_TXCR_CSR_MASK, fmt); + + return RT_EOK; +} + +rt_err_t rockchip_i2s_tdm_start(struct rockchip_i2s_tdm *i2s) +{ + if (!i2s) + { + return -RT_EINVAL; + } + + if (i2s->rst_tx) + { + rt_reset_control_assert(i2s->rst_tx); + rt_reset_control_deassert(i2s->rst_tx); + } + + i2s_writel(i2s, I2S_CLR, I2S_CLR_TXC); + + if (i2s->trcm_tx_only) + { + i2s_update_bits(i2s, I2S_XFER, I2S_XFER_TXS_MASK | I2S_XFER_RXS_MASK, + I2S_XFER_TXS_START | I2S_XFER_RXS_START); + } + else + { + i2s_update_bits(i2s, I2S_XFER, I2S_XFER_TXS_MASK, I2S_XFER_TXS_START); + } + + i2s->running = RT_TRUE; + + return RT_EOK; +} + +rt_err_t rockchip_i2s_tdm_stop(struct rockchip_i2s_tdm *i2s) +{ + if (!i2s) + { + return -RT_EINVAL; + } + + if (i2s->trcm_tx_only) + { + i2s_update_bits(i2s, I2S_XFER, I2S_XFER_TXS_MASK | I2S_XFER_RXS_MASK, + I2S_XFER_TXS_STOP | I2S_XFER_RXS_STOP); + i2s_writel(i2s, I2S_CLR, I2S_CLR_TXC); + } + else + { + i2s_update_bits(i2s, I2S_XFER, I2S_XFER_TXS_MASK, I2S_XFER_TXS_STOP); + i2s_writel(i2s, I2S_CLR, I2S_CLR_TXC); + } + + rt_hw_us_delay(150); + i2s->running = RT_FALSE; + + if (i2s->mclk_tx) + { + rt_clk_disable_unprepare(i2s->mclk_tx); + } + + return RT_EOK; +} + +rt_ssize_t rockchip_i2s_tdm_push(struct rockchip_i2s_tdm *i2s, + const rt_uint8_t *buf, rt_size_t size) +{ + rt_size_t i = 0; + rt_uint32_t fifo; + + if (!i2s || !buf || !size) + { + return 0; + } + + while (i + 1 < size) + { + fifo = i2s_readl(i2s, I2S_TXFIFOLR) & I2S_FIFOLR_TFL0_MASK; + + if (fifo >= I2S_FIFO_DEPTH) + { + rt_thread_mdelay(1); + continue; + } + + i2s_writel(i2s, I2S_TXDR, buf[i] | (buf[i + 1] << 8)); + i += 2; + } + + return i; +} + +struct rt_dma_chan *rockchip_i2s_tdm_get_dma_tx(struct rockchip_i2s_tdm *i2s) +{ + return i2s ? i2s->dma_tx : RT_NULL; +} + +rt_ubase_t rockchip_i2s_tdm_txdr_phys(struct rockchip_i2s_tdm *i2s) +{ + if (!i2s) + { + return 0; + } + + return i2s->phys + I2S_TXDR; +} + +rt_err_t rockchip_i2s_tdm_dma_enable(struct rockchip_i2s_tdm *i2s) +{ + if (!i2s) + { + return -RT_EINVAL; + } + + i2s_update_bits(i2s, I2S_DMACR, I2S_DMACR_TDL_MASK | I2S_DMACR_TDE_MASK, + I2S_DMACR_TDL(16) | I2S_DMACR_TDE_ENABLE); + + return RT_EOK; +} + +rt_err_t rockchip_i2s_tdm_dma_disable(struct rockchip_i2s_tdm *i2s) +{ + if (!i2s) + { + return -RT_EINVAL; + } + + i2s_update_bits(i2s, I2S_DMACR, I2S_DMACR_TDE_MASK, 0); + + return RT_EOK; +} + +static rt_err_t rockchip_i2s_tdm_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + struct rt_device *dev = &pdev->parent; + struct rockchip_i2s_tdm *i2s; + struct rt_ofw_node *grf_np; + + i2s = rt_calloc(1, sizeof(*i2s)); + + if (!i2s) + { + return -RT_ENOMEM; + } + + i2s->np = dev->ofw_node; + i2s->parent.ofw_node = dev->ofw_node; + i2s->trcm_tx_only = rt_dm_dev_prop_read_bool(dev, "rockchip,trcm-sync-tx-only"); + i2s->playback_only = rt_dm_dev_prop_read_bool(dev, "rockchip,playback-only"); + + i2s->regs = rt_dm_dev_iomap(dev, 0); + + if (!i2s->regs) + { + err = -RT_EIO; + goto _fail; + } + + rt_dm_dev_get_address(dev, 0, &i2s->phys, RT_NULL); + + i2s->hclk = rt_clk_get_by_name(dev, "hclk"); + i2s->mclk_tx = rt_clk_get_by_name(dev, "mclk_tx"); + i2s->mclk_rx = rt_clk_get_by_name(dev, "mclk_rx"); + i2s->rst_tx = rt_reset_control_get_by_name(dev, "tx-m"); + i2s->rst_rx = rt_reset_control_get_by_name(dev, "rx-m"); + + if (!rt_is_err(i2s->hclk)) + { + rt_clk_prepare_enable(i2s->hclk); + } + + if ((grf_np = rt_ofw_parse_phandle(dev->ofw_node, "rockchip,grf", 0))) + { + i2s->grf = rt_syscon_find_by_ofw_node(grf_np); + rt_ofw_node_put(grf_np); + } + + if ((err = rockchip_i2s_tdm_grf_init(i2s))) + { + goto _fail; + } + + i2s->dma_tx = rt_dma_chan_request(dev, "tx"); + + if (rt_is_err_or_null(i2s->dma_tx)) + { + LOG_W("No DMA tx channel, using PIO"); + i2s->dma_tx = RT_NULL; + } + else + { + LOG_D("I2S DMA tx channel ready"); + } + + rt_spin_lock(&i2s_list_lock); + rt_list_insert_before(&i2s_list, &i2s->list); + rt_spin_unlock(&i2s_list_lock); + + dev->user_data = i2s; + rt_dm_dev_bind_fwdata(dev, RT_NULL, i2s); + + LOG_D("I2S/TDM probed at %p", i2s->regs); + + return RT_EOK; + +_fail: + rt_free(i2s); + + return err; +} + +static rt_err_t rockchip_i2s_tdm_remove(struct rt_platform_device *pdev) +{ + struct rockchip_i2s_tdm *i2s = pdev->parent.user_data; + + if (!i2s) + { + return RT_EOK; + } + + rt_spin_lock(&i2s_list_lock); + rt_list_remove(&i2s->list); + rt_spin_unlock(&i2s_list_lock); + + if (i2s->dma_tx) + { + rt_dma_chan_release(i2s->dma_tx); + i2s->dma_tx = RT_NULL; + } + + rt_dm_dev_unbind_fwdata(&pdev->parent, RT_NULL); + + if (!rt_is_err(i2s->hclk)) + { + rt_clk_disable_unprepare(i2s->hclk); + } + + rt_free(i2s); + + return RT_EOK; +} + +static const struct rt_ofw_node_id rockchip_i2s_tdm_ofw_ids[] = +{ + { .compatible = "rockchip,rk3568-i2s-tdm" }, + { .compatible = "rockchip,rk3588-i2s-tdm" }, + { .compatible = "rockchip,rk3308-i2s-tdm" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver rockchip_i2s_tdm_driver = +{ + .name = "rockchip-i2s-tdm", + .ids = rockchip_i2s_tdm_ofw_ids, + .probe = rockchip_i2s_tdm_probe, + .remove = rockchip_i2s_tdm_remove, +}; + +static int rockchip_i2s_tdm_register(void) +{ + rt_platform_driver_register(&rockchip_i2s_tdm_driver); + + return 0; +} +INIT_DEVICE_EXPORT(rockchip_i2s_tdm_register); diff --git a/bsp/rockchip/dm/audio/rockchip-i2s-tdm.h b/bsp/rockchip/dm/audio/rockchip-i2s-tdm.h new file mode 100644 index 000000000000..73b268a9e0dc --- /dev/null +++ b/bsp/rockchip/dm/audio/rockchip-i2s-tdm.h @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-11-26 GuEe-GUI first version + */ + +#ifndef __ROCKCHIP_I2S_TDM_H__ +#define __ROCKCHIP_I2S_TDM_H__ + +#include +#include + +/* I2S register offsets */ +#define I2S_TXCR 0x0000 +#define I2S_RXCR 0x0004 +#define I2S_CKR 0x0008 +#define I2S_TXFIFOLR 0x000c +#define I2S_DMACR 0x0010 +#define I2S_INTCR 0x0014 +#define I2S_INTSR 0x0018 +#define I2S_XFER 0x001c +#define I2S_CLR 0x0020 +#define I2S_TXDR 0x0024 +#define I2S_RXDR 0x0028 +#define I2S_CLKDIV 0x0038 + +#define I2S_TXCR_VDW(x) (((x) - 1) << 0) +#define I2S_TXCR_VDW_MASK (0x1f << 0) +#define I2S_TXCR_CSR(x) ((x) << 15) +#define I2S_TXCR_CSR_MASK (3 << 15) +#define I2S_TXCR_IBM_NORMAL (0 << 9) +#define I2S_TXCR_TFS_I2S (0 << 5) + +#define I2S_CKR_TRCM_TXONLY (1 << 28) +#define I2S_CKR_TRCM_MASK (3 << 28) +#define I2S_CKR_MSS_MASTER (0 << 27) +#define I2S_CKR_MSS_MASK (1 << 27) +#define I2S_CKR_CKP_NORMAL (0 << 26) +#define I2S_CKR_TLP_NORMAL (0 << 24) +#define I2S_CKR_RLP_NORMAL (0 << 25) +#define I2S_CKR_TSD(x) (((x) - 1) << 0) +#define I2S_CKR_TSD_MASK (0xff << 0) + +#define I2S_CLKDIV_TXM(x) (((x) - 1) << 0) +#define I2S_CLKDIV_TXM_MASK (0xff << 0) + +#define I2S_CHN_2 (0 << 15) + +#define I2S_DMACR_TDE_ENABLE (1 << 8) +#define I2S_DMACR_TDE_MASK (1 << 8) +#define I2S_DMACR_TDL(x) ((x) << 0) +#define I2S_DMACR_TDL_MASK (0x1f << 0) + +#define I2S_XFER_TXS_START (1 << 0) +#define I2S_XFER_TXS_STOP (0 << 0) +#define I2S_XFER_TXS_MASK (1 << 0) +#define I2S_XFER_RXS_START (1 << 1) +#define I2S_XFER_RXS_STOP (0 << 1) +#define I2S_XFER_RXS_MASK (1 << 1) + +#define I2S_CLR_TXC RT_BIT(0) + +#define I2S_FIFOLR_TFL0_MASK 0x3f + +#define RK3568_I2S1_GRF_REG 0x504 +#define RK3568_I2S1_CLK_TXONLY ((1 << (5 + 16)) | (1 << 5)) + +#define I2S_DEFAULT_FRAME_WIDTH 64 + +struct rockchip_i2s_config +{ + rt_uint32_t samplerate; + rt_uint16_t channels; + rt_uint16_t samplebits; + rt_uint32_t mclk_fs; +}; + +struct rockchip_i2s_tdm; + +rt_err_t rockchip_i2s_tdm_hw_params(struct rockchip_i2s_tdm *i2s, + const struct rockchip_i2s_config *cfg); +rt_err_t rockchip_i2s_tdm_start(struct rockchip_i2s_tdm *i2s); +rt_err_t rockchip_i2s_tdm_stop(struct rockchip_i2s_tdm *i2s); +rt_ssize_t rockchip_i2s_tdm_push(struct rockchip_i2s_tdm *i2s, + const rt_uint8_t *buf, rt_size_t size); +struct rockchip_i2s_tdm *rockchip_i2s_tdm_find(struct rt_ofw_node *np); + +#ifdef RT_USING_DMA +struct rt_dma_chan *rockchip_i2s_tdm_get_dma_tx(struct rockchip_i2s_tdm *i2s); +rt_ubase_t rockchip_i2s_tdm_txdr_phys(struct rockchip_i2s_tdm *i2s); +rt_err_t rockchip_i2s_tdm_dma_enable(struct rockchip_i2s_tdm *i2s); +rt_err_t rockchip_i2s_tdm_dma_disable(struct rockchip_i2s_tdm *i2s); +#endif + +#endif /* __ROCKCHIP_I2S_TDM_H__ */ diff --git a/bsp/rockchip/dm/clk/clk-rk3568.c b/bsp/rockchip/dm/clk/clk-rk3568.c index 33c78ae7acf6..ef7885aa094a 100755 --- a/bsp/rockchip/dm/clk/clk-rk3568.c +++ b/bsp/rockchip/dm/clk/clk-rk3568.c @@ -584,8 +584,8 @@ static struct rt_clk_cell *rk3568_clk_cells[] = [PLL_DPLL] = &rk3568_pll_dpll.rk_cell.cell, [PLL_CPLL] = &rk3568_pll_cpll.rk_cell.cell, [PLL_GPLL] = &rk3568_pll_gpll.rk_cell.cell, - [PLL_VPLL] = &rk3568_pll_npll.rk_cell.cell, - [PLL_NPLL] = &rk3568_pll_vpll.rk_cell.cell, + [PLL_VPLL] = &rk3568_pll_vpll.rk_cell.cell, + [PLL_NPLL] = &rk3568_pll_npll.rk_cell.cell, [CPLL_333M] = COMPOSITE_NOMUX(CPLL_333M, "cpll_333m", "cpll", RT_CLK_F_IGNORE_UNUSED, RK3568_CLKSEL_CON(79), 0, 5, DFLAGS, RK3568_CLKGATE_CON(35), 8, GFLAGS), @@ -958,13 +958,13 @@ static struct rt_clk_cell *rk3568_clk_cells[] = RK3568_CLKGATE_CON(20), 6, GFLAGS), [ACLK_VOP] = GATE(ACLK_VOP, "aclk_vop", "aclk_vop_pre", 0, RK3568_CLKGATE_CON(20), 8, GFLAGS), [HCLK_VOP] = GATE(HCLK_VOP, "hclk_vop", "hclk_vo", 0, RK3568_CLKGATE_CON(20), 9, GFLAGS), - [DCLK_VOP0] = COMPOSITE(DCLK_VOP0, "dclk_vop0", hpll_vpll_gpll_cpll_p, 0, + [DCLK_VOP0] = COMPOSITE(DCLK_VOP0, "dclk_vop0", hpll_vpll_gpll_cpll_p, RT_CLK_F_SET_RATE_NO_REPARENT, RK3568_CLKSEL_CON(39), 10, 2, MFLAGS, 0, 8, DFLAGS, RK3568_CLKGATE_CON(20), 10, GFLAGS), - [DCLK_VOP1] = COMPOSITE(DCLK_VOP1, "dclk_vop1", hpll_vpll_gpll_cpll_p, 0, + [DCLK_VOP1] = COMPOSITE(DCLK_VOP1, "dclk_vop1", hpll_vpll_gpll_cpll_p, RT_CLK_F_SET_RATE_NO_REPARENT, RK3568_CLKSEL_CON(40), 10, 2, MFLAGS, 0, 8, DFLAGS, RK3568_CLKGATE_CON(20), 11, GFLAGS), - [DCLK_VOP2] = COMPOSITE(DCLK_VOP2, "dclk_vop2", hpll_vpll_gpll_cpll_p, 0, + [DCLK_VOP2] = COMPOSITE(DCLK_VOP2, "dclk_vop2", hpll_vpll_gpll_cpll_p, RT_CLK_F_SET_RATE_NO_REPARENT, RK3568_CLKSEL_CON(41), 10, 2, MFLAGS, 0, 8, DFLAGS, RK3568_CLKGATE_CON(20), 12, GFLAGS), [CLK_VOP_PWM] = GATE(CLK_VOP_PWM, "clk_vop_pwm", "xin24m", 0, RK3568_CLKGATE_CON(20), 13, GFLAGS), diff --git a/bsp/rockchip/dm/dvfs/event/event-rockchip-dfi.c b/bsp/rockchip/dm/dvfs/event/event-rockchip-dfi.c index 60f90395cadb..b20e075e1d19 100755 --- a/bsp/rockchip/dm/dvfs/event/event-rockchip-dfi.c +++ b/bsp/rockchip/dm/dvfs/event/event-rockchip-dfi.c @@ -335,7 +335,7 @@ static rt_err_t rockchip_dfi_probe(struct rt_platform_device *pdev) pdev->priv = dfi; - LOG_I("%s: dram_type=%u ch_msk=0x%x", rt_dm_dev_get_name(dev), + LOG_D("%s: dram_type=%u ch_msk=0x%x", rt_dm_dev_get_name(dev), dfi->dram_type, dfi->ch_msk); return RT_EOK; diff --git a/bsp/rockchip/dm/ethernet/Kconfig b/bsp/rockchip/dm/ethernet/Kconfig new file mode 100644 index 000000000000..47673e506d29 --- /dev/null +++ b/bsp/rockchip/dm/ethernet/Kconfig @@ -0,0 +1,5 @@ +config RT_ETHERNET_DWMAC_ROCKCHIP + bool "Rockchip DWMAC (RK3308/RK3528/RK3568/RK3576/RK3588)" + depends on RT_ETHERNET_DWMAC + depends on RT_USING_OFW + default n diff --git a/bsp/rockchip/dm/ethernet/SConscript b/bsp/rockchip/dm/ethernet/SConscript new file mode 100644 index 000000000000..2d6d227833ab --- /dev/null +++ b/bsp/rockchip/dm/ethernet/SConscript @@ -0,0 +1,14 @@ +from building import * + +group = [] +src = [] +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../include', + cwd + '/../../../../components/drivers/ethernet/synopsys'] + +if GetDepend(['RT_ETHERNET_DWMAC_ROCKCHIP']): + src += ['dwmac-rockchip.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/rockchip/dm/ethernet/dwmac-rockchip.c b/bsp/rockchip/dm/ethernet/dwmac-rockchip.c new file mode 100644 index 000000000000..4ef1872f2837 --- /dev/null +++ b/bsp/rockchip/dm/ethernet/dwmac-rockchip.c @@ -0,0 +1,959 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-11-26 GuEe-GUI first version + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rockchip.h" +#include "dwmac-platform.h" + +#define DBG_TAG "eth.dwmac.rk" +#define DBG_LVL DBG_INFO +#include + +#define GRF_BIT(nr) (RT_BIT(nr) | RT_BIT((nr) + 16)) +#define GRF_CLR_BIT(nr) RT_BIT((nr) + 16) + +#define DELAY_ENABLE(soc, tx, rx) \ + ((((tx) >= 0) ? soc##_GMAC_TXCLK_DLY_ENABLE : soc##_GMAC_TXCLK_DLY_DISABLE) | \ + (((rx) >= 0) ? soc##_GMAC_RXCLK_DLY_ENABLE : soc##_GMAC_RXCLK_DLY_DISABLE)) + +#define DELAY_ENABLE_BY_ID(soc, tx, rx, id) \ + ((((tx) >= 0) ? soc##_GMAC_TXCLK_DLY_ENABLE(id) : soc##_GMAC_TXCLK_DLY_DISABLE(id)) | \ + (((rx) >= 0) ? soc##_GMAC_RXCLK_DLY_ENABLE(id) : soc##_GMAC_RXCLK_DLY_DISABLE(id))) + +#define DELAY_VALUE(soc, tx, rx) \ + ((((tx) >= 0) ? soc##_GMAC_CLK_TX_DL_CFG(tx) : 0) | \ + (((rx) >= 0) ? soc##_GMAC_CLK_RX_DL_CFG(rx) : 0)) + +struct dwmac_rk_soc; + +struct dwmac_rk_priv +{ + struct rt_syscon *grf; + struct rt_syscon *php_grf; + int id; + int tx_delay; + int rx_delay; + rt_bool_t clock_input; + struct rt_clk *clk_phy; + struct rt_clk *pclk_xpcs; + struct rt_clk *clk_xpcs_eee; + const struct dwmac_rk_soc *soc; +}; + +struct dwmac_rk_soc +{ + void (*set_rgmii)(struct dwmac_rk_priv *priv, int tx_delay, int rx_delay); + void (*set_rmii)(struct dwmac_rk_priv *priv); + rt_err_t (*fix_link_speed)(struct dwmac_eth *eth, int speed); + void (*clock_selection)(struct dwmac_rk_priv *priv, rt_bool_t input, rt_bool_t enable); + rt_bool_t need_php_grf; +}; + +static void dwmac_rk_setup_interface(struct dwmac_eth *eth); + +static rt_err_t dwmac_rk_clk_prepare_enable(struct rt_clk *clk) +{ + if (rt_is_err_or_null(clk)) + { + return RT_EOK; + } + + return rt_clk_prepare_enable(clk); +} + +static void dwmac_rk_clk_disable_unprepare(struct rt_clk *clk) +{ + if (!rt_is_err_or_null(clk)) + { + rt_clk_disable_unprepare(clk); + } +} + +static long dwmac_rgmii_clock(int speed) +{ + switch (speed) + { + case SPEED_10: + return 2500000; + case SPEED_100: + return 25000000; + case SPEED_1000: + return 125000000; + default: + return -1; + } +} + +static rt_err_t dwmac_rk_clk_set_rate_path(struct rt_clk *clk, rt_ubase_t rate) +{ + struct rt_clk_cell *cell, *parent_cell; + struct rt_clk *parent_clk; + rt_err_t err; + + if (rt_clk_get_rate(clk) == rate) + { + return RT_EOK; + } + + err = rt_clk_set_rate(clk, rate); + if (err != -RT_ENOSYS) + { + return err; + } + + cell = clk->cell; + if (cell->flags & RT_CLK_F_SET_RATE_PARENT) + { + parent_cell = rt_clk_cell_get_parent(cell); + parent_clk = parent_cell ? rt_clk_cell_get_clk(parent_cell, RT_NULL) : RT_NULL; + if (parent_clk) + { + err = dwmac_rk_clk_set_rate_path(parent_clk, rate); + if (!err && rt_clk_get_rate(clk) == rate) + { + return RT_EOK; + } + } + } + + /* Rockchip speed clocks are muxes whose parents provide the exact rates. */ + for (rt_uint8_t index = 0; index < cell->parents_nr; ++index) + { + parent_cell = rt_clk_cell_get_parent_by_index(cell, index); + if (!parent_cell) + { + continue; + } + + parent_clk = rt_clk_cell_get_clk(parent_cell, RT_NULL); + if (!parent_clk || rt_clk_get_rate(parent_clk) != (rt_ubase_t)rate) + { + continue; + } + + return rt_clk_set_parent(clk, parent_clk); + } + + return -RT_ENOSYS; +} + +static rt_err_t dwmac_rk_clk_set_rate(struct dwmac_eth *eth, long rate) +{ + if (rt_is_err_or_null(eth->mac_clk_speed) || rate < 0) + { + return rate < 0 ? -RT_EINVAL : RT_EOK; + } + + return dwmac_rk_clk_set_rate_path(eth->mac_clk_speed, rate); +} + +static int dwmac_rk_gmac_id(struct rt_ofw_node *np) +{ + int id = rt_ofw_get_alias_id(np, "ethernet"); + + return id < 0 ? 0 : id; +} + +static rt_err_t dwmac_rk_parse_common(struct dwmac_eth *eth, + const struct dwmac_rk_soc *soc) +{ + struct dwmac_rk_priv *priv = eth->plat_priv; + struct rt_ofw_node *np = eth->dev->ofw_node; + struct rt_ofw_node *phy_np; + const char *clock_in_out = RT_NULL; + + if (!priv) + { + priv = rt_calloc(1, sizeof(*priv)); + if (!priv) + { + return -RT_ENOMEM; + } + eth->plat_priv = priv; + } + + priv->soc = soc; + + priv->grf = rt_syscon_find_by_ofw_phandle(np, "rockchip,grf"); + if (rt_is_err_or_null(priv->grf)) + { + LOG_E("rockchip,grf not found"); + return -RT_EIO; + } + + if (soc->need_php_grf) + { + priv->php_grf = rt_syscon_find_by_ofw_phandle(np, "rockchip,php_grf"); + if (rt_is_err_or_null(priv->php_grf)) + { + LOG_E("rockchip,php_grf not found"); + return -RT_EIO; + } + } + + priv->id = dwmac_rk_gmac_id(np); + + if (rt_ofw_prop_read_u32(np, "tx_delay", (rt_uint32_t *)&priv->tx_delay)) + { + priv->tx_delay = 0x30; + } + + if (rt_ofw_prop_read_u32(np, "rx_delay", (rt_uint32_t *)&priv->rx_delay)) + { + priv->rx_delay = 0x10; + } + + if (rt_ofw_prop_read_string(np, "clock_in_out", &clock_in_out) || + !clock_in_out) + { + priv->clock_input = RT_TRUE; + } + else + { + priv->clock_input = !rt_strcmp(clock_in_out, "input"); + } + + LOG_I("gmac%d clock_in_out=%s clock_input=%d", priv->id, + clock_in_out ? clock_in_out : "", priv->clock_input); + + if (eth->phy_interface == RT_PHY_INTERFACE_MODE_SGMII || + eth->phy_interface == RT_PHY_INTERFACE_MODE_QSGMII) + { + priv->pclk_xpcs = rt_clk_get_by_name(eth->dev, "pclk_xpcs"); + priv->clk_xpcs_eee = rt_clk_get_by_name(eth->dev, "clk_xpcs_eee"); + } + + phy_np = rt_ofw_parse_phandle(np, "phy-handle", 0); + if (phy_np) + { + priv->clk_phy = rt_ofw_get_clk(phy_np, 0); + rt_ofw_node_put(phy_np); + } + + return RT_EOK; +} + +/* RK3308 */ +#define RK3308_GRF_MAC_CON0 0x04a0 + +#define RK3308_MAC_PHY_INTF_SEL_RMII \ + (GRF_CLR_BIT(4) | GRF_CLR_BIT(5) | GRF_BIT(6)) +#define RK3308_MAC_SPEED_10M GRF_CLR_BIT(0) +#define RK3308_MAC_SPEED_100M GRF_BIT(0) + +static void dwmac_rk3308_set_rmii(struct dwmac_rk_priv *priv) +{ + rt_syscon_write(priv->grf, RK3308_GRF_MAC_CON0, RK3308_MAC_PHY_INTF_SEL_RMII); +} + +static rt_err_t dwmac_rk3308_fix_link_speed(struct dwmac_eth *eth, int speed) +{ + struct dwmac_rk_priv *priv = eth->plat_priv; + rt_err_t err; + long rate; + + switch (speed) + { + case SPEED_10: + rt_syscon_write(priv->grf, RK3308_GRF_MAC_CON0, RK3308_MAC_SPEED_10M); + rate = 2500000; + break; + case SPEED_100: + rt_syscon_write(priv->grf, RK3308_GRF_MAC_CON0, RK3308_MAC_SPEED_100M); + rate = 25000000; + break; + default: + return -RT_EINVAL; + } + + err = dwmac_rk_clk_set_rate(eth, rate); + return err; +} + +static const struct dwmac_rk_soc dwmac_rk3308_soc = +{ + .set_rmii = dwmac_rk3308_set_rmii, + .fix_link_speed = dwmac_rk3308_fix_link_speed, +}; + +/* RK3528 */ +#define RK3528_VO_GRF_GMAC_CON 0x60018 +#define RK3528_VPU_GRF_GMAC_CON5 0x40018 +#define RK3528_VPU_GRF_GMAC_CON6 0x4001c + +#define RK3528_GMAC_RXCLK_DLY_ENABLE GRF_BIT(15) +#define RK3528_GMAC_RXCLK_DLY_DISABLE GRF_CLR_BIT(15) +#define RK3528_GMAC_TXCLK_DLY_ENABLE GRF_BIT(14) +#define RK3528_GMAC_TXCLK_DLY_DISABLE GRF_CLR_BIT(14) +#define RK3528_GMAC_CLK_RX_DL_CFG(val) HIWORD_UPDATE(val, 0xFF, 8) +#define RK3528_GMAC_CLK_TX_DL_CFG(val) HIWORD_UPDATE(val, 0xFF, 0) + +#define RK3528_GMAC0_PHY_INTF_SEL_RMII GRF_BIT(1) +#define RK3528_GMAC1_PHY_INTF_SEL_RGMII GRF_CLR_BIT(8) +#define RK3528_GMAC1_PHY_INTF_SEL_RMII GRF_BIT(8) +#define RK3528_GMAC1_CLK_SELET_CRU GRF_CLR_BIT(12) +#define RK3528_GMAC1_CLK_SELET_IO GRF_BIT(12) +#define RK3528_GMAC0_CLK_RMII_DIV2 GRF_BIT(3) +#define RK3528_GMAC1_CLK_RMII_DIV2 GRF_BIT(10) +#define RK3528_GMAC0_CLK_RMII_DIV20 GRF_CLR_BIT(3) +#define RK3528_GMAC1_CLK_RMII_DIV20 GRF_CLR_BIT(10) +#define RK3528_GMAC1_CLK_RGMII_DIV1 (GRF_CLR_BIT(11) | GRF_CLR_BIT(10)) +#define RK3528_GMAC1_CLK_RGMII_DIV5 (GRF_BIT(11) | GRF_BIT(10)) +#define RK3528_GMAC1_CLK_RGMII_DIV50 (GRF_BIT(11) | GRF_CLR_BIT(10)) +#define RK3528_GMAC0_CLK_RMII_GATE GRF_BIT(2) +#define RK3528_GMAC0_CLK_RMII_NOGATE GRF_CLR_BIT(2) +#define RK3528_GMAC1_CLK_RMII_GATE GRF_BIT(9) +#define RK3528_GMAC1_CLK_RMII_NOGATE GRF_CLR_BIT(9) + +static void dwmac_rk3528_set_rgmii(struct dwmac_rk_priv *priv, + int tx_delay, int rx_delay) +{ + if (priv->id != 1) + { + LOG_W("RGMII on rk3528 gmac0 is not supported"); + return; + } + + rt_syscon_write(priv->grf, RK3528_VPU_GRF_GMAC_CON5, + RK3528_GMAC1_PHY_INTF_SEL_RGMII | + DELAY_ENABLE(RK3528, tx_delay, rx_delay)); + rt_syscon_write(priv->grf, RK3528_VPU_GRF_GMAC_CON6, + DELAY_VALUE(RK3528, tx_delay, rx_delay)); +} + +static void dwmac_rk3528_set_rmii(struct dwmac_rk_priv *priv) +{ + if (priv->id == 1) + { + rt_syscon_write(priv->grf, RK3528_VPU_GRF_GMAC_CON5, + RK3528_GMAC1_PHY_INTF_SEL_RMII); + } + else + { + rt_syscon_write(priv->grf, RK3528_VO_GRF_GMAC_CON, + RK3528_GMAC0_PHY_INTF_SEL_RMII | RK3528_GMAC0_CLK_RMII_DIV2); + } +} + +static rt_err_t dwmac_rk3528_fix_link_speed(struct dwmac_eth *eth, int speed) +{ + struct dwmac_rk_priv *priv = eth->plat_priv; + rt_uint32_t val = 0, offset; + + switch (speed) + { + case SPEED_10: + val = (priv->id == 1) ? RK3528_GMAC1_CLK_RMII_DIV20 : + RK3528_GMAC0_CLK_RMII_DIV20; + break; + case SPEED_100: + val = (priv->id == 1) ? RK3528_GMAC1_CLK_RMII_DIV2 : + RK3528_GMAC0_CLK_RMII_DIV2; + break; + case SPEED_1000: + if (priv->id != 1) + { + return -RT_EINVAL; + } + val = RK3528_GMAC1_CLK_RGMII_DIV1; + break; + default: + return -RT_EINVAL; + } + + offset = (priv->id == 1) ? RK3528_VPU_GRF_GMAC_CON5 : RK3528_VO_GRF_GMAC_CON; + rt_syscon_write(priv->grf, offset, val); + + return RT_EOK; +} + +static void dwmac_rk3528_clock_selection(struct dwmac_rk_priv *priv, + rt_bool_t input, rt_bool_t enable) +{ + rt_uint32_t value; + + if (priv->id == 1) + { + value = input ? RK3528_GMAC1_CLK_SELET_IO : RK3528_GMAC1_CLK_SELET_CRU; + value |= enable ? RK3528_GMAC1_CLK_RMII_NOGATE : RK3528_GMAC1_CLK_RMII_GATE; + rt_syscon_write(priv->grf, RK3528_VPU_GRF_GMAC_CON5, value); + } + else + { + value = enable ? RK3528_GMAC0_CLK_RMII_NOGATE : RK3528_GMAC0_CLK_RMII_GATE; + rt_syscon_write(priv->grf, RK3528_VO_GRF_GMAC_CON, value); + } +} + +static const struct dwmac_rk_soc dwmac_rk3528_soc = +{ + .set_rgmii = dwmac_rk3528_set_rgmii, + .set_rmii = dwmac_rk3528_set_rmii, + .fix_link_speed = dwmac_rk3528_fix_link_speed, + .clock_selection = dwmac_rk3528_clock_selection, +}; + +/* RK3568 */ +#define RK3568_GRF_GMAC0_CON0 0x0380 +#define RK3568_GRF_GMAC0_CON1 0x0384 +#define RK3568_GRF_GMAC1_CON0 0x0388 +#define RK3568_GRF_GMAC1_CON1 0x038c + +#define RK3568_GMAC_PHY_INTF_SEL_RGMII \ + (GRF_BIT(4) | GRF_CLR_BIT(5) | GRF_CLR_BIT(6)) +#define RK3568_GMAC_PHY_INTF_SEL_RMII \ + (GRF_CLR_BIT(4) | GRF_CLR_BIT(5) | GRF_BIT(6)) +#define RK3568_GMAC_RXCLK_DLY_ENABLE GRF_BIT(1) +#define RK3568_GMAC_RXCLK_DLY_DISABLE GRF_CLR_BIT(1) +#define RK3568_GMAC_TXCLK_DLY_ENABLE GRF_BIT(0) +#define RK3568_GMAC_TXCLK_DLY_DISABLE GRF_CLR_BIT(0) +#define RK3568_GMAC_CLK_RX_DL_CFG(val) HIWORD_UPDATE(val, 0x7f, 8) +#define RK3568_GMAC_CLK_TX_DL_CFG(val) HIWORD_UPDATE(val, 0x7f, 0) + +static void dwmac_rk3568_set_rgmii(struct dwmac_rk_priv *priv, + int tx_delay, int rx_delay) +{ + rt_uint32_t con0, con1; + + con0 = (priv->id == 1) ? RK3568_GRF_GMAC1_CON0 : RK3568_GRF_GMAC0_CON0; + con1 = (priv->id == 1) ? RK3568_GRF_GMAC1_CON1 : RK3568_GRF_GMAC0_CON1; + + rt_syscon_write(priv->grf, con1, + RK3568_GMAC_PHY_INTF_SEL_RGMII | + DELAY_ENABLE(RK3568, tx_delay, rx_delay)); + rt_syscon_write(priv->grf, con0, DELAY_VALUE(RK3568, tx_delay, rx_delay)); +} + +static void dwmac_rk3568_set_rmii(struct dwmac_rk_priv *priv) +{ + rt_uint32_t con1; + + con1 = (priv->id == 1) ? RK3568_GRF_GMAC1_CON1 : RK3568_GRF_GMAC0_CON1; + rt_syscon_write(priv->grf, con1, RK3568_GMAC_PHY_INTF_SEL_RMII); +} + +static rt_err_t dwmac_rk3568_fix_link_speed(struct dwmac_eth *eth, int speed) +{ + struct dwmac_rk_priv *priv = eth->plat_priv; + rt_err_t err; + long rate = dwmac_rgmii_clock(speed); + + if (rate < 0) + { + return -RT_EINVAL; + } + + err = dwmac_rk_clk_set_rate(eth, rate); + if (err) + { + LOG_W("gmac%d set clk_mac_speed rate=%ld failed: %s", + priv ? priv->id : -1, rate, rt_strerror(err)); + } + + return err; +} + +static const struct dwmac_rk_soc dwmac_rk3568_soc = +{ + .set_rgmii = dwmac_rk3568_set_rgmii, + .set_rmii = dwmac_rk3568_set_rmii, + .fix_link_speed = dwmac_rk3568_fix_link_speed, +}; + +/* RK3576 */ +#define RK3576_VCCIO0_1_3_IOC_CON2 0x6408 +#define RK3576_VCCIO0_1_3_IOC_CON4 0x6410 + +#define RK3576_GRF_GMAC_CON0 0x0020 +#define RK3576_GRF_GMAC_CON1 0x0024 + +#define RK3576_GMAC_RXCLK_DLY_ENABLE GRF_BIT(15) +#define RK3576_GMAC_RXCLK_DLY_DISABLE GRF_CLR_BIT(15) +#define RK3576_GMAC_TXCLK_DLY_ENABLE GRF_BIT(7) +#define RK3576_GMAC_TXCLK_DLY_DISABLE GRF_CLR_BIT(7) +#define RK3576_GMAC_CLK_RX_DL_CFG(val) HIWORD_UPDATE(val, 0x7f, 8) +#define RK3576_GMAC_CLK_TX_DL_CFG(val) HIWORD_UPDATE(val, 0x7f, 0) + +#define RK3576_GMAC_RMII_MODE GRF_BIT(3) +#define RK3576_GMAC_RGMII_MODE GRF_CLR_BIT(3) +#define RK3576_GMAC_CLK_SELET_IO GRF_BIT(7) +#define RK3576_GMAC_CLK_SELET_CRU GRF_CLR_BIT(7) +#define RK3576_GMAC_CLK_RMII_DIV2 GRF_BIT(5) +#define RK3576_GMAC_CLK_RMII_DIV20 GRF_CLR_BIT(5) +#define RK3576_GMAC_CLK_RGMII_DIV1 (GRF_CLR_BIT(6) | GRF_CLR_BIT(5)) +#define RK3576_GMAC_CLK_RGMII_DIV5 (GRF_BIT(6) | GRF_BIT(5)) +#define RK3576_GMAC_CLK_RGMII_DIV50 (GRF_BIT(6) | GRF_CLR_BIT(5)) +#define RK3576_GMAC_CLK_RMII_GATE GRF_BIT(4) +#define RK3576_GMAC_CLK_RMII_NOGATE GRF_CLR_BIT(4) + +static void dwmac_rk3576_set_rgmii(struct dwmac_rk_priv *priv, + int tx_delay, int rx_delay) +{ + rt_uint32_t offset_con; + + offset_con = (priv->id == 1) ? RK3576_GRF_GMAC_CON1 : RK3576_GRF_GMAC_CON0; + rt_syscon_write(priv->grf, offset_con, RK3576_GMAC_RGMII_MODE); + + offset_con = (priv->id == 1) ? RK3576_VCCIO0_1_3_IOC_CON4 : + RK3576_VCCIO0_1_3_IOC_CON2; + + rt_syscon_write(priv->php_grf, offset_con, + DELAY_ENABLE(RK3576, tx_delay, rx_delay)); + rt_syscon_write(priv->php_grf, offset_con + 0x4, + DELAY_ENABLE(RK3576, tx_delay, rx_delay)); + rt_syscon_write(priv->php_grf, offset_con, + DELAY_VALUE(RK3576, tx_delay, rx_delay)); + rt_syscon_write(priv->php_grf, offset_con + 0x4, + DELAY_VALUE(RK3576, tx_delay, rx_delay)); +} + +static void dwmac_rk3576_set_rmii(struct dwmac_rk_priv *priv) +{ + rt_uint32_t offset_con; + + offset_con = (priv->id == 1) ? RK3576_GRF_GMAC_CON1 : RK3576_GRF_GMAC_CON0; + rt_syscon_write(priv->grf, offset_con, RK3576_GMAC_RMII_MODE); +} + +static rt_err_t dwmac_rk3576_fix_link_speed(struct dwmac_eth *eth, int speed) +{ + struct dwmac_rk_priv *priv = eth->plat_priv; + rt_uint32_t val = 0, offset_con; + + switch (speed) + { + case SPEED_10: + val = (eth->phy_interface == RT_PHY_INTERFACE_MODE_RMII) ? + RK3576_GMAC_CLK_RMII_DIV20 : RK3576_GMAC_CLK_RGMII_DIV50; + break; + case SPEED_100: + val = (eth->phy_interface == RT_PHY_INTERFACE_MODE_RMII) ? + RK3576_GMAC_CLK_RMII_DIV2 : RK3576_GMAC_CLK_RGMII_DIV5; + break; + case SPEED_1000: + if (eth->phy_interface == RT_PHY_INTERFACE_MODE_RMII) + { + return -RT_EINVAL; + } + val = RK3576_GMAC_CLK_RGMII_DIV1; + break; + default: + return -RT_EINVAL; + } + + offset_con = (priv->id == 1) ? RK3576_GRF_GMAC_CON1 : RK3576_GRF_GMAC_CON0; + rt_syscon_write(priv->grf, offset_con, val); + + return RT_EOK; +} + +static void dwmac_rk3576_clock_selection(struct dwmac_rk_priv *priv, + rt_bool_t input, rt_bool_t enable) +{ + rt_uint32_t val, offset_con; + + val = input ? RK3576_GMAC_CLK_SELET_IO : RK3576_GMAC_CLK_SELET_CRU; + val |= enable ? RK3576_GMAC_CLK_RMII_NOGATE : RK3576_GMAC_CLK_RMII_GATE; + + offset_con = (priv->id == 1) ? RK3576_GRF_GMAC_CON1 : RK3576_GRF_GMAC_CON0; + rt_syscon_write(priv->grf, offset_con, val); +} + +static const struct dwmac_rk_soc dwmac_rk3576_soc = +{ + .set_rgmii = dwmac_rk3576_set_rgmii, + .set_rmii = dwmac_rk3576_set_rmii, + .fix_link_speed = dwmac_rk3576_fix_link_speed, + .clock_selection = dwmac_rk3576_clock_selection, + .need_php_grf = RT_TRUE, +}; + +/* RK3588 */ +#define RK3588_GRF_GMAC_CON7 0x031c +#define RK3588_GRF_GMAC_CON8 0x0320 +#define RK3588_GRF_GMAC_CON9 0x0324 +#define RK3588_GRF_GMAC_CON0 0x0008 +#define RK3588_GRF_CLK_CON1 0x0070 + +#define RK3588_GMAC_RXCLK_DLY_ENABLE(id) GRF_BIT(2 * (id) + 3) +#define RK3588_GMAC_RXCLK_DLY_DISABLE(id) GRF_CLR_BIT(2 * (id) + 3) +#define RK3588_GMAC_TXCLK_DLY_ENABLE(id) GRF_BIT(2 * (id) + 2) +#define RK3588_GMAC_TXCLK_DLY_DISABLE(id) GRF_CLR_BIT(2 * (id) + 2) +#define RK3588_GMAC_CLK_RX_DL_CFG(val) HIWORD_UPDATE(val, 0xFF, 8) +#define RK3588_GMAC_CLK_TX_DL_CFG(val) HIWORD_UPDATE(val, 0xFF, 0) + +#define RK3588_GMAC_PHY_INTF_SEL_RGMII(id) \ + (GRF_BIT(3 + (id) * 6) | GRF_CLR_BIT(4 + (id) * 6) | GRF_CLR_BIT(5 + (id) * 6)) +#define RK3588_GMAC_PHY_INTF_SEL_RMII(id) \ + (GRF_CLR_BIT(3 + (id) * 6) | GRF_CLR_BIT(4 + (id) * 6) | GRF_BIT(5 + (id) * 6)) +#define RK3588_GMAC_CLK_RMII_MODE(id) GRF_BIT(5 * (id)) +#define RK3588_GMAC_CLK_RGMII_MODE(id) GRF_CLR_BIT(5 * (id)) +#define RK3588_GMAC_CLK_SELET_CRU(id) GRF_BIT(5 * (id) + 4) +#define RK3588_GMAC_CLK_SELET_IO(id) GRF_CLR_BIT(5 * (id) + 4) +#define RK3588_GMA_CLK_RMII_DIV2(id) GRF_BIT(5 * (id) + 2) +#define RK3588_GMA_CLK_RMII_DIV20(id) GRF_CLR_BIT(5 * (id) + 2) +#define RK3588_GMAC_CLK_RGMII_DIV1(id) \ + (GRF_CLR_BIT(5 * (id) + 2) | GRF_CLR_BIT(5 * (id) + 3)) +#define RK3588_GMAC_CLK_RGMII_DIV5(id) \ + (GRF_BIT(5 * (id) + 2) | GRF_BIT(5 * (id) + 3)) +#define RK3588_GMAC_CLK_RGMII_DIV50(id) \ + (GRF_BIT(5 * (id) + 2) | GRF_CLR_BIT(5 * (id) + 3)) +#define RK3588_GMAC_CLK_RMII_GATE(id) GRF_BIT(5 * (id) + 1) +#define RK3588_GMAC_CLK_RMII_NOGATE(id) GRF_CLR_BIT(5 * (id) + 1) + +static void dwmac_rk3588_set_rgmii(struct dwmac_rk_priv *priv, + int tx_delay, int rx_delay) +{ + rt_uint32_t offset_con; + int id = priv->id; + + offset_con = (id == 1) ? RK3588_GRF_GMAC_CON9 : RK3588_GRF_GMAC_CON8; + + rt_syscon_write(priv->php_grf, RK3588_GRF_GMAC_CON0, + RK3588_GMAC_PHY_INTF_SEL_RGMII(id)); + rt_syscon_write(priv->php_grf, RK3588_GRF_CLK_CON1, + RK3588_GMAC_CLK_RGMII_MODE(id)); + rt_syscon_write(priv->grf, RK3588_GRF_GMAC_CON7, + DELAY_ENABLE_BY_ID(RK3588, tx_delay, rx_delay, id)); + rt_syscon_write(priv->grf, offset_con, + DELAY_VALUE(RK3588, tx_delay, rx_delay)); +} + +static void dwmac_rk3588_set_rmii(struct dwmac_rk_priv *priv) +{ + int id = priv->id; + + rt_syscon_write(priv->php_grf, RK3588_GRF_GMAC_CON0, + RK3588_GMAC_PHY_INTF_SEL_RMII(id)); + rt_syscon_write(priv->php_grf, RK3588_GRF_CLK_CON1, + RK3588_GMAC_CLK_RMII_MODE(id)); +} + +static rt_err_t dwmac_rk3588_fix_link_speed(struct dwmac_eth *eth, int speed) +{ + struct dwmac_rk_priv *priv = eth->plat_priv; + rt_uint32_t val = 0; + int id = priv->id; + + switch (speed) + { + case SPEED_10: + val = (eth->phy_interface == RT_PHY_INTERFACE_MODE_RMII) ? + RK3588_GMA_CLK_RMII_DIV20(id) : RK3588_GMAC_CLK_RGMII_DIV50(id); + break; + case SPEED_100: + val = (eth->phy_interface == RT_PHY_INTERFACE_MODE_RMII) ? + RK3588_GMA_CLK_RMII_DIV2(id) : RK3588_GMAC_CLK_RGMII_DIV5(id); + break; + case SPEED_1000: + if (eth->phy_interface == RT_PHY_INTERFACE_MODE_RMII) + { + return -RT_EINVAL; + } + val = RK3588_GMAC_CLK_RGMII_DIV1(id); + break; + default: + return -RT_EINVAL; + } + + rt_syscon_write(priv->php_grf, RK3588_GRF_CLK_CON1, val); + + return RT_EOK; +} + +static void dwmac_rk3588_clock_selection(struct dwmac_rk_priv *priv, + rt_bool_t input, rt_bool_t enable) +{ + rt_uint32_t val; + int id = priv->id; + + val = input ? RK3588_GMAC_CLK_SELET_IO(id) : RK3588_GMAC_CLK_SELET_CRU(id); + val |= enable ? RK3588_GMAC_CLK_RMII_NOGATE(id) : RK3588_GMAC_CLK_RMII_GATE(id); + rt_syscon_write(priv->php_grf, RK3588_GRF_CLK_CON1, val); +} + +static const struct dwmac_rk_soc dwmac_rk3588_soc = +{ + .set_rgmii = dwmac_rk3588_set_rgmii, + .set_rmii = dwmac_rk3588_set_rmii, + .fix_link_speed = dwmac_rk3588_fix_link_speed, + .clock_selection = dwmac_rk3588_clock_selection, + .need_php_grf = RT_TRUE, +}; + +static rt_err_t dwmac_rk_parse_ofw(struct dwmac_eth *eth, + const struct dwmac_rk_soc *soc) +{ + rt_err_t err; + + err = dwmac_rk_parse_common(eth, soc); + if (err) + { + return err; + } + + switch (eth->phy_interface) + { + 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: + if (!rt_is_err_or_null(eth->mac_clk_rx)) + { + rt_clk_put(eth->mac_clk_rx); + eth->mac_clk_rx = RT_NULL; + } + if (!rt_is_err_or_null(eth->clk_mac_refout)) + { + rt_clk_put(eth->clk_mac_refout); + eth->clk_mac_refout = RT_NULL; + } + break; + default: + break; + } + + return RT_EOK; +} + +static void dwmac_rk_setup_interface(struct dwmac_eth *eth) +{ + struct dwmac_rk_priv *priv = eth->plat_priv; + const struct dwmac_rk_soc *soc = priv->soc; + + switch (eth->phy_interface) + { + case RT_PHY_INTERFACE_MODE_RGMII: + if (soc->set_rgmii) + { + soc->set_rgmii(priv, priv->tx_delay, priv->rx_delay); + } + break; + case RT_PHY_INTERFACE_MODE_RGMII_ID: + if (soc->set_rgmii) + { + soc->set_rgmii(priv, -1, -1); + } + break; + case RT_PHY_INTERFACE_MODE_RGMII_RXID: + if (soc->set_rgmii) + { + soc->set_rgmii(priv, priv->tx_delay, -1); + } + break; + case RT_PHY_INTERFACE_MODE_RGMII_TXID: + if (soc->set_rgmii) + { + soc->set_rgmii(priv, -1, priv->rx_delay); + } + break; + case RT_PHY_INTERFACE_MODE_RMII: + if (soc->set_rmii) + { + soc->set_rmii(priv); + } + if (soc->clock_selection) + { + soc->clock_selection(priv, priv->clock_input, RT_TRUE); + } + else if (!priv->clock_input && !rt_is_err_or_null(eth->mac_clk_speed)) + { + rt_clk_set_rate(eth->mac_clk_speed, 50000000); + } + break; + default: + LOG_W("unsupported phy-mode %d, assume RGMII", eth->phy_interface); + if (soc->set_rgmii) + { + soc->set_rgmii(priv, priv->tx_delay, priv->rx_delay); + } + break; + } +} + +static rt_err_t dwmac_rk_init(struct dwmac_eth *eth) +{ + struct dwmac_rk_priv *priv = eth->plat_priv; + rt_err_t err; + + if (!priv || rt_is_err_or_null(priv->grf) || !priv->soc) + { + return -RT_EIO; + } + + err = dwmac_rk_clk_prepare_enable(priv->clk_phy); + if (err) + { + return err; + } + if ((err = dwmac_rk_clk_prepare_enable(priv->pclk_xpcs))) + { + goto _fail_clk_phy; + } + if ((err = dwmac_rk_clk_prepare_enable(priv->clk_xpcs_eee))) + { + goto _fail_pclk_xpcs; + } + + dwmac_rk_setup_interface(eth); + + return RT_EOK; + +_fail_pclk_xpcs: + dwmac_rk_clk_disable_unprepare(priv->pclk_xpcs); +_fail_clk_phy: + dwmac_rk_clk_disable_unprepare(priv->clk_phy); + + return err; +} + +static rt_err_t dwmac_rk_fix_link_speed(struct dwmac_eth *eth, int speed) +{ + struct dwmac_rk_priv *priv = eth->plat_priv; + + if (priv && priv->soc && priv->soc->fix_link_speed) + { + return priv->soc->fix_link_speed(eth, speed); + } + + return dwmac_rk_clk_set_rate(eth, dwmac_rgmii_clock(speed)); +} + +static void dwmac_rk_exit(struct dwmac_eth *eth) +{ + struct dwmac_rk_priv *priv = eth->plat_priv; + + if (priv) + { + dwmac_rk_clk_disable_unprepare(priv->clk_xpcs_eee); + dwmac_rk_clk_disable_unprepare(priv->pclk_xpcs); + dwmac_rk_clk_disable_unprepare(priv->clk_phy); + if (!rt_is_err_or_null(priv->clk_xpcs_eee)) + { + rt_clk_put(priv->clk_xpcs_eee); + } + if (!rt_is_err_or_null(priv->pclk_xpcs)) + { + rt_clk_put(priv->pclk_xpcs); + } + if (!rt_is_err_or_null(priv->clk_phy)) + { + rt_clk_put(priv->clk_phy); + } + } + + rt_free(priv); + eth->plat_priv = RT_NULL; +} + +#define DWMAC_RK_DEFINE(soc_name) \ + static rt_err_t dwmac_##soc_name##_parse_ofw(struct dwmac_eth *eth) \ + { \ + return dwmac_rk_parse_ofw(eth, &dwmac_##soc_name##_soc); \ + } \ + static const struct dwmac_plat_ops dwmac_##soc_name##_plat_ops = \ + { \ + .parse_ofw = dwmac_##soc_name##_parse_ofw, \ + .init = dwmac_rk_init, \ + .exit = dwmac_rk_exit, \ + .fix_link_speed = dwmac_rk_fix_link_speed, \ + }; \ + static const struct dwmac_config dwmac_##soc_name##_config = \ + { \ + .core_type = DWMAC_CORE_GMAC4, \ + .caps = DWMAC_CAP_TSO | DWMAC_CAP_PTP, \ + .dma_pbl = DWMAC_DMA_PBL, \ + .plat = &dwmac_##soc_name##_plat_ops, \ + }; + +DWMAC_RK_DEFINE(rk3308) +DWMAC_RK_DEFINE(rk3528) +DWMAC_RK_DEFINE(rk3568) +DWMAC_RK_DEFINE(rk3576) +DWMAC_RK_DEFINE(rk3588) + +#undef DWMAC_RK_DEFINE + +static const struct rt_ofw_node_id dwmac_rockchip_ofw_ids[] = +{ + { .compatible = "rockchip,rk3308-mac", .data = &dwmac_rk3308_config }, + { .compatible = "rockchip,rk3528-gmac", .data = &dwmac_rk3528_config }, + { .compatible = "rockchip,rk3568-gmac", .data = &dwmac_rk3568_config }, + { .compatible = "rockchip,rk3576-gmac", .data = &dwmac_rk3576_config }, + { .compatible = "rockchip,rk3588-gmac", .data = &dwmac_rk3588_config }, + { /* sentinel */ } +}; + +static void dwmac_rockchip_hw_stop(struct dwmac_eth *eth) +{ + rt_uint32_t val; + + if (!eth || !eth->mac_base) + { + return; + } + + val = dwmac_readl(eth, GMAC_CONFIG); + dwmac_writel(eth, GMAC_CONFIG, val & ~(GMAC_CONFIG_TE | GMAC_CONFIG_RE)); + + val = dwmac_readl(eth, DMA_CHAN_TX_CONTROL(DWMAC_CHAN)); + dwmac_writel(eth, DMA_CHAN_TX_CONTROL(DWMAC_CHAN), val & ~DMA_CONTROL_ST); + + val = dwmac_readl(eth, DMA_CHAN_RX_CONTROL(DWMAC_CHAN)); + dwmac_writel(eth, DMA_CHAN_RX_CONTROL(DWMAC_CHAN), val & ~DMA_CONTROL_SR); + + dwmac_writel(eth, DMA_CHAN_INTR_ENA(DWMAC_CHAN), 0); + dwmac_writel(eth, DMA_CHAN_STATUS(DWMAC_CHAN), 0xffffffff); + rt_hw_us_delay(100); +} + +static rt_err_t dwmac_rockchip_probe(struct rt_platform_device *pdev) +{ + const struct dwmac_config *cfg = pdev->id->data; + + if (!cfg) + { + return -RT_EINVAL; + } + + return dwmac_platform_register(pdev, cfg); +} + +static rt_err_t dwmac_rockchip_remove(struct rt_platform_device *pdev) +{ + return dwmac_platform_remove(pdev); +} + +static rt_err_t dwmac_rockchip_shutdown(struct rt_platform_device *pdev) +{ + dwmac_rockchip_hw_stop(pdev->parent.user_data); + + return dwmac_platform_remove(pdev); +} + +static struct rt_platform_driver dwmac_rockchip_driver = +{ + .name = "dwmac-rockchip", + .ids = dwmac_rockchip_ofw_ids, + .probe = dwmac_rockchip_probe, + .remove = dwmac_rockchip_remove, + .shutdown = dwmac_rockchip_shutdown, +}; + +RT_PLATFORM_DRIVER_EXPORT(dwmac_rockchip_driver); diff --git a/bsp/rockchip/dm/graphic/SConscript b/bsp/rockchip/dm/graphic/SConscript new file mode 100755 index 000000000000..3d15055d62d2 --- /dev/null +++ b/bsp/rockchip/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/rockchip/dm/graphic/framebuffer/Kconfig b/bsp/rockchip/dm/graphic/framebuffer/Kconfig new file mode 100755 index 000000000000..ae856f8d0b9e --- /dev/null +++ b/bsp/rockchip/dm/graphic/framebuffer/Kconfig @@ -0,0 +1,94 @@ +config RT_GRAPHIC_FB_VOP2 + bool "Rockchip VOP2 framebuffer" + depends on RT_USING_GRAPHIC + depends on RT_USING_CLK + default n + help + Rockchip VOP2 display driver with primary, overlay and cursor planes. + Supported compatibles: rk3568, rk3588, rk3528, rk3562, rk3576 (rockchip,rk3576-vop). + + Requires connector output initialized by boot loader unless a full + display pipeline is added later. + + Device tree optional properties on the vop node: + rockchip,fb-width / rockchip,fb-height + rockchip,active-vp + +config RT_GRAPHIC_FB_VOPL + bool "Rockchip VOPL framebuffer (rk3576-vop-lit)" + depends on RT_USING_GRAPHIC + depends on RT_USING_CLK + depends on RT_GRAPHIC_DISPLAY_ROCKCHIP + default n + help + Lite VOP on RK3576 (EBC block, single primary plane, DSI/RGB/eDP/HDMI). + +config RT_GRAPHIC_FB_VOP1 + bool "Rockchip VOP1 framebuffer" + depends on RT_USING_GRAPHIC + depends on RT_USING_CLK + default n + help + Rockchip legacy VOP display driver (Lite and Big variants). + + Lite: rk3308, rk3506, px30-vop-lit (primary + cursor). + Big: rk3328, rk3288, rk3399, rk3368, rv1126/rv1126b, etc. + (primary + overlay + cursor). + + Device tree optional properties: + rockchip,fb-width / rockchip,fb-height + +config RT_GRAPHIC_DISPLAY_ROCKCHIP + bool "Rockchip display subsystem (route + pipeline)" + depends on RT_USING_GRAPHIC + depends on RT_USING_OFW + default n + help + Parse display-subsystem routes and enable VOP + connector + panel. + + The rockchip.display= boot argument selects the active route: + auto - enable connected outputs, then fixed panels on unused VPs + hdmi - force the HDMI route + dsi0 - force the DSI0 route + dsi1 - force the DSI1 route + extend - enable independent framebuffers on all usable routes + mirror - deprecated alias for extend + +config RT_GRAPHIC_CONNECTOR_DSI + bool "Rockchip DW MIPI DSI connector (DSI1)" + depends on RT_GRAPHIC_DISPLAY_ROCKCHIP + default y + +config RT_GRAPHIC_CONNECTOR_DSI2 + bool "Rockchip DW MIPI DSI2 connector (rk3576)" + depends on RT_GRAPHIC_DISPLAY_ROCKCHIP + depends on RT_PHYE_ROCKCHIP_MIPI_DCPHY + default y + +config RT_GRAPHIC_CONNECTOR_HDMI + bool "Rockchip DW HDMI connector" + depends on RT_GRAPHIC_DISPLAY_ROCKCHIP + depends on RT_USING_CLK + default y + +config RT_GRAPHIC_BACKLIGHT_HINT + bool "Enable backlight Kconfig hint" + depends on RT_GRAPHIC_DISPLAY_ROCKCHIP + default y + help + Panel backlight needs RT_GRAPHIC_BACKLIGHT + RT_GRAPHIC_BACKLIGHT_PWM + and a pwm-backlight node in device tree. + +config RT_GRAPHIC_PANEL_SIMPLE + bool "Simple panel driver" + depends on RT_GRAPHIC_DISPLAY_ROCKCHIP + default y + +config RT_GRAPHIC_INPUT_TOUCH_HINT + bool "Enable touch hint in graphic Kconfig" + depends on RT_GRAPHIC_DISPLAY_ROCKCHIP + default y + help + MIPI DSI panels with touch need a separate I2C touch driver + (e.g. RT_INPUT_TOUCHSCREEN_GOODIX for GT911). Enable it under + RT-Thread Components -> Input device drivers -> Touchscreen. diff --git a/bsp/rockchip/dm/graphic/framebuffer/SConscript b/bsp/rockchip/dm/graphic/framebuffer/SConscript new file mode 100755 index 000000000000..4d40b80218a2 --- /dev/null +++ b/bsp/rockchip/dm/graphic/framebuffer/SConscript @@ -0,0 +1,35 @@ +from building import * + +group = [] +src = [] +cwd = GetCurrentDir() +CPPPATH = [cwd] + +if GetDepend(['RT_GRAPHIC_FB_VOP2']): + src += ['fb-vop2.c', 'fb-vop2-vp.c'] + +if GetDepend(['RT_GRAPHIC_FB_VOP1']): + src += ['fb-vop1.c'] + +if GetDepend(['RT_GRAPHIC_FB_VOPL']): + src += ['fb-vopl.c'] + +if GetDepend(['RT_GRAPHIC_DISPLAY_ROCKCHIP']): + src += ['display-timing.c', 'display-route.c', 'display-rockchip.c'] + +if GetDepend(['RT_GRAPHIC_CONNECTOR_DSI']): + src += ['dsi-rockchip.c'] + +if GetDepend(['RT_GRAPHIC_CONNECTOR_DSI2']): + src += ['dsi2-rockchip.c'] + +if GetDepend(['RT_GRAPHIC_CONNECTOR_HDMI']): + src += ['hdmi-rockchip.c'] + +if GetDepend(['RT_GRAPHIC_PANEL_SIMPLE']): + src += ['panel-simple.c'] + +if src: + group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/rockchip/dm/graphic/framebuffer/display-rockchip.c b/bsp/rockchip/dm/graphic/framebuffer/display-rockchip.c new file mode 100644 index 000000000000..270889a839db --- /dev/null +++ b/bsp/rockchip/dm/graphic/framebuffer/display-rockchip.c @@ -0,0 +1,741 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-09-23 GuEe-GUI first version + */ + +#include "rockchip-display.h" + +#define DBG_TAG "display.rk" +#define DBG_LVL DBG_INFO +#include + +struct rockchip_display_entity +{ + struct rt_ofw_node *np; + const struct rockchip_crtc_ops *crtc_ops; + const struct rockchip_connector_ops *conn_ops; + const struct rockchip_panel_ops *panel_ops; + void *priv; + struct rockchip_display_entity *next; +}; + +static struct rockchip_display_entity *crtc_list; +static struct rockchip_display_entity *conn_list; +static struct rockchip_display_entity *panel_list; + +static const char *display_node_name(struct rt_ofw_node *np) +{ + return np ? rt_ofw_node_full_name(np) : ""; +} + +static rt_bool_t display_is_legacy_hdmi(struct rt_ofw_node *np) +{ + if (!np) + { + return RT_FALSE; + } + + return rt_ofw_node_is_compatible(np, "rockchip,rk3568-dw-hdmi") || + rt_ofw_node_is_compatible(np, "rockchip,rk3528-dw-hdmi"); +} + +static rt_bool_t display_try_fallback_timing(const struct display_route *route, + struct display_timing *tim) +{ + if (!route || !tim || !display_is_legacy_hdmi(route->connector_np)) + { + return RT_FALSE; + } + + rt_memset(tim, 0, sizeof(*tim)); + tim->pixelclock = 74250000; + tim->hactive = 1280; + tim->hfront_porch = 110; + tim->hsync_len = 40; + tim->hback_porch = 220; + tim->vactive = 720; + tim->vfront_porch = 5; + tim->vsync_len = 5; + tim->vback_porch = 20; + tim->flags = DISPLAY_TIMING_F_PHSYNC | DISPLAY_TIMING_F_PVSYNC; + display_timing_derive(tim); + + return RT_TRUE; +} + +static rt_bool_t display_enable_connector_after_crtc(const struct display_route *route) +{ + RT_UNUSED(route); + + /* + * Keep the standard DRM/U-Boot order: let the CRTC start driving a + * stable mode first, then enable the connector/PHY. + */ + return RT_TRUE; +} + +static struct rockchip_display_entity *display_entity_find(struct rockchip_display_entity *head, + struct rt_ofw_node *np) +{ + while (head) + { + if (head->np == np) + { + return head; + } + + head = head->next; + } + + return RT_NULL; +} + +static rt_err_t display_entity_add(struct rockchip_display_entity **head, + struct rt_ofw_node *np, void *priv, + const struct rockchip_crtc_ops *crtc_ops, + const struct rockchip_connector_ops *conn_ops, + const struct rockchip_panel_ops *panel_ops) +{ + struct rockchip_display_entity *ent; + + if (display_entity_find(*head, np)) + { + LOG_D("display entity %s already registered", display_node_name(np)); + return RT_EOK; + } + + ent = rt_calloc(1, sizeof(*ent)); + + if (!ent) + { + return -RT_ENOMEM; + } + + ent->np = np; + ent->priv = priv; + ent->crtc_ops = crtc_ops; + ent->conn_ops = conn_ops; + ent->panel_ops = panel_ops; + ent->next = *head; + *head = ent; + + return RT_EOK; +} + +rt_err_t rockchip_display_register_crtc(struct rt_ofw_node *np, + const struct rockchip_crtc_ops *ops, void *priv) +{ + LOG_D("register crtc %s", display_node_name(np)); + return display_entity_add(&crtc_list, np, priv, ops, RT_NULL, RT_NULL); +} + +rt_err_t rockchip_display_register_connector(struct rt_ofw_node *np, + const struct rockchip_connector_ops *ops, void *priv) +{ + LOG_D("register connector %s", display_node_name(np)); + return display_entity_add(&conn_list, np, priv, RT_NULL, ops, RT_NULL); +} + +rt_err_t rockchip_display_register_panel(struct rt_ofw_node *np, + const struct rockchip_panel_ops *ops, void *priv) +{ + LOG_D("register panel %s", display_node_name(np)); + return display_entity_add(&panel_list, np, priv, RT_NULL, RT_NULL, ops); +} + +rt_err_t rockchip_display_route_enable(struct rt_ofw_node *route_np) +{ + rt_err_t err; + struct display_route route; + struct display_timing tim; + struct rockchip_display_entity *crtc, *conn, *panel; + rt_bool_t conn_prepared = RT_FALSE; + rt_bool_t panel_prepared = RT_FALSE; + rt_bool_t panel_enabled = RT_FALSE; + rt_bool_t conn_enabled = RT_FALSE; + rt_bool_t crtc_configured = RT_FALSE; + rt_bool_t crtc_enabled = RT_FALSE; + + if ((err = display_route_resolve(route_np, &route))) + { + LOG_W("route %s: resolve failed: %s", display_node_name(route_np), rt_strerror(err)); + return err; + } + + crtc = display_entity_find(crtc_list, route.vop_np); + conn = display_entity_find(conn_list, route.connector_np); + panel = route.panel_np ? display_entity_find(panel_list, route.panel_np) : RT_NULL; + + LOG_D("route %s: crtc=%s connector=%s panel=%s", + display_node_name(route_np), + crtc ? "yes" : "no", + conn ? "yes" : "no", + panel ? "yes" : "no"); + + if (!crtc || !crtc->crtc_ops) + { + LOG_W("route %s: no crtc driver for %s", + display_node_name(route_np), display_node_name(route.vop_np)); + return -RT_ENOSYS; + } + + if (!conn || !conn->conn_ops) + { + LOG_W("route %s: no connector driver for %s", + display_node_name(route_np), display_node_name(route.connector_np)); + return -RT_ENOSYS; + } + + if (route.panel_np && !panel) + { + LOG_W("route %s: panel node %s present but no panel driver", + display_node_name(route_np), display_node_name(route.panel_np)); + return -RT_ENOSYS; + } + + rt_memset(&tim, 0, sizeof(tim)); + + if (panel && panel->panel_ops && panel->panel_ops->get_timing) + { + LOG_D("route %s: timing from panel driver %s", + display_node_name(route_np), display_node_name(route.panel_np)); + panel->panel_ops->get_timing(panel->priv, &tim); + } + else if (route.panel_np) + { + LOG_D("route %s: timing from panel dt %s", + display_node_name(route_np), display_node_name(route.panel_np)); + display_timing_parse(route.panel_np, &tim); + } + else + { + LOG_D("route %s: no panel timing source", display_node_name(route_np)); + } + + if (!tim.hactive || !tim.vactive) + { + if (display_try_fallback_timing(&route, &tim)) + { + LOG_D("route %s: fallback timing 1280x720p60 for %s", + display_node_name(route_np), + display_node_name(route.connector_np)); + } + else + { + LOG_W("route %s: invalid timing hactive=%u vactive=%u connector=%s panel=%s", + display_node_name(route_np), tim.hactive, tim.vactive, + display_node_name(route.connector_np), + display_node_name(route.panel_np)); + return -RT_EINVAL; + } + } + + if (conn && conn->conn_ops && conn->conn_ops->prepare) + { + if ((err = conn->conn_ops->prepare(conn->priv, route.vp_id, &tim))) + { + LOG_W("route %s: connector prepare failed: %s", + display_node_name(route_np), rt_strerror(err)); + return err; + } + conn_prepared = RT_TRUE; + } + + if (panel && panel->panel_ops && panel->panel_ops->prepare) + { + if ((err = panel->panel_ops->prepare(panel->priv))) + { + LOG_W("route %s: panel prepare failed: %s", + display_node_name(route_np), rt_strerror(err)); + goto _fail_enable; + } + panel_prepared = RT_TRUE; + } + + if (panel && panel->panel_ops && panel->panel_ops->run_init && + conn && conn->conn_ops && conn->conn_ops->transfer) + { + if ((err = panel->panel_ops->run_init(panel->priv, conn->conn_ops, conn->priv))) + { + LOG_W("route %s: panel init failed: %d", display_node_name(route_np), err); + goto _fail_enable; + } + } + + if (conn && conn->conn_ops && conn->conn_ops->mode_set) + { + if ((err = conn->conn_ops->mode_set(conn->priv, &tim))) + { + LOG_W("route %s: connector mode_set failed: %s", + display_node_name(route_np), rt_strerror(err)); + goto _fail_enable; + } + } + + if (crtc->crtc_ops->mode_set) + { + LOG_D("route %s: crtc mode_set %ux%u on vp%u", + display_node_name(route_np), tim.hactive, tim.vactive, route.vp_id); + if ((err = crtc->crtc_ops->mode_set(crtc->priv, &route, &tim))) + { + LOG_W("route %s: crtc mode_set failed: %s", + display_node_name(route_np), rt_strerror(err)); + goto _fail_enable; + } + crtc_configured = RT_TRUE; + } + + if (display_enable_connector_after_crtc(&route)) + { + if (crtc->crtc_ops->enable) + { + err = crtc->crtc_ops->enable(crtc->priv, route.vp_id, RT_TRUE); + if (err) + { + LOG_W("route %s: crtc enable failed: %s", + display_node_name(route_np), rt_strerror(err)); + goto _fail_enable; + } + crtc_enabled = RT_TRUE; + } + + if (conn && conn->conn_ops && conn->conn_ops->enable) + { + err = conn->conn_ops->enable(conn->priv, RT_TRUE); + if (err) + { + LOG_W("route %s: connector enable failed: %s", + display_node_name(route_np), rt_strerror(err)); + goto _fail_enable; + } + conn_enabled = RT_TRUE; + } + } + else + { + if (conn && conn->conn_ops && conn->conn_ops->enable) + { + err = conn->conn_ops->enable(conn->priv, RT_TRUE); + if (err) + { + LOG_W("route %s: connector enable failed: %s", + display_node_name(route_np), rt_strerror(err)); + goto _fail_enable; + } + conn_enabled = RT_TRUE; + } + + if (crtc->crtc_ops->enable) + { + err = crtc->crtc_ops->enable(crtc->priv, route.vp_id, RT_TRUE); + if (err) + { + LOG_W("route %s: crtc enable failed: %s", + display_node_name(route_np), rt_strerror(err)); + goto _fail_enable; + } + crtc_enabled = RT_TRUE; + } + } + + if (panel && panel->panel_ops && panel->panel_ops->enable) + { + err = panel->panel_ops->enable(panel->priv); + if (err) + { + LOG_W("route %s: panel enable failed: %s", + display_node_name(route_np), rt_strerror(err)); + goto _fail_enable; + } + panel_enabled = RT_TRUE; + } + + /* + * Registering fb0 renders the boot logo and may commit several planes. + * Keep those operations out of the hardware-enable phase: at this point + * the complete VOP -> connector -> panel chain is already transmitting. + */ + if (crtc->crtc_ops->complete) + { + err = crtc->crtc_ops->complete(crtc->priv, route.vp_id); + if (err) + { + LOG_W("route %s: crtc completion failed: %s", + display_node_name(route_np), rt_strerror(err)); + goto _fail_enable; + } + } + + LOG_I("route %s: vp%u %ux%u via %s", + display_node_name(route_np), route.vp_id, tim.hactive, tim.vactive, + display_node_name(route.connector_np)); + + return RT_EOK; + +_fail_enable: + if ((panel_prepared || panel_enabled) && panel && panel->panel_ops && + panel->panel_ops->disable) + { + panel->panel_ops->disable(panel->priv); + } + if ((conn_prepared || conn_enabled) && conn && conn->conn_ops && + conn->conn_ops->disable) + { + conn->conn_ops->disable(conn->priv); + } + if ((crtc_configured || crtc_enabled) && crtc->crtc_ops->enable) + { + crtc->crtc_ops->enable(crtc->priv, route.vp_id, RT_FALSE); + } + + return err; +} + +static struct rt_platform_device *display_pdev; + +enum display_route_scan_pass +{ + DISPLAY_ROUTE_CONNECTED, + DISPLAY_ROUTE_FIXED, + DISPLAY_ROUTE_FALLBACK, +}; + +enum display_route_policy +{ + DISPLAY_POLICY_AUTO, + DISPLAY_POLICY_HDMI, + DISPLAY_POLICY_DSI0, + DISPLAY_POLICY_DSI1, + DISPLAY_POLICY_EXTEND, + DISPLAY_POLICY_MIRROR, +}; + +static struct rockchip_display_entity *display_route_find_connector( + struct rt_ofw_node *route_np) +{ + struct rt_ofw_node *ep_np = RT_NULL; + struct rt_ofw_node *remote_np = RT_NULL; + struct rt_ofw_node *port_np = RT_NULL; + struct rt_ofw_node *parent_np = RT_NULL; + struct rt_ofw_node *connector_np = RT_NULL; + struct rockchip_display_entity *conn = RT_NULL; + + ep_np = rt_ofw_parse_phandle(route_np, "connect", 0); + if (!ep_np) + { + goto out; + } + + remote_np = rt_ofw_parse_phandle(ep_np, "remote-endpoint", 0); + if (!remote_np) + { + goto out; + } + + port_np = rt_ofw_get_parent(remote_np); + parent_np = rt_ofw_get_parent(port_np); + if (parent_np && rt_ofw_node_tag_equ(parent_np, "ports")) + { + connector_np = rt_ofw_get_parent(parent_np); + } + else + { + connector_np = parent_np; + parent_np = RT_NULL; + } + + conn = display_entity_find(conn_list, connector_np); + +out: + rt_ofw_node_put(connector_np); + rt_ofw_node_put(parent_np); + rt_ofw_node_put(port_np); + rt_ofw_node_put(remote_np); + rt_ofw_node_put(ep_np); + + return conn; +} + +static rt_err_t display_route_scan_vp_id(struct rt_ofw_node *route_np, + rt_uint32_t *vp_id) +{ + rt_err_t err = -RT_ENOENT; + struct rt_ofw_node *ep_np; + struct rt_ofw_node *port_np; + + ep_np = rt_ofw_parse_phandle(route_np, "connect", 0); + if (!ep_np) + { + return err; + } + + port_np = rt_ofw_get_parent(ep_np); + if (port_np) + { + err = display_route_get_vp_id(port_np, vp_id); + } + + rt_ofw_node_put(port_np); + rt_ofw_node_put(ep_np); + + return err; +} + +static rt_bool_t display_route_is_legacy_hdmi(struct rt_ofw_node *route_np) +{ + struct rockchip_display_entity *conn; + + conn = display_route_find_connector(route_np); + + return conn && display_is_legacy_hdmi(conn->np); +} + +static int display_route_dsi_id(struct rt_ofw_node *route_np) +{ + struct rockchip_display_entity *conn; + + conn = display_route_find_connector(route_np); + if (!conn || !conn->np || + (!rt_ofw_node_is_compatible(conn->np, "rockchip,rk3568-mipi-dsi") && + !rt_ofw_node_is_compatible(conn->np, "rockchip,rk3588-mipi-dsi"))) + { + return -1; + } + + return rt_ofw_get_alias_id(conn->np, "dsi"); +} + +static enum display_route_policy display_route_get_policy(void) +{ + const char *value = rt_ofw_bootargs_select("rockchip.display=", 0); + + if (!value || !value[0] || !rt_strcmp(value, "auto")) + { + return DISPLAY_POLICY_AUTO; + } + if (!rt_strcmp(value, "hdmi")) + { + return DISPLAY_POLICY_HDMI; + } + if (!rt_strcmp(value, "dsi0")) + { + return DISPLAY_POLICY_DSI0; + } + if (!rt_strcmp(value, "dsi1")) + { + return DISPLAY_POLICY_DSI1; + } + if (!rt_strcmp(value, "extend")) + { + return DISPLAY_POLICY_EXTEND; + } + if (!rt_strcmp(value, "mirror")) + { + return DISPLAY_POLICY_MIRROR; + } + + LOG_W("unknown rockchip.display=%s, use auto", value); + + return DISPLAY_POLICY_AUTO; +} + +static const char *display_route_policy_name(enum display_route_policy policy) +{ + switch (policy) + { + case DISPLAY_POLICY_HDMI: + return "hdmi"; + case DISPLAY_POLICY_DSI0: + return "dsi0"; + case DISPLAY_POLICY_DSI1: + return "dsi1"; + case DISPLAY_POLICY_EXTEND: + return "extend"; + case DISPLAY_POLICY_MIRROR: + return "mirror"; + case DISPLAY_POLICY_AUTO: + default: + return "auto"; + } +} + +static rt_bool_t display_route_policy_allows(struct rt_ofw_node *route_np, + enum display_route_policy policy) +{ + switch (policy) + { + case DISPLAY_POLICY_HDMI: + return display_route_is_legacy_hdmi(route_np); + case DISPLAY_POLICY_DSI0: + return display_route_dsi_id(route_np) == 0; + case DISPLAY_POLICY_DSI1: + return display_route_dsi_id(route_np) == 1; + case DISPLAY_POLICY_AUTO: + case DISPLAY_POLICY_EXTEND: + case DISPLAY_POLICY_MIRROR: + default: + return RT_TRUE; + } +} + +static rt_bool_t display_route_matches(struct rt_ofw_node *route_np, + enum display_route_scan_pass pass) +{ + rt_err_t err; + rt_bool_t connected; + struct rockchip_display_entity *conn; + + conn = display_route_find_connector(route_np); + if (!conn || !conn->conn_ops || !conn->conn_ops->detect) + { + return pass == DISPLAY_ROUTE_FIXED; + } + + if (pass == DISPLAY_ROUTE_FIXED) + { + return RT_FALSE; + } + + err = conn->conn_ops->detect(conn->priv, &connected); + if (err) + { + LOG_D("route %s: connector detect failed: %s", + display_node_name(route_np), rt_strerror(err)); + return pass == DISPLAY_ROUTE_FALLBACK; + } + + LOG_D("route %s: connector is %s", + display_node_name(route_np), connected ? "connected" : "disconnected"); + + return connected ? pass == DISPLAY_ROUTE_CONNECTED : + pass == DISPLAY_ROUTE_FALLBACK; +} + +static rt_uint32_t display_enable_routes(void) +{ + rt_err_t err; + rt_uint32_t vp_id; + rt_uint32_t enabled_vps = 0; + rt_uint32_t enabled_count = 0; + enum display_route_policy policy; + enum display_route_scan_pass pass; + struct rt_ofw_node *route_np, *child; + struct rt_device *dev; + + if (!display_pdev) + { + LOG_W("display-subsystem route init: device not ready"); + return 0; + } + + dev = &display_pdev->parent; + route_np = rt_ofw_get_child_by_tag(dev->ofw_node, "route"); + + if (!route_np) + { + LOG_W("display-subsystem route init: no route node"); + return 0; + } + + LOG_D("display-subsystem route init: scan routes"); + policy = display_route_get_policy(); + LOG_I("display policy: %s", display_route_policy_name(policy)); + + /* + * Connected hot-plug outputs are enabled first so they receive fb0. + * Fixed panels are then enabled on any remaining VP and receive fb1+. + * Explicit single-output policies still filter the route list above. + */ + for (pass = DISPLAY_ROUTE_CONNECTED; pass <= DISPLAY_ROUTE_FALLBACK; ++pass) + { + if (pass == DISPLAY_ROUTE_FALLBACK && enabled_count) + { + break; + } + rt_ofw_foreach_child_node(route_np, child) + { + if (!rt_ofw_node_is_available(child)) + { + LOG_D("route %s: disabled, skip", display_node_name(child)); + continue; + } + + if (!display_route_policy_allows(child, policy)) + { + continue; + } + + if (!display_route_matches(child, pass)) + { + continue; + } + + if (display_route_scan_vp_id(child, &vp_id)) + { + LOG_D("route %s: cannot resolve VP, skip", display_node_name(child)); + continue; + } + + if (vp_id >= 32 || (enabled_vps & RT_BIT(vp_id))) + { + LOG_D("route %s: vp%u already active, skip", + display_node_name(child), vp_id); + continue; + } + + LOG_D("route %s: enabling", display_node_name(child)); + err = rockchip_display_route_enable(child); + + if (err) + { + LOG_W("route %s: enable failed: %s", + display_node_name(child), rt_strerror(err)); + } + else + { + enabled_vps |= RT_BIT(vp_id); + enabled_count++; + } + } + } + + return enabled_count; +} + +static rt_err_t display_subsys_probe(struct rt_platform_device *pdev) +{ + display_pdev = pdev; + LOG_D("display-subsystem probed"); + return RT_EOK; +} + +static int rockchip_display_routes_init(void) +{ + /* + * DSI retries deferred probing at component level 4. Enable every display + * policy afterwards, but before environment level 5 can wait for rootfs. + */ + display_enable_routes(); + + return 0; +} +INIT_EXPORT(rockchip_display_routes_init, "4.1"); + +static const struct rt_ofw_node_id display_subsys_ids[] = +{ + { .compatible = "rockchip,display-subsystem" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver display_subsys_driver = +{ + .name = "rockchip-display", + .ids = display_subsys_ids, + .probe = display_subsys_probe, +}; +RT_PLATFORM_DRIVER_EXPORT(display_subsys_driver); diff --git a/bsp/rockchip/dm/graphic/framebuffer/display-route.c b/bsp/rockchip/dm/graphic/framebuffer/display-route.c new file mode 100644 index 000000000000..193378718caf --- /dev/null +++ b/bsp/rockchip/dm/graphic/framebuffer/display-route.c @@ -0,0 +1,205 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-09-23 GuEe-GUI first version + */ + +#include "rockchip-display.h" + +#define DBG_TAG "display.route" +#define DBG_LVL DBG_INFO +#include + +static const char *display_route_node_name(struct rt_ofw_node *np) +{ + return np ? rt_ofw_node_full_name(np) : ""; +} + +static struct rt_ofw_node *display_graph_remote(struct rt_ofw_node *ep_np) +{ + return rt_ofw_parse_phandle(ep_np, "remote-endpoint", 0); +} + +static struct rt_ofw_node *display_graph_device_from_ep(struct rt_ofw_node *ep_np, + struct rt_ofw_node **out_port_np) +{ + struct rt_ofw_node *port_np, *dev_np; + + port_np = rt_ofw_get_parent(ep_np); + + if (out_port_np) + { + *out_port_np = port_np; + } + + if (!port_np) + { + return RT_NULL; + } + + dev_np = rt_ofw_get_parent(port_np); + + if (dev_np && rt_ofw_node_tag_equ(dev_np, "ports")) + { + dev_np = rt_ofw_get_parent(dev_np); + } + + return dev_np; +} + +static struct rt_ofw_node *display_graph_find_sink(struct rt_ofw_node *connector_np, + struct rt_ofw_node *source_np) +{ + struct rt_ofw_node *child, *ports_np = RT_NULL; + struct rt_ofw_node *port_np, *ep_np, *remote_ep, *sink_np; + + if (!connector_np) + { + return RT_NULL; + } + + /* A DSI panel is commonly represented as a direct child of the host. */ + rt_ofw_foreach_available_child_node(connector_np, child) + { + if (rt_ofw_node_is_compatible(child, "simple-panel-dsi") || + rt_ofw_node_is_compatible(child, "simple-panel") || + rt_ofw_node_is_compatible(child, "rockchip,panel-simple")) + { + return child; + } + + if (rt_ofw_node_tag_equ(child, "ports")) + { + ports_np = child; + } + } + + if (!ports_np) + { + return RT_NULL; + } + + rt_ofw_foreach_available_child_node(ports_np, port_np) + { + rt_ofw_foreach_available_child_node(port_np, ep_np) + { + remote_ep = display_graph_remote(ep_np); + + if (!remote_ep) + { + continue; + } + + sink_np = display_graph_device_from_ep(remote_ep, RT_NULL); + + if (sink_np && sink_np != source_np && sink_np != connector_np) + { + rt_ofw_node_put(remote_ep); + return sink_np; + } + + rt_ofw_node_put(remote_ep); + } + } + + return RT_NULL; +} + +rt_err_t display_route_get_vp_id(struct rt_ofw_node *vp_port_np, rt_uint32_t *vp_id) +{ + rt_uint32_t reg; + + if (!vp_port_np || !vp_id) + { + return -RT_EINVAL; + } + + if (!rt_ofw_prop_read_u32(vp_port_np, "reg", ®)) + { + *vp_id = reg; + return RT_EOK; + } + + *vp_id = 0; + + return RT_EOK; +} + +rt_err_t display_route_resolve(struct rt_ofw_node *route_np, struct display_route *route) +{ + struct rt_ofw_node *ep_np, *port_np, *remote_ep, *remote_port; + const char *route_name = display_route_node_name(route_np); + + if (!route_np || !route) + { + return -RT_EINVAL; + } + + rt_memset(route, 0, sizeof(*route)); + route->route_np = route_np; + + ep_np = rt_ofw_parse_phandle(route_np, "connect", 0); + + if (!ep_np) + { + LOG_W("route %s: missing connect phandle", route_name); + return -RT_EINVAL; + } + + route->vop_np = display_graph_device_from_ep(ep_np, &port_np); + + if (!port_np) + { + LOG_W("route %s: endpoint %s has no port parent", + route_name, display_route_node_name(ep_np)); + return -RT_ENOENT; + } + + route->vp_port_np = port_np; + + if (!route->vop_np) + { + LOG_W("route %s: failed to resolve vop node", route_name); + return -RT_ENOENT; + } + + display_route_get_vp_id(route->vp_port_np, &route->vp_id); + + remote_ep = display_graph_remote(ep_np); + + if (!remote_ep) + { + LOG_W("route %s: endpoint %s missing remote-endpoint", + route_name, display_route_node_name(ep_np)); + return -RT_ENOENT; + } + + route->connector_np = display_graph_device_from_ep(remote_ep, &remote_port); + + if (!remote_port) + { + LOG_W("route %s: remote endpoint %s has no port parent", + route_name, display_route_node_name(remote_ep)); + return -RT_ENOENT; + } + + if (!route->connector_np) + { + LOG_W("route %s: remote port %s has no connector parent", + route_name, display_route_node_name(remote_port)); + return -RT_ENOENT; + } + + route->panel_np = display_graph_find_sink(route->connector_np, route->vop_np); + + LOG_D("route %s: resolved vop=%s vp%u connector=%s panel=%s", + route_name, display_route_node_name(route->vop_np), route->vp_id, + display_route_node_name(route->connector_np), + display_route_node_name(route->panel_np)); + + return RT_EOK; +} diff --git a/bsp/rockchip/dm/graphic/framebuffer/display-timing.c b/bsp/rockchip/dm/graphic/framebuffer/display-timing.c new file mode 100644 index 000000000000..1457f040b15e --- /dev/null +++ b/bsp/rockchip/dm/graphic/framebuffer/display-timing.c @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-09-23 GuEe-GUI first version + */ + +#include "rockchip-display.h" + +void display_timing_derive(struct display_timing *tim) +{ + rt_uint32_t hsync_start, hsync_end, vsync_start, vsync_end; + + hsync_start = tim->hactive + tim->hfront_porch; + hsync_end = hsync_start + tim->hsync_len; + tim->htotal = hsync_end + tim->hback_porch; + + vsync_start = tim->vactive + tim->vfront_porch; + vsync_end = vsync_start + tim->vsync_len; + tim->vtotal = vsync_end + tim->vback_porch; +} + +static rt_err_t display_timing_read_u32(struct rt_ofw_node *np, + const char *prop, rt_uint32_t *value) +{ + int count = rt_ofw_prop_count_of_u32(np, prop); + + if (count <= 0) + { + return count ? (rt_err_t)count : -RT_ENOENT; + } + + /* Timing bindings may encode ; use the typical value. */ + return rt_ofw_prop_read_u32_index(np, prop, count >= 3 ? 1 : 0, value); +} + +static rt_err_t display_timing_parse_prop(struct rt_ofw_node *np, struct display_timing *tim) +{ + rt_uint32_t val, pixelclock; + + if (display_timing_read_u32(np, "hactive", &tim->hactive)) + { + return -RT_EINVAL; + } + + if (display_timing_read_u32(np, "vactive", &tim->vactive)) + { + return -RT_EINVAL; + } + + if (display_timing_read_u32(np, "clock-frequency", &pixelclock)) + { + tim->pixelclock = 0; + } + else + { + tim->pixelclock = pixelclock; + } + + if (display_timing_read_u32(np, "hsync-len", &tim->hsync_len)) + { + tim->hsync_len = 10; + } + + if (display_timing_read_u32(np, "hfront-porch", &tim->hfront_porch)) + { + tim->hfront_porch = 40; + } + + if (display_timing_read_u32(np, "hback-porch", &tim->hback_porch)) + { + tim->hback_porch = 40; + } + + if (display_timing_read_u32(np, "vsync-len", &tim->vsync_len)) + { + tim->vsync_len = 4; + } + + if (display_timing_read_u32(np, "vfront-porch", &tim->vfront_porch)) + { + tim->vfront_porch = 20; + } + + if (display_timing_read_u32(np, "vback-porch", &tim->vback_porch)) + { + tim->vback_porch = 20; + } + + tim->flags = 0; + + if (!rt_ofw_prop_read_u32(np, "hsync-active", &val) && val) + { + tim->flags |= DISPLAY_TIMING_F_PHSYNC; + } + + if (!rt_ofw_prop_read_u32(np, "vsync-active", &val) && val) + { + tim->flags |= DISPLAY_TIMING_F_PVSYNC; + } + + if (!rt_ofw_prop_read_u32(np, "pixelclk-active", &val) && !val) + { + tim->flags |= DISPLAY_TIMING_F_PIXDATA_NEGEDGE; + } + + display_timing_derive(tim); + + return RT_EOK; +} + +rt_err_t display_timing_parse(struct rt_ofw_node *np, struct display_timing *tim) +{ + struct rt_ofw_node *child, *timings; + rt_err_t err = -RT_ENOSYS; + + if (!np || !tim) + { + return -RT_EINVAL; + } + + rt_memset(tim, 0, sizeof(*tim)); + + if (!display_timing_parse_prop(np, tim)) + { + return RT_EOK; + } + + child = rt_ofw_get_child_by_tag(np, "panel-timing"); + if (child) + { + err = display_timing_parse_prop(child, tim); + rt_ofw_node_put(child); + + if (!err) + { + return RT_EOK; + } + } + + timings = rt_ofw_get_child_by_tag(np, "display-timings"); + if (!timings) + { + return err; + } + + child = rt_ofw_parse_phandle(timings, "native-mode", 0); + if (child) + { + err = display_timing_parse_prop(child, tim); + rt_ofw_node_put(child); + + if (!err) + { + rt_ofw_node_put(timings); + return RT_EOK; + } + } + + rt_ofw_foreach_available_child_node(timings, child) + { + err = display_timing_parse_prop(child, tim); + + if (!err) + { + rt_ofw_node_put(child); + rt_ofw_node_put(timings); + return RT_EOK; + } + } + + rt_ofw_node_put(timings); + + return err; +} diff --git a/bsp/rockchip/dm/graphic/framebuffer/dsi-rockchip.c b/bsp/rockchip/dm/graphic/framebuffer/dsi-rockchip.c new file mode 100644 index 000000000000..a21007dfd774 --- /dev/null +++ b/bsp/rockchip/dm/graphic/framebuffer/dsi-rockchip.c @@ -0,0 +1,1027 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-09-23 GuEe-GUI first version + */ + +#include "rockchip-display.h" + +#define DBG_TAG "dsi.rk" +#define DBG_LVL DBG_INFO +#include + +#define DSI_VERSION 0x00 +#define DSI_PWR_UP 0x04 +#define DSI_CLKMGR_CFG 0x08 +#define DSI_DPI_VCID 0x0c +#define DSI_DPI_COLOR_CODING 0x10 +#define DSI_DPI_CFG_POL 0x14 +#define DSI_DPI_LP_CMD_TIM 0x18 +#define DSI_PCKHDL_CFG 0x2c +#define DSI_MODE_CFG 0x34 +#define DSI_VID_MODE_CFG 0x38 +#define DSI_VID_PKT_SIZE 0x3c +#define DSI_VID_NUM_CHUNKS 0x40 +#define DSI_VID_NULL_SIZE 0x44 +#define DSI_VID_HSA_TIME 0x48 +#define DSI_VID_HBP_TIME 0x4c +#define DSI_VID_HLINE_TIME 0x50 +#define DSI_VID_VSA_LINES 0x54 +#define DSI_VID_VBP_LINES 0x58 +#define DSI_VID_VFP_LINES 0x5c +#define DSI_VID_VACTIVE_LINES 0x60 +#define DSI_EDPI_CMD_SIZE 0x64 +#define DSI_CMD_MODE_CFG 0x68 +#define DSI_GEN_HDR 0x6c +#define DSI_GEN_PLD_DATA 0x70 +#define DSI_CMD_PKT_STATUS 0x74 +#define DSI_TO_CNT_CFG 0x78 +#define DSI_BTA_TO_CNT 0x8c +#define DSI_LPCLK_CTRL 0x94 +#define DSI_PHY_TMR_LPCLK_CFG 0x98 +#define DSI_PHY_TMR_CFG 0x9c +#define DSI_PHY_RSTZ 0xa0 +#define DSI_PHY_IF_CFG 0xa4 +#define DSI_PHY_STATUS 0xb0 +#define DSI_PHY_TST_CTRL0 0xb4 +#define DSI_INT_ST0 0xbc +#define DSI_INT_ST1 0xc0 +#define DSI_INT_MSK0 0xc4 +#define DSI_INT_MSK1 0xc8 +#define DSI_PHY_TMR_RD_CFG 0xf4 + +#define DSI_POWERUP RT_BIT(0) +#define DSI_CMD_MODE RT_BIT(0) +#define DSI_VIDEO_MODE 0 + +#define DSI_TO_CLK_DIV(x) (((x) & 0xff) << 8) +#define DSI_TX_ESC_CLK_DIV(x) ((x) & 0xff) + +#define DSI_DPI_COLOR_16BIT 0x0 +#define DSI_DPI_COLOR_18BIT_PACKED 0x3 +#define DSI_DPI_COLOR_18BIT_LOOSE (0x4 | RT_BIT(8)) +#define DSI_DPI_COLOR_24BIT 0x5 +#define DSI_HSYNC_ACTIVE_LOW RT_BIT(2) +#define DSI_VSYNC_ACTIVE_LOW RT_BIT(1) + +#define DSI_CRC_RX_EN RT_BIT(4) +#define DSI_ECC_RX_EN RT_BIT(3) +#define DSI_BTA_EN RT_BIT(2) +#define DSI_EOTP_RX_EN RT_BIT(1) +#define DSI_EOTP_TX_EN RT_BIT(0) + +#define DSI_LP_HFP_EN RT_BIT(13) +#define DSI_LP_HBP_EN RT_BIT(12) +#define DSI_LP_VACT_EN RT_BIT(11) +#define DSI_LP_VFP_EN RT_BIT(10) +#define DSI_LP_VBP_EN RT_BIT(9) +#define DSI_LP_VSA_EN RT_BIT(8) +#define DSI_ENABLE_LP_CMD RT_BIT(15) +#define DSI_VID_MODE_BURST 0x2 +#define DSI_VID_MODE_SYNC_PULSE 0x0 +#define DSI_VID_MODE_SYNC_EVENT 0x1 +#define DSI_VID_MODE_VPG_ENABLE RT_BIT(16) +#define DSI_VID_MODE_VPG_BER RT_BIT(20) +#define DSI_VID_MODE_VPG_HORIZONTAL RT_BIT(24) + +#define DSI_CMD_MODE_ALL_LP (RT_BIT(24) | RT_BIT(19) | RT_BIT(18) | \ + RT_BIT(17) | RT_BIT(16) | RT_BIT(14) | \ + RT_BIT(13) | RT_BIT(12) | RT_BIT(11) | \ + RT_BIT(10) | RT_BIT(9) | RT_BIT(8)) + +#define DSI_GEN_PLD_W_FULL RT_BIT(3) +#define DSI_GEN_PLD_W_EMPTY RT_BIT(2) +#define DSI_GEN_CMD_FULL RT_BIT(1) +#define DSI_GEN_CMD_EMPTY RT_BIT(0) +#define DSI_GEN_RD_CMD_BUSY RT_BIT(6) +#define DSI_GEN_PLD_R_EMPTY RT_BIT(4) + +#define DSI_PHY_TXREQUESTCLKHS RT_BIT(0) +#define DSI_AUTO_CLKLANE_CTRL RT_BIT(1) +#define DSI_PHY_LOCK RT_BIT(0) +#define DSI_PHY_STOP_CLK RT_BIT(2) +#define DSI_PHY_ENABLE 0x0f + +#define MIPI_DSI_MODE_VIDEO RT_BIT(0) +#define MIPI_DSI_MODE_VIDEO_BURST RT_BIT(1) +#define MIPI_DSI_MODE_VIDEO_SYNC_PULSE RT_BIT(2) +#define MIPI_DSI_MODE_VIDEO_NO_HFP RT_BIT(5) +#define MIPI_DSI_MODE_VIDEO_NO_HBP RT_BIT(6) +#define MIPI_DSI_MODE_NO_EOT_PACKET RT_BIT(9) +#define MIPI_DSI_CLOCK_NON_CONTINUOUS RT_BIT(10) +#define MIPI_DSI_MODE_LPM RT_BIT(11) + +#define MIPI_DSI_FMT_RGB888 0 +#define MIPI_DSI_FMT_RGB666 1 +#define MIPI_DSI_FMT_RGB666_PACKED 2 +#define MIPI_DSI_FMT_RGB565 3 + +#define RK3568_GRF_VO_CON2 0x0368 +#define RK3568_GRF_VO_CON3 0x036c +#define RK3568_DSI_LANE_CFG_MASK ((0x1f << 11) | (0xf << 4) | RT_BIT(2) | RT_BIT(0)) +#define HIWORD_UPDATE(v, m) (((v) & (m)) | ((m) << 16)) + +#define DSI_FIFO_TIMEOUT_US 20000 +#define DSI_PHY_TIMEOUT_US 20000 + +struct rk_dsi +{ + struct rt_device *dev; + void *regs; + struct rt_clk_array *clks; + struct rt_reset_control *apb_rst; + struct rt_syscon *grf; + struct rt_phye *dphy; + struct rt_ofw_node *panel_np; + rt_uint32_t grf_lane_reg; + rt_uint32_t lanes; + rt_uint32_t channel; + rt_uint32_t format; + rt_uint32_t mode_flags; + rt_uint32_t lane_mbps; + rt_uint32_t id; + struct display_timing mode; + rt_bool_t prepared; + rt_bool_t phy_on; +}; + +static struct rk_dsi *rk_dsi_instances[2]; + +rt_inline rt_uint32_t dsi_read(struct rk_dsi *dsi, rt_uint32_t reg) +{ + return HWREG32((rt_uint8_t *)dsi->regs + reg); +} + +rt_inline void dsi_write(struct rk_dsi *dsi, rt_uint32_t reg, rt_uint32_t val) +{ + HWREG32((rt_uint8_t *)dsi->regs + reg) = val; +} + +static rt_err_t rk_dsi_wait(struct rk_dsi *dsi, rt_uint32_t reg, + rt_uint32_t mask, rt_uint32_t expected, rt_uint32_t timeout_us) +{ + while (timeout_us) + { + if ((dsi_read(dsi, reg) & mask) == expected) + { + return RT_EOK; + } + + rt_hw_us_delay(10); + timeout_us = timeout_us > 10 ? timeout_us - 10 : 0; + } + + return -RT_ETIMEOUT; +} + +static rt_bool_t rk_dsi_packet_is_long(rt_uint8_t type) +{ + return type == 0x19 || type == 0x29 || type == 0x39; +} + +static rt_err_t rk_dsi_write_packet(struct rk_dsi *dsi, rt_uint8_t type, + const rt_uint8_t *payload, rt_size_t len) +{ + rt_uint32_t header, word, status; + rt_size_t i; + + if (rk_dsi_packet_is_long(type)) + { + for (i = 0; i < len; i += sizeof(word)) + { + rt_size_t chunk = len - i; + + if (rk_dsi_wait(dsi, DSI_CMD_PKT_STATUS, DSI_GEN_PLD_W_FULL, 0, + DSI_FIFO_TIMEOUT_US)) + { + return -RT_ETIMEOUT; + } + + if (chunk > sizeof(word)) + { + chunk = sizeof(word); + } + + word = 0; + rt_memcpy(&word, &payload[i], chunk); + dsi_write(dsi, DSI_GEN_PLD_DATA, word); + } + + header = (type & 0x3f) | ((dsi->channel & 0x3) << 6) | + ((len & 0xff) << 8) | (((len >> 8) & 0xff) << 16); + } + else + { + header = (type & 0x3f) | ((dsi->channel & 0x3) << 6); + + if (len) + { + header |= payload[0] << 8; + } + if (len > 1) + { + header |= payload[1] << 16; + } + } + + if (rk_dsi_wait(dsi, DSI_CMD_PKT_STATUS, DSI_GEN_CMD_FULL, 0, + DSI_FIFO_TIMEOUT_US)) + { + return -RT_ETIMEOUT; + } + + dsi_write(dsi, DSI_GEN_HDR, header); + status = DSI_GEN_CMD_EMPTY | DSI_GEN_PLD_W_EMPTY; + + return rk_dsi_wait(dsi, DSI_CMD_PKT_STATUS, status, status, + DSI_FIFO_TIMEOUT_US); +} + +static rt_err_t rk_dsi_transfer(void *priv, rt_uint8_t data_type, rt_uint8_t delay_ms, + const rt_uint8_t *payload, rt_size_t len) +{ + struct rk_dsi *dsi = priv; + rt_uint32_t val; + rt_err_t err; + + if (!dsi || (!payload && len)) + { + return -RT_EINVAL; + } + + dsi_write(dsi, DSI_DPI_LP_CMD_TIM, (16 << 16) | 4); + dsi_write(dsi, DSI_CMD_MODE_CFG, + (dsi->mode_flags & MIPI_DSI_MODE_LPM) ? DSI_CMD_MODE_ALL_LP : 0); + + val = dsi_read(dsi, DSI_VID_MODE_CFG); + if (dsi->mode_flags & MIPI_DSI_MODE_LPM) + { + val |= DSI_ENABLE_LP_CMD; + dsi_write(dsi, DSI_LPCLK_CTRL, + dsi_read(dsi, DSI_LPCLK_CTRL) & ~DSI_PHY_TXREQUESTCLKHS); + } + else + { + val &= ~DSI_ENABLE_LP_CMD; + dsi_write(dsi, DSI_LPCLK_CTRL, + dsi_read(dsi, DSI_LPCLK_CTRL) | DSI_PHY_TXREQUESTCLKHS); + } + dsi_write(dsi, DSI_VID_MODE_CFG, val); + + err = rk_dsi_write_packet(dsi, data_type, payload, len); + + if (delay_ms) + { + rt_thread_mdelay(delay_ms); + } + + return err; +} + +static rt_err_t rk_dsi_read_packet(struct rk_dsi *dsi, rt_uint8_t command, + rt_uint8_t *payload, rt_size_t len) +{ + rt_uint8_t max_return[2]; + rt_uint32_t saved_power, saved_mode, saved_cmd, saved_lpclk, saved_video; + rt_uint32_t status, val, word; + rt_size_t i, j; + rt_err_t err; + + if (!dsi || !payload || !len || len > 0xffff) + { + return -RT_EINVAL; + } + + max_return[0] = len & 0xff; + max_return[1] = (len >> 8) & 0xff; + + saved_power = dsi_read(dsi, DSI_PWR_UP); + saved_mode = dsi_read(dsi, DSI_MODE_CFG); + saved_cmd = dsi_read(dsi, DSI_CMD_MODE_CFG); + saved_lpclk = dsi_read(dsi, DSI_LPCLK_CTRL); + saved_video = dsi_read(dsi, DSI_VID_MODE_CFG); + + /* Stop the video stream before requesting bus turn-around. */ + dsi_write(dsi, DSI_PWR_UP, 0); + dsi_write(dsi, DSI_MODE_CFG, DSI_CMD_MODE); + dsi_write(dsi, DSI_DPI_LP_CMD_TIM, (16 << 16) | 4); + dsi_write(dsi, DSI_CMD_MODE_CFG, DSI_CMD_MODE_ALL_LP); + + val = dsi_read(dsi, DSI_VID_MODE_CFG) | DSI_ENABLE_LP_CMD; + dsi_write(dsi, DSI_VID_MODE_CFG, val); + dsi_write(dsi, DSI_LPCLK_CTRL, + dsi_read(dsi, DSI_LPCLK_CTRL) & ~DSI_PHY_TXREQUESTCLKHS); + dsi_write(dsi, DSI_PWR_UP, DSI_POWERUP); + + err = rk_dsi_wait(dsi, DSI_PHY_STATUS, DSI_PHY_STOP_CLK, + DSI_PHY_STOP_CLK, DSI_PHY_TIMEOUT_US); + if (err) + { + goto _restore; + } + + err = rk_dsi_write_packet(dsi, 0x37, max_return, sizeof(max_return)); + if (err) + { + goto _restore; + } + + dsi_write(dsi, DSI_CMD_MODE_CFG, DSI_CMD_MODE_ALL_LP); + err = rk_dsi_write_packet(dsi, 0x06, &command, 1); + if (err) + { + goto _restore; + } + + err = rk_dsi_wait(dsi, DSI_CMD_PKT_STATUS, DSI_GEN_RD_CMD_BUSY, 0, + DSI_FIFO_TIMEOUT_US); + if (err) + { + goto _restore; + } + + for (i = 0; i < len; i += sizeof(word)) + { + err = rk_dsi_wait(dsi, DSI_CMD_PKT_STATUS, DSI_GEN_PLD_R_EMPTY, 0, + DSI_FIFO_TIMEOUT_US); + if (err) + { + goto _restore; + } + + word = dsi_read(dsi, DSI_GEN_PLD_DATA); + for (j = 0; j < sizeof(word) && i + j < len; ++j) + { + payload[i + j] = (word >> (j * 8)) & 0xff; + } + } + + status = dsi_read(dsi, DSI_CMD_PKT_STATUS); + if (!(status & DSI_GEN_PLD_R_EMPTY)) + { + LOG_W("DCS read left data in RX FIFO, status=0x%08x", status); + } + +_restore: + dsi_write(dsi, DSI_PWR_UP, 0); + dsi_write(dsi, DSI_CMD_MODE_CFG, saved_cmd); + dsi_write(dsi, DSI_VID_MODE_CFG, saved_video); + dsi_write(dsi, DSI_LPCLK_CTRL, saved_lpclk); + dsi_write(dsi, DSI_MODE_CFG, saved_mode); + dsi_write(dsi, DSI_PWR_UP, saved_power); + + return err; +} + +static rt_uint32_t rk_dsi_lbcc(struct rk_dsi *dsi, rt_uint32_t pixels) +{ + rt_uint64_t cycles; + + if (!dsi->mode.pixelclock) + { + return 0; + } + + cycles = (rt_uint64_t)pixels * dsi->lane_mbps * 1000000ULL; + cycles = (cycles + dsi->mode.pixelclock * 4) / (dsi->mode.pixelclock * 8); + + return (rt_uint32_t)cycles; +} + +static void rk_dsi_set_mode(struct rk_dsi *dsi, rt_bool_t video) +{ + rt_uint32_t val; + + dsi_write(dsi, DSI_PWR_UP, 0); + + if (video) + { + val = DSI_LP_VSA_EN | DSI_LP_VBP_EN | DSI_LP_VFP_EN | + DSI_LP_VACT_EN | DSI_LP_HBP_EN | DSI_LP_HFP_EN; + + if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_NO_HFP) + { + val &= ~DSI_LP_HFP_EN; + } + if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_NO_HBP) + { + val &= ~DSI_LP_HBP_EN; + } + + if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_BURST) + { + val |= DSI_VID_MODE_BURST; + } + else if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) + { + val |= DSI_VID_MODE_SYNC_PULSE; + } + else + { + val |= DSI_VID_MODE_SYNC_EVENT; + } + + dsi_write(dsi, DSI_VID_MODE_CFG, val); + dsi_write(dsi, DSI_MODE_CFG, DSI_VIDEO_MODE); + } + else + { + dsi_write(dsi, DSI_MODE_CFG, DSI_CMD_MODE); + } + + dsi_write(dsi, DSI_PWR_UP, DSI_POWERUP); +} + +static rt_err_t rk_dsi_configure_phy(struct rk_dsi *dsi) +{ + union rt_phye_configure_opts opts; + rt_uint64_t target_rate; + rt_uint32_t bpp; + rt_err_t err; + + if (!dsi->dphy) + { + return -RT_ENOSYS; + } + + switch (dsi->format) + { + case MIPI_DSI_FMT_RGB565: + bpp = 16; + break; + case MIPI_DSI_FMT_RGB666: + case MIPI_DSI_FMT_RGB666_PACKED: + bpp = 18; + break; + case MIPI_DSI_FMT_RGB888: + default: + bpp = 24; + break; + } + + /* Match Rockchip Linux's MHz-rounded external-PHY bandwidth calculation. */ + target_rate = RT_DIV_ROUND_UP_ULL(dsi->mode.pixelclock, 1000000ULL); + target_rate = target_rate * (bpp / dsi->lanes) * 10 / 9; + target_rate = (target_rate * dsi->lanes + bpp / 2) / bpp; + target_rate = target_rate * bpp * 1000000ULL / dsi->lanes; + + rt_memset(&opts, 0, sizeof(opts)); + rt_phye_mipi_dphy_get_default_config_for_hsclk(target_rate, dsi->lanes, + &opts.mipi_dphy); + + if ((err = rt_phye_set_mode_simple(dsi->dphy, RT_PHYE_MODE_MIPI_DPHY))) + { + return err; + } + if ((err = rt_phye_configure(dsi->dphy, &opts))) + { + return err; + } + + dsi->lane_mbps = (rt_uint32_t)((opts.mipi_dphy.hs_clk_rate + 999999) / 1000000); + + return RT_EOK; +} + +static void rk_dsi_host_config(struct rk_dsi *dsi) +{ + rt_uint32_t color, pol = 0, pckhdl, esc_div, hwver; + + esc_div = ((dsi->lane_mbps / 8) + 19) / 20; + if (!esc_div) + { + esc_div = 1; + } + + dsi_write(dsi, DSI_PWR_UP, 0); + dsi_write(dsi, DSI_CLKMGR_CFG, DSI_TO_CLK_DIV(10) | DSI_TX_ESC_CLK_DIV(esc_div)); + + switch (dsi->format) + { + case MIPI_DSI_FMT_RGB565: + color = DSI_DPI_COLOR_16BIT; + break; + case MIPI_DSI_FMT_RGB666: + color = DSI_DPI_COLOR_18BIT_LOOSE; + break; + case MIPI_DSI_FMT_RGB666_PACKED: + color = DSI_DPI_COLOR_18BIT_PACKED; + break; + case MIPI_DSI_FMT_RGB888: + default: + color = DSI_DPI_COLOR_24BIT; + break; + } + + if (!(dsi->mode.flags & DISPLAY_TIMING_F_PHSYNC)) + { + pol |= DSI_HSYNC_ACTIVE_LOW; + } + if (!(dsi->mode.flags & DISPLAY_TIMING_F_PVSYNC)) + { + pol |= DSI_VSYNC_ACTIVE_LOW; + } + + dsi_write(dsi, DSI_DPI_VCID, dsi->channel & 0x3); + dsi_write(dsi, DSI_DPI_COLOR_CODING, color); + dsi_write(dsi, DSI_DPI_CFG_POL, pol); + + pckhdl = DSI_CRC_RX_EN | DSI_ECC_RX_EN | DSI_BTA_EN; + if (!(dsi->mode_flags & MIPI_DSI_MODE_NO_EOT_PACKET)) + { + pckhdl |= DSI_EOTP_RX_EN | DSI_EOTP_TX_EN; + } + dsi_write(dsi, DSI_PCKHDL_CFG, pckhdl); + + dsi_write(dsi, DSI_VID_PKT_SIZE, dsi->mode.hactive); + dsi_write(dsi, DSI_VID_NUM_CHUNKS, 0); + dsi_write(dsi, DSI_VID_NULL_SIZE, 0); + dsi_write(dsi, DSI_VID_HSA_TIME, rk_dsi_lbcc(dsi, dsi->mode.hsync_len)); + dsi_write(dsi, DSI_VID_HBP_TIME, rk_dsi_lbcc(dsi, dsi->mode.hback_porch)); + dsi_write(dsi, DSI_VID_HLINE_TIME, rk_dsi_lbcc(dsi, dsi->mode.htotal)); + dsi_write(dsi, DSI_VID_VSA_LINES, dsi->mode.vsync_len); + dsi_write(dsi, DSI_VID_VBP_LINES, dsi->mode.vback_porch); + dsi_write(dsi, DSI_VID_VFP_LINES, dsi->mode.vfront_porch); + dsi_write(dsi, DSI_VID_VACTIVE_LINES, dsi->mode.vactive); + + dsi_write(dsi, DSI_TO_CNT_CFG, (1000 << 16) | 1000); + dsi_write(dsi, DSI_BTA_TO_CNT, 0xd00); + dsi_write(dsi, DSI_MODE_CFG, DSI_CMD_MODE); + + dsi_write(dsi, DSI_PHY_RSTZ, 0); + dsi_write(dsi, DSI_PHY_TST_CTRL0, 0); + dsi_write(dsi, DSI_PHY_TST_CTRL0, 1); + dsi_write(dsi, DSI_PHY_TST_CTRL0, 0); + + hwver = dsi_read(dsi, DSI_VERSION) & 0xffffff00; + if (hwver >= 0x31333100) + { + dsi_write(dsi, DSI_PHY_TMR_CFG, (0x14 << 16) | 0x10); + dsi_write(dsi, DSI_PHY_TMR_RD_CFG, 10000); + } + else + { + dsi_write(dsi, DSI_PHY_TMR_CFG, (0x14 << 24) | (0x10 << 16) | 10000); + } + dsi_write(dsi, DSI_PHY_TMR_LPCLK_CFG, (0x40 << 16) | 0x40); + dsi_write(dsi, DSI_PHY_IF_CFG, (0x20 << 8) | ((dsi->lanes - 1) & 0x3)); + + (void)dsi_read(dsi, DSI_INT_ST0); + (void)dsi_read(dsi, DSI_INT_ST1); + dsi_write(dsi, DSI_INT_MSK0, 0); + dsi_write(dsi, DSI_INT_MSK1, 0); +} + +static rt_err_t rk_dsi_prepare(void *priv, rt_uint32_t vp_id, + const struct display_timing *tim) +{ + struct rk_dsi *dsi = priv; + rt_err_t err; + + RT_UNUSED(vp_id); + + if (!dsi || !tim || !tim->hactive || !tim->vactive) + { + return -RT_EINVAL; + } + + if (dsi->prepared) + { + return RT_EOK; + } + + dsi->mode = *tim; + + if ((err = rt_clk_array_prepare_enable(dsi->clks))) + { + return err; + } + + if (!rt_is_err_or_null(dsi->apb_rst)) + { + rt_reset_control_assert(dsi->apb_rst); + rt_hw_us_delay(10); + rt_reset_control_deassert(dsi->apb_rst); + } + + if ((err = rk_dsi_configure_phy(dsi))) + { + goto _fail_clk; + } + + if (dsi->grf) + { + rt_syscon_write(dsi->grf, dsi->grf_lane_reg, + HIWORD_UPDATE(0, RK3568_DSI_LANE_CFG_MASK)); + } + + rk_dsi_host_config(dsi); + + if ((err = rt_phye_init(dsi->dphy))) + { + goto _fail_clk; + } + if ((err = rt_phye_power_on(dsi->dphy))) + { + rt_phye_exit(dsi->dphy); + goto _fail_clk; + } + dsi->phy_on = RT_TRUE; + + dsi_write(dsi, DSI_PHY_RSTZ, DSI_PHY_ENABLE); + + if ((err = rk_dsi_wait(dsi, DSI_PHY_STATUS, DSI_PHY_LOCK, + DSI_PHY_LOCK, DSI_PHY_TIMEOUT_US))) + { + LOG_W("PHY lock timeout, status=0x%08x", dsi_read(dsi, DSI_PHY_STATUS)); + goto _fail_phy; + } + if ((err = rk_dsi_wait(dsi, DSI_PHY_STATUS, DSI_PHY_STOP_CLK, + DSI_PHY_STOP_CLK, DSI_PHY_TIMEOUT_US))) + { + LOG_W("PHY clock lane stop timeout, status=0x%08x", dsi_read(dsi, DSI_PHY_STATUS)); + goto _fail_phy; + } + + /* Synopsys requires two generated frame periods before panel prepare. */ + if (tim->pixelclock && tim->htotal && tim->vtotal) + { + rt_uint64_t frame_pixels = (rt_uint64_t)tim->htotal * tim->vtotal; + rt_uint32_t refresh = (rt_uint32_t)(tim->pixelclock / frame_pixels); + + if (!refresh) + { + refresh = 60; + } + rt_thread_mdelay(RT_DIV_ROUND_UP(1000, refresh) * 2); + } + + rk_dsi_set_mode(dsi, RT_FALSE); + dsi->prepared = RT_TRUE; + + LOG_D("prepared %ux%u, %u lane(s) at %u Mbps", + tim->hactive, tim->vactive, dsi->lanes, dsi->lane_mbps); + + return RT_EOK; + +_fail_phy: + rt_phye_power_off(dsi->dphy); + rt_phye_exit(dsi->dphy); + dsi->phy_on = RT_FALSE; +_fail_clk: + rt_clk_array_disable_unprepare(dsi->clks); + return err; +} + +static rt_err_t rk_dsi_enable(void *priv, rt_bool_t enable) +{ + struct rk_dsi *dsi = priv; + rt_uint32_t val; + + if (!dsi || (enable && !dsi->prepared)) + { + return -RT_EINVAL; + } + + if (enable) + { + val = DSI_PHY_TXREQUESTCLKHS; + if (dsi->mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS) + { + val |= DSI_AUTO_CLKLANE_CTRL; + } + dsi_write(dsi, DSI_LPCLK_CTRL, val); + dsi_write(dsi, DSI_EDPI_CMD_SIZE, dsi->mode.hactive); + rk_dsi_set_mode(dsi, !!(dsi->mode_flags & MIPI_DSI_MODE_VIDEO)); + +#if DBG_LVL >= DBG_LOG + LOG_D("enabled video stream: phy=0x%08x cmd=0x%08x int0=0x%08x int1=0x%08x", + dsi_read(dsi, DSI_PHY_STATUS), + dsi_read(dsi, DSI_CMD_PKT_STATUS), + dsi_read(dsi, DSI_INT_ST0), + dsi_read(dsi, DSI_INT_ST1)); +#endif + } + else + { + dsi_write(dsi, DSI_LPCLK_CTRL, 0); + dsi_write(dsi, DSI_PWR_UP, 0); + + if (dsi->phy_on) + { + rt_phye_power_off(dsi->dphy); + rt_phye_exit(dsi->dphy); + dsi->phy_on = RT_FALSE; + } + + rt_clk_array_disable_unprepare(dsi->clks); + dsi->prepared = RT_FALSE; + } + + return RT_EOK; +} + +static rt_err_t rk_dsi_disable(void *priv) +{ + return rk_dsi_enable(priv, RT_FALSE); +} + +static const struct rockchip_connector_ops rk_dsi_connector_ops = +{ + .prepare = rk_dsi_prepare, + .transfer = rk_dsi_transfer, + .enable = rk_dsi_enable, + .disable = rk_dsi_disable, +}; + +static struct rt_ofw_node *rk_dsi_find_panel(struct rt_ofw_node *np) +{ + struct rt_ofw_node *child; + + rt_ofw_foreach_available_child_node(np, child) + { + if (rt_ofw_node_is_compatible(child, "simple-panel-dsi") || + rt_ofw_node_is_compatible(child, "rockchip,panel-simple")) + { + return child; + } + } + + return RT_NULL; +} + +static rt_err_t rk_dsi_probe(struct rt_platform_device *pdev) +{ + struct rt_device *dev = &pdev->parent; + struct rt_ofw_node *np = dev->ofw_node; + struct rk_dsi *dsi = rt_calloc(1, sizeof(*dsi)); + rt_uint64_t addr; + rt_err_t err; + + if (!dsi) + { + return -RT_ENOMEM; + } + + dsi->dev = dev; + dsi->regs = rt_ofw_iomap(np, 0); + + if (!dsi->regs) + { + err = -RT_EIO; + goto _fail; + } + + dsi->clks = rt_clk_get_array(dev); + if (rt_is_err(dsi->clks)) + { + err = rt_ptr_err(dsi->clks); + goto _fail_unmap; + } + + dsi->apb_rst = rt_reset_control_get_by_name(dev, "apb"); + dsi->grf = rt_syscon_find_by_ofw_phandle(np, "rockchip,grf"); + dsi->dphy = rt_phye_get_by_name(dev, "dphy"); + + if (rt_is_err_or_null(dsi->dphy)) + { + LOG_D("%s: waiting for DPHY provider", rt_ofw_node_full_name(np)); + err = -RT_EBUSY; + goto _fail_resources; + } + + dsi->lanes = 4; + dsi->channel = 0; + dsi->format = MIPI_DSI_FMT_RGB888; + dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | + MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_NO_EOT_PACKET; + + dsi->panel_np = rk_dsi_find_panel(np); + if (dsi->panel_np) + { + rt_ofw_prop_read_u32(dsi->panel_np, "dsi,lanes", &dsi->lanes); + rt_ofw_prop_read_u32(dsi->panel_np, "dsi,format", &dsi->format); + rt_ofw_prop_read_u32(dsi->panel_np, "dsi,flags", &dsi->mode_flags); + rt_ofw_prop_read_u32(dsi->panel_np, "reg", &dsi->channel); + + err = rt_platform_ofw_request(dsi->panel_np); + if (err || !dsi->panel_np->dev || !dsi->panel_np->dev->drv) + { + LOG_E("%s: panel driver probe failed", rt_ofw_node_full_name(np)); + err = err ? err : -RT_ENOSYS; + goto _fail_dphy; + } + } + + if (!dsi->lanes || dsi->lanes > 4) + { + err = -RT_EINVAL; + goto _fail_dphy; + } + + if (!rt_ofw_get_address(np, 0, &addr, RT_NULL) && addr == 0xfe070000ULL) + { + dsi->id = 1; + dsi->grf_lane_reg = RK3568_GRF_VO_CON3; + } + else + { + dsi->id = 0; + dsi->grf_lane_reg = RK3568_GRF_VO_CON2; + } + + if ((err = rockchip_display_register_connector(np, &rk_dsi_connector_ops, dsi))) + { + goto _fail_dphy; + } + + dev->user_data = dsi; + rk_dsi_instances[dsi->id] = dsi; + + LOG_D("DSI %s: panel=%s lanes=%u format=%u flags=0x%x", + rt_ofw_node_full_name(np), + dsi->panel_np ? rt_ofw_node_full_name(dsi->panel_np) : "", + dsi->lanes, dsi->format, dsi->mode_flags); + + return RT_EOK; + +_fail_dphy: + if (dsi->panel_np) + { + rt_ofw_node_put(dsi->panel_np); + } + rt_phye_put(dsi->dphy); +_fail_resources: + if (!rt_is_err_or_null(dsi->apb_rst)) + { + rt_reset_control_put(dsi->apb_rst); + } + rt_clk_array_put(dsi->clks); +_fail_unmap: + rt_iounmap(dsi->regs); +_fail: + rt_free(dsi); + return err; +} + +static int rk_dsi_retry_deferred_probe(void) +{ + rt_err_t err; + struct rt_ofw_node *np; + + rt_ofw_foreach_node_by_compatible(np, "rockchip,rk3568-mipi-dsi") + { + if (!rt_ofw_node_is_available(np) || (np->dev && np->dev->drv)) + { + continue; + } + + err = rt_platform_ofw_request(np); + if (err || !np->dev || !np->dev->drv) + { + LOG_E("%s: deferred probe failed: %s", + rt_ofw_node_full_name(np), rt_strerror(err ? err : -RT_ENOSYS)); + } + } + + return 0; +} +INIT_COMPONENT_EXPORT(rk_dsi_retry_deferred_probe); + +#ifdef RT_USING_FINSH +#include +#include + +static int rk_dsi_vpg(int argc, char **argv) +{ + struct rk_dsi *dsi; + rt_uint32_t id, val; + + if (argc != 3 || argv[1][1] || (argv[1][0] != '0' && argv[1][0] != '1')) + { + rt_kprintf("Usage: dsi_vpg <0|1> \n"); + return -RT_EINVAL; + } + + id = argv[1][0] - '0'; + dsi = rk_dsi_instances[id]; + if (!dsi || !dsi->prepared) + { + rt_kprintf("dsi%u is not prepared\n", id); + return -RT_EBUSY; + } + + val = dsi_read(dsi, DSI_VID_MODE_CFG); + val &= ~(DSI_VID_MODE_VPG_ENABLE | DSI_VID_MODE_VPG_BER | + DSI_VID_MODE_VPG_HORIZONTAL); + + if (!rt_strcmp(argv[2], "color")) + { + val |= DSI_VID_MODE_VPG_ENABLE; + } + else if (!rt_strcmp(argv[2], "ber")) + { + val |= DSI_VID_MODE_VPG_ENABLE | DSI_VID_MODE_VPG_BER; + } + else if (rt_strcmp(argv[2], "off")) + { + rt_kprintf("Usage: dsi_vpg <0|1> \n"); + return -RT_EINVAL; + } + + dsi_write(dsi, DSI_VID_MODE_CFG, val); + rt_kprintf("dsi%u: VID_MODE_CFG=0x%08x PHY=0x%08x INT0=0x%08x INT1=0x%08x\n", + id, val, dsi_read(dsi, DSI_PHY_STATUS), + dsi_read(dsi, DSI_INT_ST0), dsi_read(dsi, DSI_INT_ST1)); + + return RT_EOK; +} +MSH_CMD_EXPORT_ALIAS(rk_dsi_vpg, dsi_vpg, + DSI internal pattern: dsi_vpg <0|1> ); + +static int rk_dsi_dcs_read(int argc, char **argv) +{ + struct rk_dsi *dsi; + rt_uint8_t data[16]; + unsigned long id, command, len = 1; + char *end; + rt_size_t i; + rt_err_t err; + + if (argc < 3 || argc > 4) + { + goto _usage; + } + + id = strtoul(argv[1], &end, 0); + if (*end || id > 1) + { + goto _usage; + } + + command = strtoul(argv[2], &end, 0); + if (*end || command > 0xff) + { + goto _usage; + } + + if (argc == 4) + { + len = strtoul(argv[3], &end, 0); + if (*end || !len || len > sizeof(data)) + { + goto _usage; + } + } + + dsi = rk_dsi_instances[id]; + if (!dsi || !dsi->prepared) + { + rt_kprintf("dsi%lu is not prepared\n", id); + return -RT_EBUSY; + } + + rt_memset(data, 0, sizeof(data)); + err = rk_dsi_read_packet(dsi, command, data, len); + rt_kprintf("dsi%lu DCS[0x%02lx]:", id, command); + if (err) + { + rt_kprintf(" read failed: %s, status=0x%08x int0=0x%08x int1=0x%08x\n", + rt_strerror(err), dsi_read(dsi, DSI_CMD_PKT_STATUS), + dsi_read(dsi, DSI_INT_ST0), dsi_read(dsi, DSI_INT_ST1)); + return err; + } + + for (i = 0; i < len; ++i) + { + rt_kprintf(" %02x", data[i]); + } + rt_kprintf("\n"); + + return RT_EOK; + +_usage: + rt_kprintf("Usage: dsi_dcs_read <0|1> [1..16]\n"); + return -RT_EINVAL; +} +MSH_CMD_EXPORT_ALIAS(rk_dsi_dcs_read, dsi_dcs_read, + Read panel DCS register: dsi_dcs_read <0|1> [length]); +#endif + +static const struct rt_ofw_node_id rk_dsi_ids[] = +{ + { .compatible = "rockchip,rk3568-mipi-dsi" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver rk_dsi_driver = +{ + .name = "dw-mipi-dsi-rockchip", + .ids = rk_dsi_ids, + .probe = rk_dsi_probe, +}; +RT_PLATFORM_DRIVER_EXPORT(rk_dsi_driver); diff --git a/bsp/rockchip/dm/graphic/framebuffer/dsi2-rockchip.c b/bsp/rockchip/dm/graphic/framebuffer/dsi2-rockchip.c new file mode 100644 index 000000000000..c7d0537f366b --- /dev/null +++ b/bsp/rockchip/dm/graphic/framebuffer/dsi2-rockchip.c @@ -0,0 +1,703 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-09-23 GuEe-GUI first version + */ + +#include "rockchip-display.h" + +#define DBG_TAG "dsi2.rk" +#define DBG_LVL DBG_INFO +#include + +#define UPDATE(v, h, l) (((v) << (l)) & (((2U << (h)) - 1U) & ~((1U << (l)) - 1U))) +#define GRF_REG_FIELD(reg, lsb, msb) (((reg) << 16) | ((lsb) << 8) | (msb)) + +#define DSI2_PWR_UP 0x000c +#define DSI2_SOFT_RESET 0x0010 +#define DSI2_MODE_CTRL 0x0018 +#define DSI2_MODE_STATUS 0x001c +#define DSI2_CORE_STATUS 0x0020 +#define MANUAL_MODE_CFG 0x0024 +#define DSI2_PHY_MODE_CFG 0x0100 +#define DSI2_PHY_CLK_CFG 0x0104 +#define DSI2_PHY_IPI_RATIO_MAN_CFG 0x0134 +#define DSI2_DSI_GENERAL_CFG 0x0200 +#define DSI2_DSI_VCID_CFG 0x0204 +#define DSI2_DSI_VID_TX_CFG 0x020c +#define DSI2_IPI_COLOR_MAN_CFG 0x0300 +#define DSI2_IPI_VID_HSA_MAN_CFG 0x0304 +#define DSI2_IPI_VID_HBP_MAN_CFG 0x030c +#define DSI2_IPI_VID_HACT_MAN_CFG 0x0314 +#define DSI2_IPI_VID_HLINE_MAN_CFG 0x031c +#define DSI2_IPI_VID_VSA_MAN_CFG 0x0324 +#define DSI2_IPI_VID_VBP_MAN_CFG 0x032c +#define DSI2_IPI_VID_VACT_MAN_CFG 0x0334 +#define DSI2_IPI_VID_VFP_MAN_CFG 0x033c +#define DSI2_IPI_PIX_PKT_CFG 0x0344 +#define DSI2_CRI_TX_HDR 0x02c0 +#define DSI2_CRI_TX_PLD 0x02c4 + +#define POWER_UP RT_BIT(0) +#define SYS_RSTN RT_BIT(2) +#define PHY_RSTN RT_BIT(1) +#define IPI_RSTN RT_BIT(0) +#define MANUAL_MODE_EN RT_BIT(0) +#define COMMAND_MODE 3 +#define VIDEO_MODE 4 +#define BTA_EN RT_BIT(1) +#define EOTP_TX_EN RT_BIT(0) +#define CRI_BUSY RT_BIT(16) +#define CRT_FIFOS_NOT_EMPTY RT_BIT(17) +#define PPI_WIDTH_16_BITS 1 +#define DPHY 0 +#define IPI_DEPTH_8_BITS 0x05 +#define IPI_FORMAT_RGB 0x0 +#define VID_MODE_TYPE_BURST 2 +#define CMD_TX_MODE(x) UPDATE(x, 24, 24) +#define NON_CONTINUOUS_CLK RT_BIT(0) + +#define MIPI_DSI_MODE_VIDEO RT_BIT(0) +#define MIPI_DSI_MODE_VIDEO_BURST RT_BIT(3) +#define MIPI_DSI_MODE_LPM RT_BIT(4) +#define MIPI_DSI_MODE_NO_EOT_PACKET RT_BIT(5) + +#define IPI_COLOR_DEPTH GRF_REG_FIELD(0x0028, 8, 11) +#define IPI_FORMAT GRF_REG_FIELD(0x0028, 4, 7) + +enum dsi2_grf_field +{ + GRF_IPI_COLOR_DEPTH, + GRF_IPI_FORMAT, +}; + +struct rk_dsi2 +{ + struct rt_device *dev; + void *regs; + struct rt_clk_array *clks; + struct rt_syscon *grf; + struct rt_phye *dcphy; + rt_uint32_t lanes; + rt_uint32_t channel; + rt_uint32_t mode_flags; + rt_uint64_t lane_hs_rate; + struct display_timing mode; + rt_bool_t prepared; + rt_bool_t phy_on; + rt_bool_t video_on; +}; + +static rt_err_t rk_dsi2_parse_panel_props(struct rk_dsi2 *dsi2, struct rt_ofw_node *panel_np); +static void rk_dsi2_bind_panel(struct rk_dsi2 *dsi2); + +rt_inline void dsi2_write(struct rk_dsi2 *dsi2, rt_uint32_t reg, rt_uint32_t val) +{ + HWREG32((rt_uint8_t *)dsi2->regs + reg) = val; +} + +rt_inline rt_uint32_t dsi2_read(struct rk_dsi2 *dsi2, rt_uint32_t reg) +{ + return HWREG32((rt_uint8_t *)dsi2->regs + reg); +} + +static void rk_dsi2_grf_field_write(struct rk_dsi2 *dsi2, rt_uint32_t field, rt_uint32_t val) +{ + rt_uint32_t reg = (field >> 16) & 0xffff; + rt_uint8_t lsb = (field >> 8) & 0xff; + rt_uint8_t msb = field & 0xff; + rt_uint32_t mask = RT_GENMASK(msb, lsb); + + if (!dsi2->grf || !field) + { + return; + } + + rt_syscon_write(dsi2->grf, reg, ((val << lsb) & mask) | (mask << 16)); +} + +static rt_err_t rk_dsi2_wait_mode(struct rk_dsi2 *dsi2, rt_uint32_t mode, rt_int32_t timeout_us) +{ + rt_int32_t i; + + for (i = 0; i < timeout_us; ++i) + { + if ((dsi2_read(dsi2, DSI2_MODE_STATUS) & mode) == mode) + { + return RT_EOK; + } + + rt_hw_us_delay(1); + } + + return -RT_ETIMEOUT; +} + +static rt_err_t rk_dsi2_cri_wait(struct rk_dsi2 *dsi2) +{ + rt_uint32_t sts; + rt_int32_t i; + + for (i = 0; i < 20000; ++i) + { + sts = dsi2_read(dsi2, DSI2_CORE_STATUS); + + if (!(sts & (CRI_BUSY | CRT_FIFOS_NOT_EMPTY))) + { + return RT_EOK; + } + + rt_hw_us_delay(1); + } + + return -RT_ETIMEOUT; +} + +static void rk_dsi2_set_cmd_mode(struct rk_dsi2 *dsi2) +{ + dsi2_write(dsi2, DSI2_MODE_CTRL, COMMAND_MODE); + rk_dsi2_wait_mode(dsi2, COMMAND_MODE, 10000); +} + +static void rk_dsi2_set_video_mode(struct rk_dsi2 *dsi2) +{ + dsi2_write(dsi2, DSI2_MODE_CTRL, VIDEO_MODE); + rk_dsi2_wait_mode(dsi2, VIDEO_MODE, 10000); +} + +static void dsi2_host_reset(struct rk_dsi2 *dsi2) +{ + dsi2_write(dsi2, DSI2_SOFT_RESET, 0); + rt_thread_mdelay(1); + dsi2_write(dsi2, DSI2_SOFT_RESET, SYS_RSTN | PHY_RSTN | IPI_RSTN); +} + +static void dsi2_phy_basic_cfg(struct rk_dsi2 *dsi2) +{ + rt_uint32_t val; + + val = UPDATE(PPI_WIDTH_16_BITS, 9, 8) | + UPDATE((dsi2->lanes - 1) & 0x3, 5, 4) | + UPDATE(DPHY, 0, 0); + dsi2_write(dsi2, DSI2_PHY_MODE_CFG, val); + dsi2_write(dsi2, DSI2_PHY_CLK_CFG, NON_CONTINUOUS_CLK); +} + +static void rk_dsi2_grf_ipi_cfg(struct rk_dsi2 *dsi2) +{ + rk_dsi2_grf_field_write(dsi2, IPI_COLOR_DEPTH, IPI_DEPTH_8_BITS); + rk_dsi2_grf_field_write(dsi2, IPI_FORMAT, IPI_FORMAT_RGB); +} + +static rt_uint64_t rk_dsi2_calc_lane_rate(struct rk_dsi2 *dsi2, const struct display_timing *tim) +{ + rt_uint64_t pixelclock = tim->pixelclock; + rt_uint32_t value; + rt_uint64_t tmp; + + if (!pixelclock) + { + pixelclock = (rt_uint64_t)tim->htotal * tim->vtotal * 60; + } + + if (dsi2->dev && !rt_dm_dev_prop_read_u32(dsi2->dev, "rockchip,lane-rate", &value)) + { + if (value >= 80 && value <= 4500) + { + return value; + } + } + + tmp = pixelclock * 24 / dsi2->lanes / 1000000; + + if (dsi2->mode_flags & MIPI_DSI_MODE_VIDEO_BURST) + { + tmp = tmp * 10 / 9; + } + + if (tmp < 200) + { + tmp = 500; + } + + return tmp; +} + +static void dsi2_ipi_timing(struct rk_dsi2 *dsi2, const struct display_timing *tim) +{ + rt_uint64_t pixel_clk, phy_hs_clk, tmp; + rt_uint32_t hsa_time, hbp_time, hact_time, hline_time; + + if (!tim->pixelclock) + { + return; + } + + pixel_clk = tim->pixelclock; + phy_hs_clk = dsi2->lane_hs_rate * 1000000ULL / 16ULL; + + tmp = (rt_uint64_t)tim->hsync_len * phy_hs_clk; + hsa_time = (rt_uint32_t)((tmp << 16) / pixel_clk); + dsi2_write(dsi2, DSI2_IPI_VID_HSA_MAN_CFG, hsa_time); + + tmp = (rt_uint64_t)tim->hback_porch * phy_hs_clk; + hbp_time = (rt_uint32_t)((tmp << 16) / pixel_clk); + dsi2_write(dsi2, DSI2_IPI_VID_HBP_MAN_CFG, hbp_time); + + tmp = (rt_uint64_t)tim->hactive * phy_hs_clk; + hact_time = (rt_uint32_t)((tmp << 16) / pixel_clk); + dsi2_write(dsi2, DSI2_IPI_VID_HACT_MAN_CFG, hact_time); + + tmp = (rt_uint64_t)tim->htotal * phy_hs_clk; + hline_time = (rt_uint32_t)((tmp << 16) / pixel_clk); + dsi2_write(dsi2, DSI2_IPI_VID_HLINE_MAN_CFG, hline_time); + + dsi2_write(dsi2, DSI2_IPI_VID_VSA_MAN_CFG, tim->vsync_len); + dsi2_write(dsi2, DSI2_IPI_VID_VBP_MAN_CFG, tim->vback_porch); + dsi2_write(dsi2, DSI2_IPI_VID_VACT_MAN_CFG, tim->vactive); + dsi2_write(dsi2, DSI2_IPI_VID_VFP_MAN_CFG, tim->vfront_porch); + dsi2_write(dsi2, DSI2_IPI_PIX_PKT_CFG, tim->hactive); + + tmp = ((phy_hs_clk << 16) / pixel_clk); + dsi2_write(dsi2, DSI2_PHY_IPI_RATIO_MAN_CFG, (rt_uint32_t)tmp); +} + +static rt_err_t rk_dsi2_build_packet(rt_uint8_t data_type, const rt_uint8_t *payload, + rt_size_t len, rt_uint8_t header[4], rt_uint32_t *pld) +{ + rt_size_t i; + + rt_memset(header, 0, 4); + header[0] = data_type; + + switch (data_type) + { + case 0x05: + case 0x15: + if (len >= 1) + { + header[1] = payload[0]; + } + if (len >= 2 && data_type == 0x15) + { + header[2] = payload[1]; + } + break; + case 0x23: + case 0x13: + case 0x03: + if (len >= 1) + { + header[1] = payload[0]; + } + if (len >= 2) + { + header[2] = payload[1]; + } + break; + case 0x39: + case 0x29: + header[1] = len & 0xff; + header[2] = (len >> 8) & 0xff; + *pld = 0; + for (i = 0; i < len && i < 4; ++i) + { + ((rt_uint8_t *)pld)[i] = payload[i]; + } + break; + default: + return -RT_EINVAL; + } + + return RT_EOK; +} + +static rt_err_t rk_dsi2_transfer(void *priv, rt_uint8_t data_type, rt_uint8_t delay_ms, + const rt_uint8_t *payload, rt_size_t len) +{ + struct rk_dsi2 *dsi2 = priv; + rt_uint8_t header[4]; + rt_uint32_t pld = 0; + rt_uint32_t hdr; + rt_err_t err; + rt_bool_t lpm = !!(dsi2->mode_flags & MIPI_DSI_MODE_LPM); + + if (!dsi2 || !dsi2->prepared) + { + return -RT_EINVAL; + } + + rk_dsi2_set_cmd_mode(dsi2); + + if ((err = rk_dsi2_build_packet(data_type, payload, len, header, &pld))) + { + return err; + } + + if ((err = rk_dsi2_cri_wait(dsi2))) + { + return err; + } + + if (data_type == 0x39 || data_type == 0x29) + { + rt_size_t off = 0; + rt_uint32_t val; + + while (off < len) + { + rt_size_t chunk = len - off; + + if (chunk >= 4) + { + val = payload[off] | (payload[off + 1] << 8) | + (payload[off + 2] << 16) | (payload[off + 3] << 24); + off += 4; + } + else + { + val = 0; + rt_memcpy(&val, &payload[off], chunk); + off = len; + } + + dsi2_write(dsi2, DSI2_CRI_TX_PLD, val); + } + } + + hdr = header[0] | (header[1] << 8) | (header[2] << 16) | (header[3] << 24); + dsi2_write(dsi2, DSI2_CRI_TX_HDR, CMD_TX_MODE(lpm ? 1 : 0) | hdr); + + if ((err = rk_dsi2_cri_wait(dsi2))) + { + return err; + } + + if (delay_ms) + { + rt_thread_mdelay(delay_ms); + } + + return RT_EOK; +} + +static rt_err_t rk_dsi2_phy_up(struct rk_dsi2 *dsi2) +{ + rt_err_t err; + union rt_phye_configure_opts phy_opts; + + if (!dsi2->dcphy || dsi2->phy_on) + { + return RT_EOK; + } + + if ((err = rt_phye_set_mode_simple(dsi2->dcphy, RT_PHYE_MODE_MIPI_DPHY))) + { + return err; + } + + if ((err = rt_phye_mipi_dphy_get_default_config_for_hsclk( + dsi2->lane_hs_rate * 1000000ULL, dsi2->lanes, &phy_opts.mipi_dphy))) + { + return err; + } + + if ((err = rt_phye_configure(dsi2->dcphy, &phy_opts))) + { + return err; + } + + dsi2->lane_hs_rate = phy_opts.mipi_dphy.hs_clk_rate / 1000000ULL; + + if ((err = rt_phye_init(dsi2->dcphy))) + { + return err; + } + + if ((err = rt_phye_power_on(dsi2->dcphy))) + { + rt_phye_exit(dsi2->dcphy); + return err; + } + + dsi2->phy_on = RT_TRUE; + + return RT_EOK; +} + +static void rk_dsi2_phy_down(struct rk_dsi2 *dsi2) +{ + if (!dsi2->dcphy || !dsi2->phy_on) + { + return; + } + + rt_phye_power_off(dsi2->dcphy); + rt_phye_exit(dsi2->dcphy); + dsi2->phy_on = RT_FALSE; +} + +static rt_err_t rk_dsi2_prepare(void *priv, rt_uint32_t vp_id, const struct display_timing *tim) +{ + struct rk_dsi2 *dsi2 = priv; + rt_err_t err; + + RT_UNUSED(vp_id); + + if (!dsi2 || !tim) + { + return -RT_EINVAL; + } + + dsi2->mode = *tim; + dsi2->lane_hs_rate = rk_dsi2_calc_lane_rate(dsi2, tim); + + rt_clk_array_prepare_enable(dsi2->clks); + + if ((err = rk_dsi2_phy_up(dsi2))) + { + rt_clk_array_disable_unprepare(dsi2->clks); + return err; + } + + dsi2_write(dsi2, DSI2_PWR_UP, 0); + dsi2_host_reset(dsi2); + dsi2_phy_basic_cfg(dsi2); + dsi2_write(dsi2, MANUAL_MODE_CFG, MANUAL_MODE_EN); + rk_dsi2_grf_ipi_cfg(dsi2); + rk_dsi2_set_cmd_mode(dsi2); + + dsi2->prepared = RT_TRUE; + dsi2->video_on = RT_FALSE; + + return RT_EOK; +} + +static rt_err_t rk_dsi2_mode_set(void *priv, const struct display_timing *tim) +{ + struct rk_dsi2 *dsi2 = priv; + rt_uint32_t val; + rt_uint32_t vid_mode = (dsi2->mode_flags & MIPI_DSI_MODE_VIDEO_BURST) ? + VID_MODE_TYPE_BURST : 1; + rt_uint32_t general = BTA_EN; + + if (!dsi2 || !tim) + { + return -RT_EINVAL; + } + + dsi2->mode = *tim; + + if (!dsi2->mode.pixelclock) + { + dsi2->mode.pixelclock = (rt_uint64_t)tim->htotal * tim->vtotal * 60; + } + + val = UPDATE(IPI_DEPTH_8_BITS, 7, 4) | UPDATE(IPI_FORMAT_RGB, 3, 0); + dsi2_write(dsi2, DSI2_IPI_COLOR_MAN_CFG, val); + + if (!(dsi2->mode_flags & MIPI_DSI_MODE_NO_EOT_PACKET)) + { + general |= EOTP_TX_EN; + } + + dsi2_write(dsi2, DSI2_DSI_GENERAL_CFG, general); + dsi2_write(dsi2, DSI2_DSI_VCID_CFG, dsi2->channel & 0x3); + dsi2_write(dsi2, DSI2_DSI_VID_TX_CFG, UPDATE(vid_mode, 1, 0)); + + dsi2_ipi_timing(dsi2, &dsi2->mode); + rk_dsi2_set_video_mode(dsi2); + dsi2_write(dsi2, DSI2_PWR_UP, POWER_UP); + + dsi2->video_on = RT_TRUE; + + return RT_EOK; +} + +static rt_err_t rk_dsi2_enable(void *priv, rt_bool_t enable) +{ + struct rk_dsi2 *dsi2 = priv; + + if (!dsi2) + { + return -RT_EINVAL; + } + + if (enable) + { + if (!dsi2->prepared || !dsi2->video_on) + { + return -RT_EINVAL; + } + + dsi2_write(dsi2, DSI2_PWR_UP, POWER_UP); + } + else + { + dsi2_write(dsi2, DSI2_PWR_UP, 0); + } + + return RT_EOK; +} + +static rt_err_t rk_dsi2_disable(void *priv) +{ + struct rk_dsi2 *dsi2 = priv; + + if (!dsi2) + { + return -RT_EINVAL; + } + + rk_dsi2_enable(priv, RT_FALSE); + rk_dsi2_phy_down(dsi2); + rt_clk_array_disable_unprepare(dsi2->clks); + dsi2->prepared = RT_FALSE; + dsi2->video_on = RT_FALSE; + + return RT_EOK; +} + +static const struct rockchip_connector_ops rk_dsi2_connector_ops = +{ + .prepare = rk_dsi2_prepare, + .mode_set = rk_dsi2_mode_set, + .transfer = rk_dsi2_transfer, + .enable = rk_dsi2_enable, + .disable = rk_dsi2_disable, +}; + +static rt_err_t rk_dsi2_probe(struct rt_platform_device *pdev) +{ + struct rt_device *dev = &pdev->parent; + struct rt_ofw_node *np = dev->ofw_node; + struct rk_dsi2 *dsi2 = rt_calloc(1, sizeof(*dsi2)); + + if (!dsi2) + { + return -RT_ENOMEM; + } + + dsi2->regs = rt_ofw_iomap(np, 0); + + if (!dsi2->regs) + { + rt_free(dsi2); + return -RT_EIO; + } + + dsi2->clks = rt_clk_get_array(dev); + + if (rt_is_err(dsi2->clks)) + { + rt_iounmap(dsi2->regs); + rt_free(dsi2); + return rt_ptr_err(dsi2->clks); + } + + dsi2->dev = dev; + dsi2->grf = rt_syscon_find_by_ofw_phandle(np, "rockchip,grf"); + + dsi2->lanes = 4; + dsi2->channel = 0; + rt_dm_dev_prop_read_u32(dev, "rockchip,dsi,lanes", &dsi2->lanes); + rt_dm_dev_prop_read_u32(dev, "rockchip,dsi,channel", &dsi2->channel); + + dsi2->dcphy = rt_phye_get_by_name(dev, "dcphy"); + if (rt_is_err(dsi2->dcphy)) + { + dsi2->dcphy = RT_NULL; + } + + rockchip_display_register_connector(np, &rk_dsi2_connector_ops, dsi2); + rk_dsi2_bind_panel(dsi2); + + pdev->parent.user_data = dsi2; + + LOG_D("DSI2 %s: %u lanes", np->name, dsi2->lanes); + + return RT_EOK; +} + +static rt_err_t rk_dsi2_parse_panel_props(struct rk_dsi2 *dsi2, struct rt_ofw_node *panel_np) +{ + rt_uint32_t flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | + MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_NO_EOT_PACKET; + + if (!panel_np) + { + dsi2->mode_flags = flags; + return RT_EOK; + } + + rt_ofw_prop_read_u32(panel_np, "dsi,flags", &flags); + rt_ofw_prop_read_u32(panel_np, "dsi,lanes", &dsi2->lanes); + + dsi2->mode_flags = flags; + + return RT_EOK; +} + +static void rk_dsi2_bind_panel(struct rk_dsi2 *dsi2) +{ + struct rt_ofw_node *np = dsi2->dev->ofw_node; + struct rt_ofw_node *child, *ports_np = RT_NULL, *port_np, *ep_np, *remote; + + rt_ofw_foreach_child_node(np, child) + { + if (!rt_strcmp(child->name, "ports")) + { + ports_np = child; + break; + } + } + + if (!ports_np) + { + dsi2->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | + MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_NO_EOT_PACKET; + return; + } + + rt_ofw_foreach_child_node(ports_np, port_np) + { + rt_ofw_foreach_child_node(port_np, ep_np) + { + remote = rt_ofw_parse_phandle(ep_np, "remote-endpoint", 0); + + if (!remote) + { + continue; + } + + port_np = rt_ofw_get_parent(remote); + + if (port_np) + { + rk_dsi2_parse_panel_props(dsi2, rt_ofw_get_parent(port_np)); + } + + rt_ofw_node_put(remote); + return; + } + } +} + +static const struct rt_ofw_node_id rk_dsi2_ids[] = +{ + { .compatible = "rockchip,rk3576-mipi-dsi2" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver rk_dsi2_driver = +{ + .name = "dw-mipi-dsi2-rockchip", + .ids = rk_dsi2_ids, + .probe = rk_dsi2_probe, + .remove = RT_NULL, +}; +RT_PLATFORM_DRIVER_EXPORT(rk_dsi2_driver); diff --git a/bsp/rockchip/dm/graphic/framebuffer/dw-hdmi-regs.h b/bsp/rockchip/dm/graphic/framebuffer/dw-hdmi-regs.h new file mode 100644 index 000000000000..2dc6cc3bfdde --- /dev/null +++ b/bsp/rockchip/dm/graphic/framebuffer/dw-hdmi-regs.h @@ -0,0 +1,256 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-09-23 GuEe-GUI first version + */ + +#ifndef __DW_HDMI_REGS_H__ +#define __DW_HDMI_REGS_H__ + +/* Identification and interrupt registers. */ +#define HDMI_CONFIG2_ID 0x0006 +#define HDMI_DESIGN_ID 0x0000 +#define HDMI_IH_PHY_STAT0 0x0104 +#define HDMI_IH_I2CMPHY_STAT0 0x0108 +#define HDMI_IH_MUTE_FC_STAT2 0x0182 +#define HDMI_IH_MUTE 0x01ff + +#define HDMI_IH_PHY_STAT0_HPD 0x01 +#define HDMI_IH_MUTE_FC_STAT2_OVERFLOW_MASK 0x03 +#define HDMI_IH_MUTE_MUTE_ALL_INTERRUPT 0x01 +#define HDMI_IH_MUTE_MUTE_WAKEUP_INTERRUPT 0x02 + +/* Video sampler. */ +#define HDMI_TX_INVID0 0x0200 +#define HDMI_TX_INSTUFFING 0x0201 +#define HDMI_TX_GYDATA0 0x0202 +#define HDMI_TX_GYDATA1 0x0203 +#define HDMI_TX_RCRDATA0 0x0204 +#define HDMI_TX_RCRDATA1 0x0205 +#define HDMI_TX_BCBDATA0 0x0206 +#define HDMI_TX_BCBDATA1 0x0207 + +#define HDMI_TX_INVID0_INTERNAL_DE_GENERATOR_DISABLE 0x00 +#define HDMI_TX_INVID0_VIDEO_MAPPING_OFFSET 0 +#define HDMI_TX_INSTUFFING_GYDATA_STUFFING_ENABLE 0x01 +#define HDMI_TX_INSTUFFING_RCRDATA_STUFFING_ENABLE 0x02 +#define HDMI_TX_INSTUFFING_BDBDATA_STUFFING_ENABLE 0x04 + +/* Video packetizer. */ +#define HDMI_VP_PR_CD 0x0801 +#define HDMI_VP_STUFF 0x0802 +#define HDMI_VP_REMAP 0x0803 +#define HDMI_VP_CONF 0x0804 + +#define HDMI_VP_PR_CD_COLOR_DEPTH_MASK 0xf0 +#define HDMI_VP_PR_CD_COLOR_DEPTH_OFFSET 4 +#define HDMI_VP_PR_CD_DESIRED_PR_FACTOR_MASK 0x0f +#define HDMI_VP_PR_CD_DESIRED_PR_FACTOR_OFFSET 0 +#define HDMI_VP_STUFF_IDEFAULT_PHASE_MASK 0x20 +#define HDMI_VP_STUFF_PP_STUFFING_MASK 0x02 +#define HDMI_VP_STUFF_PP_STUFFING_STUFFING_MODE 0x02 +#define HDMI_VP_STUFF_PR_STUFFING_MASK 0x01 +#define HDMI_VP_STUFF_PR_STUFFING_STUFFING_MODE 0x01 +#define HDMI_VP_STUFF_YCC422_STUFFING_MASK 0x04 +#define HDMI_VP_STUFF_YCC422_STUFFING_STUFFING_MODE 0x04 +#define HDMI_VP_CONF_BYPASS_EN_MASK 0x40 +#define HDMI_VP_CONF_BYPASS_EN_ENABLE 0x40 +#define HDMI_VP_CONF_PP_EN_ENMASK 0x20 +#define HDMI_VP_CONF_PP_EN_DISABLE 0x00 +#define HDMI_VP_CONF_PR_EN_MASK 0x10 +#define HDMI_VP_CONF_PR_EN_DISABLE 0x00 +#define HDMI_VP_CONF_YCC422_EN_MASK 0x08 +#define HDMI_VP_CONF_YCC422_EN_DISABLE 0x00 +#define HDMI_VP_CONF_BYPASS_SELECT_MASK 0x04 +#define HDMI_VP_CONF_BYPASS_SELECT_VID_PACKETIZER 0x04 +#define HDMI_VP_CONF_OUTPUT_SELECTOR_MASK 0x03 +#define HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS 0x03 + +/* Frame composer. */ +#define HDMI_FC_INVIDCONF 0x1000 +#define HDMI_FC_INHACTV0 0x1001 +#define HDMI_FC_INHACTV1 0x1002 +#define HDMI_FC_INHBLANK0 0x1003 +#define HDMI_FC_INHBLANK1 0x1004 +#define HDMI_FC_INVACTV0 0x1005 +#define HDMI_FC_INVACTV1 0x1006 +#define HDMI_FC_INVBLANK 0x1007 +#define HDMI_FC_HSYNCINDELAY0 0x1008 +#define HDMI_FC_HSYNCINDELAY1 0x1009 +#define HDMI_FC_HSYNCINWIDTH0 0x100a +#define HDMI_FC_HSYNCINWIDTH1 0x100b +#define HDMI_FC_VSYNCINDELAY 0x100c +#define HDMI_FC_VSYNCINWIDTH 0x100d +#define HDMI_FC_CTRLDUR 0x1011 +#define HDMI_FC_EXCTRLDUR 0x1012 +#define HDMI_FC_EXCTRLSPAC 0x1013 +#define HDMI_FC_CH0PREAM 0x1014 +#define HDMI_FC_CH1PREAM 0x1015 +#define HDMI_FC_CH2PREAM 0x1016 +#define HDMI_FC_AUDICONF0 0x1025 +#define HDMI_FC_AUDICONF1 0x1026 +#define HDMI_FC_AUDICONF2 0x1027 +#define HDMI_FC_AUDICONF3 0x1028 +#define HDMI_FC_AUDSCONF 0x1063 +#define HDMI_FC_AUDSCHNLS7 0x106e +#define HDMI_FC_AUDSCHNLS8 0x106f +#define HDMI_FC_DBGFORCE 0x1200 +#define HDMI_FC_DBGTMDS0 0x1219 +#define HDMI_FC_DBGTMDS1 0x121a +#define HDMI_FC_DBGTMDS2 0x121b + +#define HDMI_FC_INVIDCONF_HDCP_KEEPOUT_ACTIVE 0x80 +#define HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_ACTIVE_HIGH 0x40 +#define HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_ACTIVE_LOW 0x00 +#define HDMI_FC_INVIDCONF_HSYNC_IN_POLARITY_ACTIVE_HIGH 0x20 +#define HDMI_FC_INVIDCONF_HSYNC_IN_POLARITY_ACTIVE_LOW 0x00 +#define HDMI_FC_INVIDCONF_DE_IN_POLARITY_ACTIVE_HIGH 0x10 +#define HDMI_FC_INVIDCONF_DVI_MODEZ_HDMI_MODE 0x08 +#define HDMI_FC_INVIDCONF_DVI_MODEZ_DVI_MODE 0x00 +#define HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC_ACTIVE_LOW 0x00 +#define HDMI_FC_INVIDCONF_IN_I_P_PROGRESSIVE 0x00 +#define HDMI_FC_AUDICONF0_CC_MASK 0x70 +#define HDMI_FC_AUDICONF0_CC_OFFSET 4 +#define HDMI_FC_AUDSCONF_AUD_PACKET_LAYOUT_MASK 0x01 +#define HDMI_FC_AUDSCONF_AUD_PACKET_LAYOUT_LAYOUT0 0x00 +#define HDMI_FC_DBGFORCE_FORCEVIDEO 0x01 + +/* I2S audio sampler and audio clock regeneration. */ +#define HDMI_AUD_CONF0 0x3100 +#define HDMI_AUD_CONF1 0x3101 +#define HDMI_AUD_CONF2 0x3103 +#define HDMI_AUD_N1 0x3200 +#define HDMI_AUD_N2 0x3201 +#define HDMI_AUD_N3 0x3202 +#define HDMI_AUD_CTS1 0x3203 +#define HDMI_AUD_CTS2 0x3204 +#define HDMI_AUD_CTS3 0x3205 +#define HDMI_AUD_INPUTCLKFS 0x3206 + +#define HDMI_AUD_CONF0_SW_RESET 0x80 +#define HDMI_AUD_CONF0_I2S_SELECT 0x20 +#define HDMI_AUD_CONF0_I2S_EN0 0x01 +#define HDMI_AUD_CONF1_MODE_I2S 0x00 +#define HDMI_AUD_CONF1_WIDTH_16 0x10 +#define HDMI_AUD_CONF1_WIDTH_24 0x18 +#define HDMI_AUD_CONF2_INSERT_PCUV 0x04 +#define HDMI_AUD_CTS3_N_SHIFT_MASK 0xe0 +#define HDMI_AUD_CTS3_CTS_MANUAL 0x10 +#define HDMI_AUD_INPUTCLKFS_64FS 0x04 + +/* PHY. */ +#define HDMI_PHY_CONF0 0x3000 +#define HDMI_PHY_TST0 0x3001 +#define HDMI_PHY_STAT0 0x3004 +#define HDMI_PHY_MASK0 0x3006 + +#define HDMI_PHY_CONF0_PDZ_MASK 0x80 +#define HDMI_PHY_CONF0_PDZ_OFFSET 7 +#define HDMI_PHY_CONF0_ENTMDS_MASK 0x40 +#define HDMI_PHY_CONF0_ENTMDS_OFFSET 6 +#define HDMI_PHY_CONF0_SVSRET_MASK 0x20 +#define HDMI_PHY_CONF0_SVSRET_OFFSET 5 +#define HDMI_PHY_CONF0_GEN2_PDDQ_MASK 0x10 +#define HDMI_PHY_CONF0_GEN2_PDDQ_OFFSET 4 +#define HDMI_PHY_CONF0_GEN2_TXPWRON_MASK 0x08 +#define HDMI_PHY_CONF0_GEN2_TXPWRON_OFFSET 3 +#define HDMI_PHY_CONF0_SELDATAENPOL_MASK 0x02 +#define HDMI_PHY_CONF0_SELDATAENPOL_OFFSET 1 +#define HDMI_PHY_CONF0_SELDIPIF_MASK 0x01 +#define HDMI_PHY_CONF0_SELDIPIF_OFFSET 0 +#define HDMI_PHY_TST0_TSTCLR_MASK 0x20 +#define HDMI_PHY_TST0_TSTCLR_OFFSET 5 +#define HDMI_PHY_HPD 0x02 +#define HDMI_PHY_TX_PHY_LOCK 0x01 + +/* PHY I2C master. */ +#define HDMI_PHY_I2CM_SLAVE_ADDR 0x3020 +#define HDMI_PHY_I2CM_ADDRESS_ADDR 0x3021 +#define HDMI_PHY_I2CM_DATAO_1_ADDR 0x3022 +#define HDMI_PHY_I2CM_DATAO_0_ADDR 0x3023 +#define HDMI_PHY_I2CM_OPERATION_ADDR 0x3026 +#define HDMI_PHY_I2CM_INT_ADDR 0x3027 +#define HDMI_PHY_I2CM_CTLINT_ADDR 0x3028 + +#define HDMI_PHY_I2CM_SLAVE_ADDR_PHY_GEN2 0x69 +#define HDMI_PHY_I2CM_OPERATION_ADDR_WRITE 0x10 +#define HDMI_PHY_I2CM_INT_ADDR_DONE_POL 0x08 +#define HDMI_PHY_I2CM_CTLINT_ADDR_ARBITRATION_POL 0x08 +#define HDMI_PHY_I2CM_CTLINT_ADDR_NAC_POL 0x80 +#define HDMI_IH_I2CMPHY_STAT0_ERROR 0x01 +#define HDMI_IH_I2CMPHY_STAT0_DONE 0x02 + +/* Main controller. */ +#define HDMI_MC_CLKDIS 0x4001 +#define HDMI_MC_SWRSTZ 0x4002 +#define HDMI_MC_FLOWCTRL 0x4004 +#define HDMI_MC_PHYRSTZ 0x4005 +#define HDMI_MC_HEACPHY_RST 0x4007 + +#define HDMI_MC_CLKDIS_PIXELCLK_DISABLE 0x01 +#define HDMI_MC_CLKDIS_TMDSCLK_DISABLE 0x02 +#define HDMI_MC_CLKDIS_AUDCLK_DISABLE 0x08 +#define HDMI_MC_SWRSTZ_TMDSSWRST_REQ 0x02 +#define HDMI_MC_SWRSTZ_I2SSWRST_REQ 0x08 +#define HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_BYPASS 0x00 +#define HDMI_MC_PHYRSTZ_PHYRSTZ 0x01 +#define HDMI_MC_HEACPHY_RST_ASSERT 0x01 + +/* Color space converter. */ +#define HDMI_CSC_CFG 0x4100 +#define HDMI_CSC_SCALE 0x4101 +#define HDMI_CSC_COEF_A1_MSB 0x4102 +#define HDMI_CSC_COEF_A1_LSB 0x4103 +#define HDMI_CSC_COEF_B1_MSB 0x410a +#define HDMI_CSC_COEF_B1_LSB 0x410b +#define HDMI_CSC_COEF_C1_MSB 0x4112 +#define HDMI_CSC_COEF_C1_LSB 0x4113 + +#define HDMI_CSC_CFG_INTMODE_DISABLE 0x00 +#define HDMI_CSC_CFG_DECMODE_DISABLE 0x00 +#define HDMI_CSC_SCALE_CSC_COLORDE_PTH_MASK 0xf0 +#define HDMI_CSC_SCALE_CSC_COLORDE_PTH_24BPP 0x00 +#define HDMI_CSC_SCALE_CSCSCALE_MASK 0x03 + +/* HDCP polarity and HDMI/DVI selection. */ +#define HDMI_A_HDCPCFG0 0x5000 +#define HDMI_A_VIDPOLCFG 0x5009 + +#define HDMI_A_HDCPCFG0_AVMUTE_MASK 0x08 +#define HDMI_A_HDCPCFG0_AVMUTE_DISABLE 0x00 +#define HDMI_A_HDCPCFG0_HDMIDVI_MASK 0x01 +#define HDMI_A_HDCPCFG0_HDMIDVI_HDMI 0x01 +#define HDMI_A_HDCPCFG0_HDMIDVI_DVI 0x00 +#define HDMI_A_VIDPOLCFG_DATAENPOL_MASK 0x10 +#define HDMI_A_VIDPOLCFG_DATAENPOL_ACTIVE_HIGH 0x10 +#define HDMI_A_VIDPOLCFG_VSYNCPOL_MASK 0x08 +#define HDMI_A_VIDPOLCFG_VSYNCPOL_ACTIVE_HIGH 0x08 +#define HDMI_A_VIDPOLCFG_VSYNCPOL_ACTIVE_LOW 0x00 +#define HDMI_A_VIDPOLCFG_HSYNCPOL_MASK 0x02 +#define HDMI_A_VIDPOLCFG_HSYNCPOL_ACTIVE_HIGH 0x02 +#define HDMI_A_VIDPOLCFG_HSYNCPOL_ACTIVE_LOW 0x00 + +/* DDC I2C interrupt control. */ +#define HDMI_I2CM_INT 0x7e05 +#define HDMI_I2CM_CTLINT 0x7e06 +#define HDMI_I2CM_INT_DONE_MASK 0x04 +#define HDMI_I2CM_CTLINT_ARB_MASK 0x04 +#define HDMI_I2CM_CTLINT_NAC_MASK 0x40 + +/* Synopsys Gen2 PHY internal register addresses. */ +#define HDMI_3D_TX_PHY_CKCALCTRL 0x05 +#define HDMI_3D_TX_PHY_CPCE_CTRL 0x06 +#define HDMI_3D_TX_PHY_CKSYMTXCTRL 0x09 +#define HDMI_3D_TX_PHY_VLEVCTRL 0x0e +#define HDMI_3D_TX_PHY_CURRCTRL 0x10 +#define HDMI_3D_TX_PHY_PLLPHBYCTRL 0x13 +#define HDMI_3D_TX_PHY_GMPCTRL 0x15 +#define HDMI_3D_TX_PHY_MSM_CTRL 0x17 +#define HDMI_3D_TX_PHY_TXTERM 0x19 +#define HDMI_3D_TX_PHY_MSM_CTRL_CKO_SEL_FB_CLK (3 << 1) + +#endif /* __DW_HDMI_REGS_H__ */ diff --git a/bsp/rockchip/dm/graphic/framebuffer/fb-vop1.c b/bsp/rockchip/dm/graphic/framebuffer/fb-vop1.c new file mode 100644 index 000000000000..d5391e869615 --- /dev/null +++ b/bsp/rockchip/dm/graphic/framebuffer/fb-vop1.c @@ -0,0 +1,1113 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-09-23 GuEe-GUI first version + */ + +#include "fb-vop1.h" + +#include + +#define DBG_TAG "fb.vop1" +#define DBG_LVL DBG_INFO +#include + +/* RK3366 Lite (rk3308 / rk3506 / px30-lit class) */ +#define VOP1_LIT_CFG_DONE 0x000 +#define VOP1_LIT_WIN0_CTRL0 0x050 +#define VOP1_LIT_WIN0_VIR 0x05c +#define VOP1_LIT_WIN0_YRGB_MST 0x060 +#define VOP1_LIT_WIN0_ACT_INFO 0x068 +#define VOP1_LIT_WIN0_DSP_INFO 0x06c +#define VOP1_LIT_WIN0_DSP_ST 0x070 +#define VOP1_LIT_WIN0_ALPHA 0x080 +#define VOP1_LIT_WIN1_CTRL0 0x090 +#define VOP1_LIT_WIN1_VIR 0x098 +#define VOP1_LIT_WIN1_MST 0x0a0 +#define VOP1_LIT_WIN1_DSP_INFO 0x0a4 +#define VOP1_LIT_WIN1_DSP_ST 0x0a8 +#define VOP1_LIT_WIN1_ALPHA 0x0bc + +/* RK3288-class big VOP (rk3328 / rk3288 / rk3399) */ +#define VOP1_BIG_CFG_DONE 0x000 + +#define VOP1_WIN_EN_MASK 1 +#define VOP1_WIN_EN_SHIFT 0 +#define VOP1_WIN_FORMAT_MASK 0x7 +#define VOP1_WIN_FORMAT_SHIFT 1 + +/* -------------------------------------------------------------------------- */ +/* Lite window maps */ +/* -------------------------------------------------------------------------- */ + +static const struct vop1fb_win_regs lite_win0_regs = +{ + .ctrl0 = VOP1_LIT_WIN0_CTRL0, + .vir = VOP1_LIT_WIN0_VIR, + .yrgb_mst = VOP1_LIT_WIN0_YRGB_MST, + .act_info = VOP1_LIT_WIN0_ACT_INFO, + .dsp_info = VOP1_LIT_WIN0_DSP_INFO, + .dsp_st = VOP1_LIT_WIN0_DSP_ST, + .alpha = VOP1_LIT_WIN0_ALPHA, +}; + +static const struct vop1fb_win_regs lite_win1_regs = +{ + .ctrl0 = VOP1_LIT_WIN1_CTRL0, + .vir = VOP1_LIT_WIN1_VIR, + .yrgb_mst = VOP1_LIT_WIN1_MST, + .dsp_info = VOP1_LIT_WIN1_DSP_INFO, + .dsp_st = VOP1_LIT_WIN1_DSP_ST, + .alpha = VOP1_LIT_WIN1_ALPHA, +}; + +static const struct vop1fb_win_desc lite_primary = +{ + .name = "Win0", + .regs = &lite_win0_regs, + .z_order = 1, +}; + +static const struct vop1fb_win_desc lite_cursor = +{ + .name = "Win1", + .regs = &lite_win1_regs, + .z_order = 2, +}; + +/* -------------------------------------------------------------------------- */ +/* Big window maps (win-relative offsets from each win base) */ +/* -------------------------------------------------------------------------- */ + +#define VOP1_BIG_WIN_CTRL0 0x00 +#define VOP1_BIG_WIN_VIR 0x0c +#define VOP1_BIG_WIN_YRGB_MST 0x10 +#define VOP1_BIG_WIN_ACT_INFO 0x18 +#define VOP1_BIG_WIN_DSP_INFO 0x1c +#define VOP1_BIG_WIN_DSP_ST 0x20 +#define VOP1_BIG_WIN_ALPHA 0x30 + +static const struct vop1fb_win_regs big_win0_regs = +{ + .ctrl0 = 0xd0 + VOP1_BIG_WIN_CTRL0, + .vir = 0xd0 + VOP1_BIG_WIN_VIR, + .yrgb_mst = 0xd0 + VOP1_BIG_WIN_YRGB_MST, + .act_info = 0xd0 + VOP1_BIG_WIN_ACT_INFO, + .dsp_info = 0xd0 + VOP1_BIG_WIN_DSP_INFO, + .dsp_st = 0xd0 + VOP1_BIG_WIN_DSP_ST, + .alpha = 0xd0 + VOP1_BIG_WIN_ALPHA, +}; + +static const struct vop1fb_win_regs big_win1_regs = +{ + .ctrl0 = 0x1d0 + VOP1_BIG_WIN_CTRL0, + .vir = 0x1d0 + VOP1_BIG_WIN_VIR, + .yrgb_mst = 0x1d0 + VOP1_BIG_WIN_YRGB_MST, + .act_info = 0x1d0 + VOP1_BIG_WIN_ACT_INFO, + .dsp_info = 0x1d0 + VOP1_BIG_WIN_DSP_INFO, + .dsp_st = 0x1d0 + VOP1_BIG_WIN_DSP_ST, + .alpha = 0x1d0 + VOP1_BIG_WIN_ALPHA, +}; + +static const struct vop1fb_win_regs big_win2_regs = +{ + .ctrl0 = 0x2d0 + VOP1_BIG_WIN_CTRL0, + .vir = 0x2d0 + VOP1_BIG_WIN_VIR, + .yrgb_mst = 0x2d0 + VOP1_BIG_WIN_YRGB_MST, + .act_info = 0x2d0 + VOP1_BIG_WIN_ACT_INFO, + .dsp_info = 0x2d0 + VOP1_BIG_WIN_DSP_INFO, + .dsp_st = 0x2d0 + VOP1_BIG_WIN_DSP_ST, + .alpha = 0x2d0 + VOP1_BIG_WIN_ALPHA, +}; + +static const struct vop1fb_win_desc big_primary = +{ + .name = "Win0", + .regs = &big_win0_regs, + .z_order = 1, +}; + +static const struct vop1fb_win_desc big_cursor = +{ + .name = "Win2", + .regs = &big_win2_regs, + .z_order = 3, +}; + +static const struct vop1fb_win_desc big_overlays[] = +{ + { + .name = "Win1", + .regs = &big_win1_regs, + .z_order = 2, + }, +}; + +static const struct vop1fb_soc_data vop1_lite_soc = +{ + .arch = VOP1FB_ARCH_LITE, + .version = "vop1-lite", + .reg_size = 0x200, + .cfg_done = VOP1_LIT_CFG_DONE, + .primary = &lite_primary, + .cursor = &lite_cursor, + .overlay_count = 0, +}; + +static const struct vop1fb_soc_data vop1_big_soc = +{ + .arch = VOP1FB_ARCH_BIG, + .version = "vop1-big", + .reg_size = 0x400, + .cfg_done = VOP1_BIG_CFG_DONE, + .primary = &big_primary, + .cursor = &big_cursor, + .overlays = big_overlays, + .overlay_count = RT_ARRAY_SIZE(big_overlays), +}; + +static rt_uint32_t vop1fb_modes[] = +{ + RTGRAPHIC_PIXEL_FORMAT_ARGB888, + RTGRAPHIC_PIXEL_FORMAT_RGB888, + RTGRAPHIC_PIXEL_FORMAT_RGB565, +}; + +/* -------------------------------------------------------------------------- */ +/* Helpers */ +/* -------------------------------------------------------------------------- */ + +rt_uint32_t vop1fb_mode_to_hw(rt_uint32_t mode) +{ + switch (mode) + { + case RTGRAPHIC_PIXEL_FORMAT_ARGB888: + case RTGRAPHIC_PIXEL_FORMAT_ABGR888: + return VOP1FB_FMT_ARGB8888; + case RTGRAPHIC_PIXEL_FORMAT_RGB888: + case RTGRAPHIC_PIXEL_FORMAT_BGR888: + return VOP1FB_FMT_RGB888; + case RTGRAPHIC_PIXEL_FORMAT_RGB565: + case RTGRAPHIC_PIXEL_FORMAT_BGR565: + return VOP1FB_FMT_RGB565; + default: + return VOP1FB_FMT_ARGB8888; + } +} + +rt_uint32_t vop1fb_hw_to_bpp(rt_uint32_t hw_fmt) +{ + switch (hw_fmt) + { + case VOP1FB_FMT_RGB565: + return 16; + case VOP1FB_FMT_RGB888: + return 24; + default: + return 32; + } +} + +static struct vop1fb *vop1fb_from_plane(struct rt_graphic_plane *plane) +{ + return rt_container_of(plane->graphic, struct vop1fb, parent); +} + +static struct vop1fb_plane_priv *vop1fb_plane_priv(struct rt_graphic_plane *plane) +{ + return (struct vop1fb_plane_priv *)plane->priv; +} + +rt_inline void vop1fb_reg_write(struct vop1fb *vfb, rt_uint32_t offset, rt_uint32_t v) +{ + HWREG32((rt_uint8_t *)vfb->regs + offset) = v; +} + +rt_inline void vop1fb_mask_write(struct vop1fb *vfb, rt_uint32_t offset, + rt_uint32_t mask, rt_uint32_t shift, rt_uint32_t v) +{ + rt_uint32_t cached = HWREG32((rt_uint8_t *)vfb->regs + offset); + rt_uint32_t newv = (cached & ~(mask << shift)) | ((v & mask) << shift); + + vop1fb_reg_write(vfb, offset, newv); +} + +static rt_uint32_t vop1fb_xvir(rt_uint32_t width, rt_uint32_t bpp) +{ + return RT_ALIGN(width * bpp, 32) >> 5; +} + +static void vop1fb_cfg_done(struct vop1fb *vfb) +{ + vop1fb_reg_write(vfb, vfb->soc->cfg_done, 1); +} + +static void vop1fb_win_disable(struct vop1fb *vfb, const struct vop1fb_win_desc *desc) +{ + const struct vop1fb_win_regs *r = desc->regs; + + vop1fb_mask_write(vfb, r->ctrl0, VOP1_WIN_EN_MASK, VOP1_WIN_EN_SHIFT, 0); + vop1fb_cfg_done(vfb); +} + +static void vop1fb_win_alpha(struct vop1fb *vfb, const struct vop1fb_win_desc *desc, + rt_uint8_t alpha) +{ + const struct vop1fb_win_regs *r = desc->regs; + + if (!r->alpha) + { + return; + } + + /* alpha_en | alpha_mode | global_alpha */ + vop1fb_reg_write(vfb, r->alpha, RT_BIT(0) | RT_BIT(1) | ((rt_uint32_t)alpha << 4)); +} + +static rt_err_t vop1fb_win_commit(struct vop1fb *vfb, const struct vop1fb_win_desc *desc, + rt_ubase_t dma_addr, rt_uint32_t hw_fmt, + rt_uint32_t src_w, rt_uint32_t src_h, + rt_uint32_t dst_x, rt_uint32_t dst_y, + rt_uint32_t dst_w, rt_uint32_t dst_h, + rt_uint32_t xvir, rt_bool_t enable, rt_uint8_t alpha) +{ + const struct vop1fb_win_regs *r = desc->regs; + rt_uint32_t act_info, dsp_info, dsp_st; + rt_uint32_t fmt_shift = VOP1_WIN_FORMAT_SHIFT; + + if (!enable) + { + vop1fb_win_disable(vfb, desc); + return RT_EOK; + } + + if (vfb->soc->arch == VOP1FB_ARCH_LITE && desc != vfb->soc->primary) + { + fmt_shift = 4; + } + + act_info = ((src_h - 1) << 16) | ((src_w - 1) & 0xffff); + dsp_info = ((dst_h - 1) << 16) | ((dst_w - 1) & 0xffff); + dsp_st = (dst_y << 16) | (dst_x & 0xffff); + + vop1fb_mask_write(vfb, r->ctrl0, VOP1_WIN_FORMAT_MASK, fmt_shift, hw_fmt); + + if (r->vir) + { + vop1fb_reg_write(vfb, r->vir, xvir); + } + + vop1fb_reg_write(vfb, r->yrgb_mst, (rt_uint32_t)dma_addr); + + if (r->act_info) + { + vop1fb_reg_write(vfb, r->act_info, act_info); + } + + vop1fb_reg_write(vfb, r->dsp_info, dsp_info); + vop1fb_reg_write(vfb, r->dsp_st, dsp_st); + vop1fb_win_alpha(vfb, desc, alpha); + vop1fb_mask_write(vfb, r->ctrl0, VOP1_WIN_EN_MASK, VOP1_WIN_EN_SHIFT, 1); + vop1fb_cfg_done(vfb); + + return RT_EOK; +} + +static rt_err_t vop1fb_plane_commit(struct rt_graphic_plane *plane, rt_bool_t enable) +{ + struct vop1fb *vfb = vop1fb_from_plane(plane); + struct vop1fb_plane_priv *priv = vop1fb_plane_priv(plane); + rt_uint32_t bpp = rt_graphic_mode_bpp(plane->mode); + rt_uint32_t xvir; + rt_ubase_t dma; + rt_uint32_t dst_w, dst_h, dst_x, dst_y; + + if (!priv || !priv->desc) + { + return -RT_EINVAL; + } + + if (!enable || !plane->framebuffer) + { + priv->enabled = RT_FALSE; + vop1fb_win_disable(vfb, priv->desc); + return RT_EOK; + } + + dma = priv->dma_handle + priv->pan_offset; + xvir = vop1fb_xvir(plane->width, bpp); + + if (plane->type == RT_GRAPHIC_PLANE_TYPE_PRIMARY) + { + dst_x = 0; + dst_y = 0; + dst_w = plane->width; + dst_h = plane->height; + } + else + { + dst_x = plane->x; + dst_y = plane->y; + dst_w = plane->width; + dst_h = plane->height; + } + + priv->enabled = RT_TRUE; + + return vop1fb_win_commit(vfb, priv->desc, dma, vop1fb_mode_to_hw(plane->mode), + plane->width, plane->height, dst_x, dst_y, dst_w, dst_h, xvir, RT_TRUE, + plane->alpha ? plane->alpha : 0xff); +} + +static void vop1fb_plane_free_fb(struct rt_graphic_plane *plane) +{ + struct vop1fb *vfb = vop1fb_from_plane(plane); + struct vop1fb_plane_priv *priv = vop1fb_plane_priv(plane); + struct rt_device *dev = &vfb->parent.parent; + + if (plane->framebuffer) + { + rt_dma_free_coherent(dev, plane->framebuffer_len, + plane->framebuffer, priv->dma_handle); + plane->framebuffer = RT_NULL; + plane->framebuffer_len = 0; + plane->screen_len = 0; + priv->dma_handle = 0; + priv->pan_offset = 0; + } +} + +static rt_err_t vop1fb_plane_update(struct rt_graphic_plane *plane, + struct rt_device_rect_info *rect) +{ + struct vop1fb_plane_priv *priv = vop1fb_plane_priv(plane); + + RT_UNUSED(rect); + + if (priv) + { + priv->enabled = RT_TRUE; + } + + return vop1fb_plane_commit(plane, RT_TRUE); +} + +static rt_err_t vop1fb_plane_fb_remap(struct rt_graphic_plane *plane, + rt_uint32_t mode, struct rt_device_rect_info *rect) +{ + rt_err_t err; + struct vop1fb *vfb = vop1fb_from_plane(plane); + struct vop1fb_plane_priv *priv = vop1fb_plane_priv(plane); + struct rt_device *dev = &vfb->parent.parent; + rt_uint32_t bpp = rt_graphic_mode_bpp(mode); + rt_size_t screen_len, fb_len; + void *fb; + + if (!rect->width || !rect->height || !bpp) + { + return -RT_EINVAL; + } + + vop1fb_plane_free_fb(plane); + + plane->line_length = RT_ALIGN(rect->width * bpp, 32) / 8; + plane->bits_per_pixel = bpp; + screen_len = plane->line_length * rect->height; + + if (plane->type == RT_GRAPHIC_PLANE_TYPE_PRIMARY) + { + fb_len = screen_len * 2; + } + else + { + fb_len = screen_len; + } + + fb = rt_dma_alloc_coherent(dev, fb_len, &priv->dma_handle); + + if (!fb) + { + return -RT_ENOMEM; + } + + rt_memset(fb, 0, fb_len); + + plane->framebuffer = fb; + plane->screen_len = screen_len; + plane->framebuffer_len = fb_len; + plane->width = rect->width; + plane->height = rect->height; + plane->mode = mode; + priv->pan_offset = 0; + + if (vfb->powered && plane->type == RT_GRAPHIC_PLANE_TYPE_PRIMARY) + { + err = vop1fb_plane_commit(plane, RT_TRUE); + } + else + { + err = RT_EOK; + } + + return err; +} + +static rt_err_t vop1fb_plane_fb_pan_display(struct rt_graphic_plane *plane, + struct rt_device_rect_info *rect) +{ + struct vop1fb_plane_priv *priv = vop1fb_plane_priv(plane); + + if (rect->width != plane->width || rect->height != plane->height) + { + return vop1fb_plane_fb_remap(plane, plane->mode, rect); + } + + if (plane->framebuffer_len <= plane->screen_len) + { + plane->x = rect->x; + plane->y = rect->y; + return RT_EOK; + } + + priv->pan_offset = rect->y * plane->line_length + rect->x * (plane->bits_per_pixel / 8); + + if (priv->pan_offset + plane->screen_len > plane->framebuffer_len) + { + priv->pan_offset = 0; + return -RT_EINVAL; + } + + plane->x = rect->x; + plane->y = rect->y; + + return vop1fb_plane_commit(plane, RT_TRUE); +} + +static rt_err_t vop1fb_plane_fb_cleanup(struct rt_graphic_plane *plane) +{ + struct vop1fb *vfb = vop1fb_from_plane(plane); + struct vop1fb_plane_priv *priv = vop1fb_plane_priv(plane); + + if (priv && priv->enabled && priv->desc) + { + vop1fb_win_disable(vfb, priv->desc); + priv->enabled = RT_FALSE; + } + + vop1fb_plane_free_fb(plane); + + return RT_EOK; +} + +static rt_err_t vop1fb_plane_prop_set(struct rt_graphic_plane *plane, + enum rt_graphic_plane_prop prop, void *value) +{ + struct vop1fb *vfb = vop1fb_from_plane(plane); + struct vop1fb_plane_priv *priv = vop1fb_plane_priv(plane); + + if (!priv || !priv->desc) + { + return -RT_EINVAL; + } + + switch (prop) + { + case RT_GRAPHIC_PLANE_PROP_Z: + if (value) + { + plane->z = (rt_uint32_t)(rt_ubase_t)value; + } + return RT_EOK; + + case RT_GRAPHIC_PLANE_PROP_ALPHA: + if (value) + { + plane->alpha = (rt_uint8_t)(rt_ubase_t)value; + vop1fb_win_alpha(vfb, priv->desc, plane->alpha); + vop1fb_cfg_done(vfb); + } + return RT_EOK; + + default: + return -RT_ENOSYS; + } +} + +static const struct rt_graphic_plane_ops vop1fb_primary_ops = +{ + .update = vop1fb_plane_update, + .fb_remap = vop1fb_plane_fb_remap, + .fb_pan_display = vop1fb_plane_fb_pan_display, + .fb_cleanup = vop1fb_plane_fb_cleanup, + .prop_set = vop1fb_plane_prop_set, +}; + +static const struct rt_graphic_plane_ops vop1fb_overlay_ops = +{ + .update = vop1fb_plane_update, + .fb_remap = vop1fb_plane_fb_remap, + .fb_cleanup = vop1fb_plane_fb_cleanup, + .prop_set = vop1fb_plane_prop_set, +}; + +static const struct rt_graphic_plane_ops vop1fb_cursor_ops = +{ + .update = vop1fb_plane_update, + .fb_remap = vop1fb_plane_fb_remap, + .fb_cleanup = vop1fb_plane_fb_cleanup, + .prop_set = vop1fb_plane_prop_set, +}; + +static rt_err_t vop1fb_clk_enable(struct vop1fb *vfb) +{ + if (!vfb->clk_enabled && !rt_is_err_or_null(vfb->clks)) + { + rt_clk_array_prepare_enable(vfb->clks); + vfb->clk_enabled = RT_TRUE; + } + + return RT_EOK; +} + +static void vop1fb_clk_disable(struct vop1fb *vfb) +{ + if (vfb->clk_enabled && !rt_is_err_or_null(vfb->clks)) + { + rt_clk_array_disable_unprepare(vfb->clks); + vfb->clk_enabled = RT_FALSE; + } +} + +static rt_err_t vop1fb_dpms_switch(struct rt_graphic_device *gdev, rt_uint32_t dpms) +{ + struct vop1fb *vfb = rt_container_of(gdev, struct vop1fb, parent); + rt_size_t i; + + switch (dpms) + { + case RT_GRAPHIC_DPMS_ON: + vop1fb_clk_enable(vfb); + vfb->powered = RT_TRUE; + + if (vfb->primary && vfb->primary->framebuffer) + { + vop1fb_plane_commit(vfb->primary, RT_TRUE); + } + + for (i = 0; i < vfb->overlay_count; ++i) + { + struct rt_graphic_plane *plane = vfb->overlays[i]; + struct vop1fb_plane_priv *priv; + + if (!plane || !plane->framebuffer) + { + continue; + } + + priv = vop1fb_plane_priv(plane); + + if (priv && priv->enabled) + { + vop1fb_plane_commit(plane, RT_TRUE); + } + } + + if (vfb->cursor && vfb->cursor->framebuffer) + { + struct vop1fb_plane_priv *priv = vop1fb_plane_priv(vfb->cursor); + + if (priv && priv->enabled) + { + vop1fb_plane_commit(vfb->cursor, RT_TRUE); + } + } + + rt_graphic_device_update_auto(gdev, RT_GRAPHIC_UPDATE_MS); + break; + + case RT_GRAPHIC_DPMS_STANDBY: + case RT_GRAPHIC_DPMS_SUSPEND: + rt_graphic_device_update_auto(gdev, 0); + + if (vfb->primary) + { + vop1fb_plane_commit(vfb->primary, RT_FALSE); + } + + for (i = 0; i < vfb->overlay_count; ++i) + { + if (vfb->overlays[i]) + { + vop1fb_plane_commit(vfb->overlays[i], RT_FALSE); + } + } + + if (vfb->cursor) + { + vop1fb_plane_commit(vfb->cursor, RT_FALSE); + } + break; + + case RT_GRAPHIC_DPMS_OFF: + rt_graphic_device_update_auto(gdev, 0); + + if (vfb->primary) + { + vop1fb_plane_commit(vfb->primary, RT_FALSE); + } + + for (i = 0; i < vfb->overlay_count; ++i) + { + if (vfb->overlays[i]) + { + vop1fb_plane_commit(vfb->overlays[i], RT_FALSE); + } + } + + if (vfb->cursor) + { + vop1fb_plane_commit(vfb->cursor, RT_FALSE); + } + + vop1fb_clk_disable(vfb); + vfb->powered = RT_FALSE; + break; + + default: + return -RT_EINVAL; + } + + gdev->dpms = dpms; + + return RT_EOK; +} + +static rt_err_t vop1fb_wait_vsync(struct rt_graphic_device *gdev) +{ + struct vop1fb *vfb = rt_container_of(gdev, struct vop1fb, parent); + + if (vfb->irq >= 0) + { + rt_atomic_store(&vfb->vsync, 0); + + if (rt_sem_take(&vfb->vsync_sem, rt_tick_from_millisecond(100)) == RT_EOK) + { + return RT_EOK; + } + } + + rt_thread_mdelay(16); + + return RT_EOK; +} + +static const struct rt_graphic_device_ops vop1fb_ops = +{ + .dpms_switch = vop1fb_dpms_switch, + .wait_vsync = vop1fb_wait_vsync, +}; + +static void vop1fb_isr(int irqno, void *param) +{ + struct vop1fb *vfb = param; + + RT_UNUSED(irqno); + + rt_atomic_store(&vfb->vsync, 1); + rt_sem_release(&vfb->vsync_sem); +} + +static void vop1fb_plane_init_fb_state(struct rt_graphic_plane *plane, rt_uint32_t mode) +{ + rt_uint32_t bpp = rt_graphic_mode_bpp(mode); + + plane->mode = mode; + plane->bits_per_pixel = bpp; + plane->line_length = RT_ALIGN(plane->width * bpp, 32) / 8; + plane->screen_len = plane->line_length * plane->height; + plane->framebuffer = RT_NULL; + plane->framebuffer_len = 0; +} + +static rt_err_t vop1fb_plane_init(struct vop1fb *vfb, + struct rt_graphic_plane *plane, + const struct vop1fb_win_desc *desc, + rt_uint32_t width, rt_uint32_t height, + rt_uint8_t type) +{ + struct vop1fb_plane_priv *priv = vop1fb_plane_priv(plane); + + priv->desc = desc; + priv->enabled = RT_FALSE; + priv->pan_offset = 0; + plane->z = desc->z_order; + plane->alpha = 0xff; + + if (type == RT_GRAPHIC_PLANE_TYPE_CURSOR) + { + plane->width = VOP1FB_CURSOR_W; + plane->height = VOP1FB_CURSOR_H; + } + else if (type == RT_GRAPHIC_PLANE_TYPE_OVERLAY) + { + plane->width = width / 4; + plane->height = height / 4; + plane->x = plane->width; + plane->y = plane->height; + } + else + { + plane->width = width; + plane->height = height; + } + + vop1fb_plane_init_fb_state(plane, RTGRAPHIC_PIXEL_FORMAT_ARGB888); + + return RT_EOK; +} + +static rt_err_t vop1fb_primary_plane_create(struct vop1fb *vfb, + rt_uint32_t width, rt_uint32_t height) +{ + rt_err_t err; + struct rt_graphic_plane *plane; + + plane = rt_graphic_device_alloc_plane(&vfb->parent, sizeof(struct vop1fb_plane_priv), + &vop1fb_primary_ops, vop1fb_modes, RT_ARRAY_SIZE(vop1fb_modes), + RT_GRAPHIC_PLANE_TYPE_PRIMARY); + + if (!plane) + { + return -RT_ENOMEM; + } + + if ((err = rt_graphic_device_add_plane(&vfb->parent, plane))) + { + rt_graphic_device_free_plane(plane); + return err; + } + + vfb->primary = plane; + + err = vop1fb_plane_init(vfb, plane, vfb->soc->primary, width, height, + RT_GRAPHIC_PLANE_TYPE_PRIMARY); + if (err) + { + vfb->primary = RT_NULL; + vfb->parent.primary_plane = RT_NULL; + rt_graphic_device_free_plane(plane); + } + + return err; +} + +static rt_err_t vop1fb_overlay_planes_create(struct vop1fb *vfb, + rt_uint32_t width, rt_uint32_t height) +{ + rt_err_t err; + rt_size_t i; + struct rt_graphic_plane *plane; + + for (i = 0; i < vfb->overlay_count; ++i) + { + plane = rt_graphic_device_alloc_plane(&vfb->parent, sizeof(struct vop1fb_plane_priv), + &vop1fb_overlay_ops, vop1fb_modes, RT_ARRAY_SIZE(vop1fb_modes), + RT_GRAPHIC_PLANE_TYPE_OVERLAY); + + if (!plane) + { + return -RT_ENOMEM; + } + + rt_snprintf(plane->name, sizeof(plane->name), "ovl-%s", vfb->soc->overlays[i].name); + + if ((err = rt_graphic_device_add_plane(&vfb->parent, plane))) + { + rt_graphic_device_free_plane(plane); + return err; + } + + vfb->overlays[i] = plane; + + if ((err = vop1fb_plane_init(vfb, plane, &vfb->soc->overlays[i], + width, height, RT_GRAPHIC_PLANE_TYPE_OVERLAY))) + { + return err; + } + } + + return RT_EOK; +} + +static rt_err_t vop1fb_cursor_plane_create(struct vop1fb *vfb, + rt_uint32_t width, rt_uint32_t height) +{ + rt_err_t err; + struct rt_graphic_plane *plane; + + plane = rt_graphic_device_alloc_plane(&vfb->parent, sizeof(struct vop1fb_plane_priv), + &vop1fb_cursor_ops, vop1fb_modes, RT_ARRAY_SIZE(vop1fb_modes), + RT_GRAPHIC_PLANE_TYPE_CURSOR); + + if (!plane) + { + return -RT_ENOMEM; + } + + if ((err = rt_graphic_device_add_plane(&vfb->parent, plane))) + { + rt_graphic_device_free_plane(plane); + return err; + } + + vfb->cursor = plane; + + return vop1fb_plane_init(vfb, plane, vfb->soc->cursor, width, height, + RT_GRAPHIC_PLANE_TYPE_CURSOR); +} + +static const struct vop1fb_soc_data *vop1fb_soc_from_id(const struct rt_ofw_node_id *id) +{ + if (!id || !id->compatible) + { + return RT_NULL; + } + + /* Lite VOP */ + if (!rt_strcmp(id->compatible, "rockchip,rk3308-vop") || + !rt_strcmp(id->compatible, "rockchip,rk3506-vop") || + !rt_strcmp(id->compatible, "rockchip,px30-vop-lit")) + { + return &vop1_lite_soc; + } + + /* Big VOP */ + if (!rt_strcmp(id->compatible, "rockchip,rk3328-vop") || + !rt_strcmp(id->compatible, "rockchip,rk3288-vop-big") || + !rt_strcmp(id->compatible, "rockchip,rk3288-vop-lit") || + !rt_strcmp(id->compatible, "rockchip,rk3399-vop-big") || + !rt_strcmp(id->compatible, "rockchip,rk3399-vop-lit") || + !rt_strcmp(id->compatible, "rockchip,rk3368-vop") || + !rt_strcmp(id->compatible, "rockchip,rk3366-vop") || + !rt_strcmp(id->compatible, "rockchip,rk3228-vop") || + !rt_strcmp(id->compatible, "rockchip,rv1126-vop") || + !rt_strcmp(id->compatible, "rockchip,rv1126b-vop") || + !rt_strcmp(id->compatible, "rockchip,rv1106-vop")) + { + return &vop1_big_soc; + } + + return RT_NULL; +} + +static rt_err_t vop1fb_parse_display(struct vop1fb *vfb, struct rt_platform_device *pdev) +{ + struct rt_device *dev = &pdev->parent; + + vfb->display_w = 1920; + vfb->display_h = 1080; + + rt_dm_dev_prop_read_u32(dev, "rockchip,fb-width", &vfb->display_w); + rt_dm_dev_prop_read_u32(dev, "rockchip,fb-height", &vfb->display_h); + + if (!vfb->display_w || !vfb->display_h) + { + return -RT_EINVAL; + } + + return RT_EOK; +} + +static rt_err_t vop1fb_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + struct rt_device *dev = &pdev->parent; + struct vop1fb *vfb = rt_calloc(1, sizeof(*vfb)); + + if (!vfb) + { + return -RT_ENOMEM; + } + + vfb->soc = vop1fb_soc_from_id(pdev->id); + + if (!vfb->soc) + { + err = -RT_ENOSYS; + goto _fail; + } + + if ((err = vop1fb_parse_display(vfb, pdev))) + { + goto _fail; + } + + vfb->regs = rt_ofw_iomap(dev->ofw_node, 0); + + if (!vfb->regs) + { + err = -RT_EIO; + goto _fail; + } + + vfb->clks = rt_clk_get_array(dev); + + if (rt_is_err(vfb->clks)) + { + err = rt_ptr_err(vfb->clks); + goto _fail_unmap; + } + + vfb->irq = rt_dm_dev_get_irq(dev, 0); + + if (vfb->irq >= 0) + { + rt_sem_init(&vfb->vsync_sem, "vop1-vsync", 0, RT_IPC_FLAG_FIFO); + rt_hw_interrupt_install(vfb->irq, vop1fb_isr, vfb, "vop1"); + rt_hw_interrupt_umask(vfb->irq); + } + + vfb->parent.ops = &vop1fb_ops; + + if ((err = vop1fb_clk_enable(vfb))) + { + goto _fail_irq; + } + + vfb->powered = RT_TRUE; + + vfb->overlay_count = rt_min_t(rt_size_t, vfb->soc->overlay_count, VOP1FB_OVERLAY_MAX); + + if ((err = vop1fb_primary_plane_create(vfb, vfb->display_w, vfb->display_h))) + { + LOG_E("%s: create primary plane failed: %s", rt_dm_dev_get_name(dev), rt_strerror(err)); + goto _fail_clk; + } + + rt_graphic_device_simple_edid(&vfb->parent, vfb->display_w, vfb->display_h, 60); + + if ((err = rt_graphic_device_register(&vfb->parent))) + { + rt_graphic_device_del_plane(&vfb->parent, vfb->primary); + rt_graphic_device_free_plane(vfb->primary); + vfb->primary = RT_NULL; + goto _fail_clk; + } + + if ((err = vop1fb_overlay_planes_create(vfb, vfb->display_w, vfb->display_h))) + { + LOG_E("%s: create overlay planes failed: %s", rt_dm_dev_get_name(dev), rt_strerror(err)); + goto _fail_graphic; + } + + if ((err = vop1fb_cursor_plane_create(vfb, vfb->display_w, vfb->display_h))) + { + LOG_E("%s: create cursor plane failed: %s", rt_dm_dev_get_name(dev), rt_strerror(err)); + goto _fail_graphic; + } + + vop1fb_dpms_switch(&vfb->parent, RT_GRAPHIC_DPMS_ON); + + pdev->parent.user_data = vfb; + + LOG_I("VOP1 %s (%s): %ux%u, primary=%s, %u overlays, cursor=%s", + vfb->soc->version, pdev->id->compatible, + vfb->display_w, vfb->display_h, + vfb->soc->primary->name, (unsigned)vfb->overlay_count, + vfb->soc->cursor->name); + + return RT_EOK; + +_fail_graphic: + rt_graphic_device_unregister(&vfb->parent); +_fail_clk: + vop1fb_clk_disable(vfb); +_fail_irq: + if (vfb->irq >= 0) + { + rt_hw_interrupt_mask(vfb->irq); + rt_sem_detach(&vfb->vsync_sem); + } + + if (!rt_is_err_or_null(vfb->clks)) + { + rt_clk_array_put(vfb->clks); + } + +_fail_unmap: + if (vfb->regs) + { + rt_iounmap(vfb->regs); + } +_fail: + rt_free(vfb); + + return err; +} + +static rt_err_t vop1fb_remove(struct rt_platform_device *pdev) +{ + struct vop1fb *vfb = pdev->parent.user_data; + + if (!vfb) + { + return RT_EOK; + } + + rt_graphic_device_unregister(&vfb->parent); + + vop1fb_dpms_switch(&vfb->parent, RT_GRAPHIC_DPMS_OFF); + + if (vfb->irq >= 0) + { + rt_hw_interrupt_mask(vfb->irq); + rt_sem_detach(&vfb->vsync_sem); + } + + if (!rt_is_err_or_null(vfb->clks)) + { + rt_clk_array_put(vfb->clks); + } + + rt_iounmap(vfb->regs); + rt_free(vfb); + + pdev->parent.user_data = RT_NULL; + + return RT_EOK; +} + +static const struct rt_ofw_node_id vop1_ofw_ids[] = +{ + /* Lite */ + { .compatible = "rockchip,rk3308-vop" }, + { .compatible = "rockchip,rk3506-vop" }, + { .compatible = "rockchip,px30-vop-lit" }, + /* Big */ + { .compatible = "rockchip,rk3328-vop" }, + { .compatible = "rockchip,rk3288-vop-big" }, + { .compatible = "rockchip,rk3288-vop-lit" }, + { .compatible = "rockchip,rk3399-vop-big" }, + { .compatible = "rockchip,rk3399-vop-lit" }, + { .compatible = "rockchip,rk3368-vop" }, + { .compatible = "rockchip,rk3366-vop" }, + { .compatible = "rockchip,rk3228-vop" }, + { .compatible = "rockchip,rv1126-vop" }, + { .compatible = "rockchip,rv1126b-vop" }, + { .compatible = "rockchip,rv1106-vop" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver vop1_driver = +{ + .name = "vop1-framebuffer", + .ids = vop1_ofw_ids, + + .probe = vop1fb_probe, + .remove = vop1fb_remove, +}; +RT_PLATFORM_DRIVER_EXPORT(vop1_driver); diff --git a/bsp/rockchip/dm/graphic/framebuffer/fb-vop1.h b/bsp/rockchip/dm/graphic/framebuffer/fb-vop1.h new file mode 100644 index 000000000000..bd147b82189b --- /dev/null +++ b/bsp/rockchip/dm/graphic/framebuffer/fb-vop1.h @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-09-23 GuEe-GUI first version + */ + +#ifndef __FB_VOP1_H__ +#define __FB_VOP1_H__ + +#include +#include +#include + +#define VOP1FB_CURSOR_W 64 +#define VOP1FB_CURSOR_H 64 +#define VOP1FB_OVERLAY_MAX 2 + +enum vop1fb_arch +{ + VOP1FB_ARCH_LITE = 0, + VOP1FB_ARCH_BIG, +}; + +enum vop1fb_hw_format +{ + VOP1FB_FMT_ARGB8888 = 0, + VOP1FB_FMT_RGB888, + VOP1FB_FMT_RGB565, +}; + +struct vop1fb_win_regs +{ + rt_uint32_t ctrl0; + rt_uint32_t vir; + rt_uint32_t yrgb_mst; + rt_uint32_t act_info; + rt_uint32_t dsp_info; + rt_uint32_t dsp_st; + rt_uint32_t alpha; +}; + +struct vop1fb_win_desc +{ + const char *name; + const struct vop1fb_win_regs *regs; + rt_uint8_t z_order; +}; + +struct vop1fb_soc_data +{ + enum vop1fb_arch arch; + const char *version; + rt_size_t reg_size; + rt_uint32_t cfg_done; + const struct vop1fb_win_desc *primary; + const struct vop1fb_win_desc *cursor; + const struct vop1fb_win_desc *overlays; + rt_size_t overlay_count; +}; + +struct vop1fb_plane_priv +{ + const struct vop1fb_win_desc *desc; + rt_ubase_t dma_handle; + rt_uint32_t pan_offset; + rt_bool_t enabled; +}; + +struct vop1fb +{ + struct rt_graphic_device parent; + + const struct vop1fb_soc_data *soc; + + void *regs; + rt_uint32_t display_w; + rt_uint32_t display_h; + + rt_bool_t clk_enabled; + struct rt_clk_array *clks; + + int irq; + rt_atomic_t vsync; + struct rt_semaphore vsync_sem; + + struct rt_graphic_plane *primary; + struct rt_graphic_plane *cursor; + struct rt_graphic_plane *overlays[VOP1FB_OVERLAY_MAX]; + rt_size_t overlay_count; + + rt_bool_t powered; +}; + +rt_uint32_t vop1fb_mode_to_hw(rt_uint32_t mode); +rt_uint32_t vop1fb_hw_to_bpp(rt_uint32_t hw_fmt); + +#endif /* __FB_VOP1_H__ */ diff --git a/bsp/rockchip/dm/graphic/framebuffer/fb-vop2-vp.c b/bsp/rockchip/dm/graphic/framebuffer/fb-vop2-vp.c new file mode 100644 index 000000000000..139d94a4cf32 --- /dev/null +++ b/bsp/rockchip/dm/graphic/framebuffer/fb-vop2-vp.c @@ -0,0 +1,1142 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-09-23 GuEe-GUI first version + */ + +#include "fb-vop2-vp.h" + +#define DBG_TAG "fb.vop2.vp" +#define DBG_LVL DBG_INFO +#include + +#define VOP2_CLUSTER0_MIX_SRC_ALPHA 0x618 +#define VOP2_MIX0_SRC_ALPHA 0x658 +#define VOP2_MIX_ALPHA_STRIDE 0x8 + +#define VOP2_VP_CLK_CTRL 0xC0C +#define VOP2_PLL_LIMIT_HZ 594000000UL +#define RK3568_NR_MIXERS 5 + +static rt_uint16_t vop2fb_scl_cal_scale2(rt_uint32_t src, rt_uint32_t dst) +{ + if (src <= 1 || dst <= 1) + { + return 0x1000; + } + + return (rt_uint16_t)(((src - 1) << 12) / (dst - 1)); +} + +static rt_uint8_t vop2fb_rk3576_pixel_rate(rt_uint32_t vp_id) +{ + return vp_id == 0 ? 2 : 1; +} + +static void vop2fb_reg_field(struct vop2fb *vfb, rt_uint32_t offset, + rt_uint32_t mask, rt_uint32_t shift, rt_uint32_t v) +{ + rt_uint32_t regv = HWREG32((rt_uint8_t *)vfb->regs + offset); + + regv &= ~(mask << shift); + regv |= (v & mask) << shift; + vop2fb_reg_write(vfb, offset, regv); +} + +static rt_uint32_t vop2fb_output_pol(const struct display_timing *tim) +{ + rt_uint32_t pol = 0; + + if (!tim) + { + return 0; + } + + if (tim->flags & DISPLAY_TIMING_F_PHSYNC) + { + pol |= RK3568_HSYNC_POSITIVE; + } + + if (tim->flags & DISPLAY_TIMING_F_PVSYNC) + { + pol |= RK3568_VSYNC_POSITIVE; + } + + return pol; +} + +static rt_uint32_t vop2fb_vp_out_mode(struct vop2fb *vfb) +{ + if (!vfb || !vfb->soc) + { + return RK3576_VP_OUT_MODE_P888; + } + + /* + * Keep RK3568 HDMI aligned with Linux/U-Boot: RGB888 over HDMI uses + * OUT_MODE_AAAA instead of plain P888. + */ + if (vfb->soc->soc == VOP2FB_SOC_RK3568 && + vfb->output_if == VOP2FB_OUTPUT_HDMI) + { + return RK3568_VP_OUT_MODE_AAAA; + } + + return RK3576_VP_OUT_MODE_P888; +} + +static void vop2fb_rk3568_disable_outputs(struct vop2fb *vfb) +{ + vop2fb_mask_write(vfb, RK3568_DSP_IF_EN, 1, RK3568_RGB_EN_SHIFT, 0); + vop2fb_mask_write(vfb, RK3568_DSP_IF_EN, 1, RK3568_HDMI0_EN_SHIFT, 0); + vop2fb_mask_write(vfb, RK3568_DSP_IF_EN, 1, RK3568_EDP0_EN_SHIFT, 0); + vop2fb_mask_write(vfb, RK3568_DSP_IF_EN, 1, RK3568_MIPI0_EN_SHIFT, 0); + vop2fb_mask_write(vfb, RK3568_DSP_IF_EN, 1, RK3568_LVDS0_EN_SHIFT, 0); + vop2fb_mask_write(vfb, RK3568_DSP_IF_EN, 1, RK3568_MIPI1_EN_SHIFT, 0); + vop2fb_mask_write(vfb, RK3568_DSP_IF_EN, 1, RK3568_LVDS1_EN_SHIFT, 0); +} + +void vop2fb_output_disable(struct vop2fb *vfb, enum vop2fb_output_if output_if) +{ + rt_uint32_t shift; + + if (!vfb || !vfb->soc || vfb->soc->soc != VOP2FB_SOC_RK3568) + { + return; + } + + switch (output_if) + { + case VOP2FB_OUTPUT_HDMI: + shift = RK3568_HDMI0_EN_SHIFT; + break; + case VOP2FB_OUTPUT_EDP: + shift = RK3568_EDP0_EN_SHIFT; + break; + case VOP2FB_OUTPUT_MIPI0: + shift = RK3568_MIPI0_EN_SHIFT; + break; + case VOP2FB_OUTPUT_MIPI1: + shift = RK3568_MIPI1_EN_SHIFT; + break; + case VOP2FB_OUTPUT_LVDS: + shift = RK3568_LVDS0_EN_SHIFT; + break; + case VOP2FB_OUTPUT_RGB: + shift = RK3568_RGB_EN_SHIFT; + break; + default: + return; + } + + vop2fb_mask_write(vfb, RK3568_DSP_IF_EN, 1, shift, 0); +} + +static void vop2fb_rk3568_if_cfg(struct vop2fb *vfb, rt_uint32_t vp_id, + const struct display_timing *tim) +{ + rt_uint32_t dclk_inv, pol; + + if (!vfb || !tim || vfb->soc->soc != VOP2FB_SOC_RK3568) + { + return; + } + + pol = vop2fb_output_pol(tim); + dclk_inv = !!(tim->flags & DISPLAY_TIMING_F_PIXDATA_NEGEDGE); + + /* + * Clear inherited bootloader routing for the first configured VP only. + * Later mode sets must preserve already-running outputs (for example + * HDMI0 on VP0 while MIPI1 is attached to VP1). + */ + if (!vfb->configured_vp_mask) + { + vop2fb_rk3568_disable_outputs(vfb); + } + vop2fb_mask_write(vfb, RK3568_DSP_IF_POL, 1, + RK3568_IF_CTRL_REG_DONE_IMD_SHIFT, 1); + + switch (vfb->output_if) + { + case VOP2FB_OUTPUT_HDMI: + vop2fb_mask_write(vfb, RK3568_DSP_IF_EN, 1, RK3568_HDMI0_EN_SHIFT, 1); + vop2fb_mask_write(vfb, RK3568_DSP_IF_EN, RK3568_IF_MUX_MASK, + RK3568_HDMI0_MUX_SHIFT, vp_id); + vop2fb_mask_write(vfb, RK3568_DSP_IF_POL, 1, + RK3568_IF_CRTL_HDMI_DCLK_POL_SHIFT, 1); + vop2fb_mask_write(vfb, RK3568_DSP_IF_POL, RK3568_IF_PIN_POL_MASK, + RK3568_IF_CRTL_HDMI_PIN_POL_SHIFT, pol); + break; + + case VOP2FB_OUTPUT_EDP: + vop2fb_mask_write(vfb, RK3568_DSP_IF_EN, 1, RK3568_EDP0_EN_SHIFT, 1); + vop2fb_mask_write(vfb, RK3568_DSP_IF_EN, RK3568_IF_MUX_MASK, + RK3568_EDP0_MUX_SHIFT, vp_id); + vop2fb_mask_write(vfb, RK3568_DSP_IF_POL, 1, + RK3568_IF_CRTL_EDP_DCLK_POL_SHIFT, 1); + vop2fb_mask_write(vfb, RK3568_DSP_IF_POL, RK3568_IF_PIN_POL_MASK, + RK3568_IF_CTRL_EDP_PIN_POL_SHIFT, pol); + break; + + case VOP2FB_OUTPUT_MIPI0: + vop2fb_mask_write(vfb, RK3568_DSP_IF_EN, 1, RK3568_MIPI0_EN_SHIFT, 1); + vop2fb_mask_write(vfb, RK3568_DSP_IF_EN, RK3568_IF_MUX_MASK, + RK3568_MIPI0_MUX_SHIFT, vp_id); + vop2fb_mask_write(vfb, RK3568_DSP_IF_POL, 1, + RK3568_IF_CRTL_MIPI_DCLK_POL_SHIFT, dclk_inv); + vop2fb_mask_write(vfb, RK3568_DSP_IF_POL, RK3568_IF_PIN_POL_MASK, + RK3568_IF_CTRL_MIPI_PIN_POL_SHIFT, pol); + break; + + case VOP2FB_OUTPUT_MIPI1: + vop2fb_mask_write(vfb, RK3568_DSP_IF_EN, 1, RK3568_MIPI1_EN_SHIFT, 1); + vop2fb_mask_write(vfb, RK3568_DSP_IF_EN, RK3568_IF_MUX_MASK, + RK3568_MIPI1_MUX_SHIFT, vp_id); + vop2fb_mask_write(vfb, RK3568_DSP_IF_POL, 1, + RK3568_IF_CRTL_MIPI_DCLK_POL_SHIFT, dclk_inv); + vop2fb_mask_write(vfb, RK3568_DSP_IF_POL, RK3568_IF_PIN_POL_MASK, + RK3568_IF_CTRL_MIPI_PIN_POL_SHIFT, pol); + break; + + case VOP2FB_OUTPUT_LVDS: + vop2fb_mask_write(vfb, RK3568_DSP_IF_EN, 1, RK3568_LVDS0_EN_SHIFT, 1); + vop2fb_mask_write(vfb, RK3568_DSP_IF_EN, RK3568_IF_MUX_MASK, + RK3568_LVDS0_MUX_SHIFT, vp_id); + vop2fb_mask_write(vfb, RK3568_DSP_IF_POL, RK3568_IF_PIN_POL_MASK, + RK3568_IF_CTRL_RGB_PIN_POL_SHIFT, pol); + break; + + case VOP2FB_OUTPUT_RGB: + vop2fb_mask_write(vfb, RK3568_DSP_IF_EN, 1, RK3568_RGB_EN_SHIFT, 1); + vop2fb_mask_write(vfb, RK3568_DSP_IF_EN, RK3568_IF_MUX_MASK, + RK3568_RGB_MUX_SHIFT, vp_id); + vop2fb_mask_write(vfb, RK3568_DSP_IF_POL, RK3568_IF_PIN_POL_MASK, + RK3568_IF_CTRL_RGB_PIN_POL_SHIFT, pol); + break; + + default: + break; + } +} + +void vop2fb_vp_irq_ctrl(struct vop2fb *vfb, rt_uint32_t vp_id, rt_bool_t enable) +{ + rt_uint32_t axi_irq = RK3568_SYS_BUS_ERROR_INTR; + rt_uint32_t clear_irqs = VOP2_VP_FS_FIELD_INTR | + VOP2_VP_POST_BUF_EMPTY_INTR; + rt_uint32_t enable_irqs = VOP2_VP_FS_FIELD_INTR; + + if (!vfb || vfb->soc->soc != VOP2FB_SOC_RK3568 || vp_id >= vfb->soc->vp_count) + { + return; + } + + HWREG32((rt_uint8_t *)vfb->regs + RK3568_VP_INT_CLR(vp_id)) = + (clear_irqs << 16) | clear_irqs; + HWREG32((rt_uint8_t *)vfb->regs + RK3568_SYS0_INT_CLR) = axi_irq << 16 | axi_irq; + HWREG32((rt_uint8_t *)vfb->regs + RK3568_SYS1_INT_CLR) = axi_irq << 16 | axi_irq; + + if (enable) + { + /* + * POST_BUF_EMPTY is diagnostic-only in Linux and may generate an + * interrupt storm while no plane is scanning out. RT has no Linux + * recovery workqueue, so keep it masked and use FS_FIELD for vsync. + */ + HWREG32((rt_uint8_t *)vfb->regs + RK3568_VP_INT_EN(vp_id)) = + (clear_irqs << 16) | enable_irqs; + HWREG32((rt_uint8_t *)vfb->regs + RK3568_SYS0_INT_EN) = axi_irq << 16 | axi_irq; + HWREG32((rt_uint8_t *)vfb->regs + RK3568_SYS1_INT_EN) = axi_irq << 16 | axi_irq; + } + else + { + HWREG32((rt_uint8_t *)vfb->regs + RK3568_VP_INT_EN(vp_id)) = + clear_irqs << 16; + HWREG32((rt_uint8_t *)vfb->regs + RK3568_SYS0_INT_EN) = axi_irq << 16; + HWREG32((rt_uint8_t *)vfb->regs + RK3568_SYS1_INT_EN) = axi_irq << 16; + } +} + +static void vop2fb_rk3568_dither_setup(struct vop2fb *vfb, rt_uint32_t vp_id) +{ + rt_uint32_t base; + rt_bool_t pre_dither_down_en; + + if (!vfb || !vfb->regs || !vfb->soc || vfb->soc->soc != VOP2FB_SOC_RK3568) + { + return; + } + + /* + * The current RT display stack only drives 24-bit RGB style outputs on + * RK3568. Match Linux/U-Boot and keep pre-dither enabled so VP0_DSP_CTRL + * aligns with the working Linux value (for HDMI 1280x720p60 this is + * 0x0001000f instead of 0x0000000f). + */ + pre_dither_down_en = vfb->output_if != VOP2FB_OUTPUT_NONE; + base = VOP2_VP_DSP_CTRL + vp_id * VOP2FB_VP_STRIDE; + + vop2fb_mask_write(vfb, base, 1, VOP2_VP_PRE_DITHER_DOWN_EN_SHIFT, + pre_dither_down_en ? 1 : 0); + vop2fb_mask_write(vfb, base, 1, VOP2_VP_DITHER_DOWN_EN_SHIFT, 0); +} + +#if DBG_LVL >= DBG_LOG +static void vop2fb_rk3568_dump_route_regs(struct vop2fb *vfb, rt_uint32_t vp_id) +{ + rt_uint32_t base; + + if (!vfb || !vfb->regs || !vfb->soc || vfb->soc->soc != VOP2FB_SOC_RK3568) + { + return; + } + + base = VOP2_VP_DSP_CTRL + vp_id * VOP2FB_VP_STRIDE; + + LOG_D("VP%u route regs: IF_EN=0x%08x IF_POL=0x%08x OVL_SEL=0x%08x OVL_PORT=0x%08x OVL_CTRL=0x%08x DSP_CTRL=0x%08x DSP_BG=0x%08x", + vp_id, + HWREG32((rt_uint8_t *)vfb->regs + RK3568_DSP_IF_EN), + HWREG32((rt_uint8_t *)vfb->regs + RK3568_DSP_IF_POL), + HWREG32((rt_uint8_t *)vfb->regs + VOP2_OVL_LAYER_SEL), + HWREG32((rt_uint8_t *)vfb->regs + VOP2_OVL_PORT_SEL), + HWREG32((rt_uint8_t *)vfb->regs + VOP2_OVL_CTRL), + HWREG32((rt_uint8_t *)vfb->regs + base), + HWREG32((rt_uint8_t *)vfb->regs + base + (VOP2_VP_DSP_BG - VOP2_VP_DSP_CTRL))); +} +#endif /* DBG_LVL >= DBG_LOG */ + +static rt_uint32_t vop2fb_rk3568_pre_scan_max_dly(rt_uint32_t vp_id) +{ + switch (vp_id) + { + case 0: + return 42; + case 1: + case 2: + return 40; + default: + return 40; + } +} + +static rt_uint32_t vop2fb_rk3568_bg_ovl_dly(struct vop2fb *vfb, rt_uint32_t vp_id) +{ + rt_uint32_t port_mux; + + if (!vfb || !vfb->regs) + { + return 0; + } + + port_mux = (HWREG32((rt_uint8_t *)vfb->regs + VOP2_OVL_PORT_SEL) >> (vp_id * 4)) & 0xf; + + if (port_mux >= RK3568_NR_MIXERS) + { + return 0; + } + + return (RK3568_NR_MIXERS - port_mux) << 1; +} + +rt_err_t vop2fb_vp_post_config(struct vop2fb *vfb, rt_uint32_t vp_id, + const struct display_timing *tim) +{ + rt_uint32_t hdisplay_round2; + rt_uint32_t hsync_len; + rt_uint32_t hact_st; + rt_uint32_t hact_end; + rt_uint32_t vact_st; + rt_uint32_t vact_end; + rt_uint32_t hsync_start; + rt_uint32_t vsync_start; + rt_uint32_t hscale; + rt_uint32_t vscale; + rt_uint32_t bg_dly; + rt_uint32_t bg_ovl_dly; + rt_uint32_t pre_scan_dly; + + if (!vfb || !tim || !vfb->regs || !vfb->soc || + vfb->soc->soc != VOP2FB_SOC_RK3568) + { + return RT_EOK; + } + + hdisplay_round2 = (tim->hactive + 1) & ~1u; + hsync_len = tim->hsync_len ? tim->hsync_len : 1; + bg_dly = vop2fb_rk3568_pre_scan_max_dly(vp_id); + bg_ovl_dly = vop2fb_rk3568_bg_ovl_dly(vfb, vp_id); + + if (bg_dly > bg_ovl_dly) + { + bg_dly -= bg_ovl_dly; + } + else + { + bg_dly = 0; + } + + pre_scan_dly = bg_dly + (hdisplay_round2 >> 1) - 1; + hsync_start = tim->hactive + tim->hfront_porch; + vsync_start = tim->vactive + tim->vfront_porch; + hact_st = tim->htotal - hsync_start; + hact_end = hact_st + tim->hactive; + vact_st = tim->vtotal - vsync_start; + vact_end = vact_st + tim->vactive; + hscale = vop2fb_scl_cal_scale2(tim->hactive, tim->hactive); + vscale = vop2fb_scl_cal_scale2(tim->vactive, tim->vactive); + + vop2fb_mask_write(vfb, RK3568_VP0_BG_MIX_CTRL + vp_id * 4, + RK3568_BG_MIX_CTRL_MASK, RK3568_BG_MIX_CTRL_SHIFT, bg_dly); + vop2fb_reg_write(vfb, VOP2_VP_DSP_BG + vp_id * VOP2FB_VP_STRIDE, 0); + vop2fb_reg_write(vfb, RK3568_VP0_POST_DSP_HACT_INFO + vp_id * VOP2FB_VP_STRIDE, + (hact_st << 16) | hact_end); + vop2fb_reg_write(vfb, RK3568_VP0_POST_DSP_VACT_INFO + vp_id * VOP2FB_VP_STRIDE, + (vact_st << 16) | vact_end); + vop2fb_reg_write(vfb, RK3568_VP0_POST_SCL_FACTOR_YRGB + vp_id * VOP2FB_VP_STRIDE, + (vscale << 16) | hscale); + vop2fb_mask_write(vfb, RK3568_VP0_POST_SCL_CTRL + vp_id * VOP2FB_VP_STRIDE, + 1, RK3568_POST_HORIZONTAL_SCALEDOWN_EN_SHIFT, 0); + vop2fb_mask_write(vfb, RK3568_VP0_POST_SCL_CTRL + vp_id * VOP2FB_VP_STRIDE, + 1, RK3568_POST_VERTICAL_SCALEDOWN_EN_SHIFT, 0); + vop2fb_reg_write(vfb, RK3568_VP0_PRE_SCAN_HTIMING + vp_id * VOP2FB_VP_STRIDE, + (pre_scan_dly << 16) | hsync_len); + vop2fb_reg_write(vfb, VOP2_REG_CFG_DONE, + vop2fb_cfg_done_vp_val(vfb, vp_id)); + +#if DBG_LVL >= DBG_LOG + LOG_D("VP%u post cfg: port_mux=%u bg_ovl_dly=%u bg_dly=%u PRE_SCAN=0x%08x BG_MIX=0x%08x", + vp_id, + (HWREG32((rt_uint8_t *)vfb->regs + VOP2_OVL_PORT_SEL) >> (vp_id * 4)) & 0xf, + bg_ovl_dly, bg_dly, + HWREG32((rt_uint8_t *)vfb->regs + RK3568_VP0_PRE_SCAN_HTIMING + + vp_id * VOP2FB_VP_STRIDE), + HWREG32((rt_uint8_t *)vfb->regs + RK3568_VP0_BG_MIX_CTRL + vp_id * 4)); + LOG_D("VP%u post regs: HACT=0x%08x VACT=0x%08x SCL=0x%08x SCL_CTRL=0x%08x DSP_BG=0x%08x", + vp_id, + HWREG32((rt_uint8_t *)vfb->regs + RK3568_VP0_POST_DSP_HACT_INFO + + vp_id * VOP2FB_VP_STRIDE), + HWREG32((rt_uint8_t *)vfb->regs + RK3568_VP0_POST_DSP_VACT_INFO + + vp_id * VOP2FB_VP_STRIDE), + HWREG32((rt_uint8_t *)vfb->regs + RK3568_VP0_POST_SCL_FACTOR_YRGB + + vp_id * VOP2FB_VP_STRIDE), + HWREG32((rt_uint8_t *)vfb->regs + RK3568_VP0_POST_SCL_CTRL + + vp_id * VOP2FB_VP_STRIDE), + HWREG32((rt_uint8_t *)vfb->regs + VOP2_VP_DSP_BG + vp_id * VOP2FB_VP_STRIDE)); +#endif /* DBG_LVL >= DBG_LOG */ + + return RT_EOK; +} + +static rt_err_t vop2fb_vp_dclk_set_rate(struct vop2fb *vfb, rt_uint32_t vp_id, rt_ubase_t rate) +{ + struct rt_device *dev = &vfb->parent.parent; + char name[20]; + struct rt_clk *dclk, *src, *parent, *pll; + rt_err_t err; + rt_ubase_t actual_rate, pll_rate; + rt_uint32_t div; + + rt_snprintf(name, sizeof(name), "dclk_vp%u", vp_id); + dclk = rt_clk_get_by_name(dev, name); + + if (rt_is_err_or_null(dclk)) + { + rt_snprintf(name, sizeof(name), "dclk_vop%u", vp_id); + dclk = rt_clk_get_by_name(dev, name); + } + + if (rt_is_err_or_null(dclk)) + { + LOG_W("VP%u dclk not found", vp_id); + return RT_EOK; + } + + /* + * RK3568 feeds the DW-HDMI PHY reference clock directly from HPLL. + * Keep HPLL and dclk_vop0 at the same pixel rate. A divided 594 MHz HPLL + * produces the requested VOP dclk but leaves the PHY reference unstable. + */ + parent = rt_clk_get_parent(dclk); + + if (vfb->soc->soc == VOP2FB_SOC_RK3568 && + vfb->output_if == VOP2FB_OUTPUT_HDMI && + parent && parent->cell && parent->cell->name && + !rt_strcmp(parent->cell->name, "hpll")) + { + if ((err = rt_clk_set_rate(parent, rate))) + { + LOG_W("VP%u hpll set %lu failed: %s", + vp_id, rate, rt_strerror(err)); + goto _put_parent; + } + + if ((err = rt_clk_set_rate(dclk, rate))) + { + LOG_W("VP%u dclk set %lu failed: %s", + vp_id, rate, rt_strerror(err)); + goto _put_parent; + } + + actual_rate = rt_clk_get_rate(dclk); + if (!actual_rate || + (actual_rate > rate ? actual_rate - rate : rate - actual_rate) > + rate / 1000) + { + LOG_E("VP%u dclk mismatch: req %lu actual %lu parent=hpll rate=%lu", + vp_id, rate, actual_rate, rt_clk_get_rate(parent)); + err = -RT_EIO; + goto _put_parent; + } + + LOG_D("VP%u dclk: req %lu actual %lu parent=hpll rate=%lu", + vp_id, rate, actual_rate, rt_clk_get_rate(parent)); + rt_clk_put(parent); + rt_clk_put(dclk); + return RT_EOK; + } + + /* + * RK3568 dclk_vop[0-2] are direct mux/div clocks. For non-HDMI + * outputs the device tree selects VPLL so it can be retuned to an + * integer multiple of the requested pixel clock. Merely changing the + * divider leaves the boot-time 594 MHz VPLL in place (70 MHz then + * becomes 66 MHz), while the DSI host still computes its line timers + * from 70 MHz. + */ + if (vfb->soc->soc == VOP2FB_SOC_RK3568 && + parent && parent->cell && parent->cell->name && + !rt_strcmp(parent->cell->name, "vpll")) + { + pll_rate = rt_clk_get_rate(parent); + + if (pll_rate < VOP2_PLL_LIMIT_HZ || (pll_rate % rate) != 0) + { + div = (rt_uint32_t)RT_DIV_ROUND_UP(VOP2_PLL_LIMIT_HZ, rate); + + if (div & 1) + { + div++; + } + + pll_rate = rate * div; + if ((err = rt_clk_set_rate(parent, pll_rate))) + { + LOG_W("VP%u vpll set %lu failed: %s", + vp_id, pll_rate, rt_strerror(err)); + goto _put_parent; + } + } + + if ((err = rt_clk_set_rate(dclk, rate))) + { + LOG_W("VP%u dclk set %lu failed: %s", + vp_id, rate, rt_strerror(err)); + goto _put_parent; + } + + if (rt_clk_get_rate(dclk) != rate) + { + LOG_W("VP%u dclk mismatch: req %lu actual %lu parent=vpll rate=%lu", + vp_id, rate, rt_clk_get_rate(dclk), rt_clk_get_rate(parent)); + err = -RT_EIO; + goto _put_parent; + } + + LOG_D("VP%u dclk: req %lu actual %lu parent=vpll rate=%lu", + vp_id, rate, rt_clk_get_rate(dclk), rt_clk_get_rate(parent)); + rt_clk_put(parent); + rt_clk_put(dclk); + return RT_EOK; + } + + if (parent) + { + rt_clk_put(parent); + parent = RT_NULL; + } + + rt_snprintf(name, sizeof(name), "dclk_src_vp%u", vp_id); + src = rt_clk_get_by_name(dev, name); + + if (rt_is_err_or_null(src)) + { + rt_snprintf(name, sizeof(name), "dclk_vop_src%u", vp_id); + src = rt_clk_get_by_name(dev, name); + } + + pll = RT_NULL; + + if (src) + { + parent = rt_clk_get_parent(src); + + if (parent) + { + pll = rt_clk_get_parent(parent); + } + } + + if (pll && pll->cell && pll->cell->name && !rt_strcmp(pll->cell->name, "vpll")) + { + pll_rate = rt_clk_get_rate(pll); + + if (pll_rate >= VOP2_PLL_LIMIT_HZ && (pll_rate % rate) == 0) + { + rt_clk_set_rate(dclk, rate); + } + else + { + div = (rt_uint32_t)((VOP2_PLL_LIMIT_HZ + rate - 1) / rate); + + if (div & 1) + { + div++; + } + + rt_clk_set_rate(pll, rate * div); + rt_clk_set_rate(dclk, rate); + } + } + else + { + rt_clk_set_rate(dclk, rate); + } + + LOG_D("VP%u dclk: req %lu actual %lu", vp_id, rate, rt_clk_get_rate(dclk)); + + if (src) + { + rt_clk_put(src); + } + + rt_clk_put(dclk); + + return RT_EOK; + +_put_parent: + if (parent) + { + rt_clk_put(parent); + } + rt_clk_put(dclk); + + return err; +} + +static rt_err_t vop2fb_rk3576_cru_cfg(struct vop2fb *vfb, rt_uint32_t vp_id, + const struct display_timing *tim) +{ + rt_uint64_t pixclk = tim->pixelclock; + rt_uint8_t port_pix_rate = vop2fb_rk3576_pixel_rate(vp_id); + rt_uint32_t clk_ctrl = VOP2_VP_CLK_CTRL + vp_id * VOP2FB_VP_STRIDE; + rt_ubase_t crtc_hz, dclk_in, dclk_core; + rt_uint32_t post_dclk_core_sel, post_dclk_out_sel; + rt_uint32_t interface_dclk_sel, interface_pix_clk_sel; + rt_uint32_t mipi_val; + + if (!pixclk) + { + pixclk = (rt_uint64_t)tim->htotal * tim->vtotal * 60; + } + + crtc_hz = (rt_ubase_t)pixclk; + dclk_in = crtc_hz; + dclk_core = crtc_hz / port_pix_rate; + + post_dclk_core_sel = dclk_in > dclk_core ? 1 : 0; + post_dclk_out_sel = 0; + interface_dclk_sel = 0; + interface_pix_clk_sel = port_pix_rate == 1 ? 1 : 0; + + vop2fb_reg_field(vfb, clk_ctrl, 0x1, 0, post_dclk_core_sel); + vop2fb_reg_field(vfb, clk_ctrl, 0x1, 2, post_dclk_out_sel); + + mipi_val = RT_BIT(0) | RT_BIT(1) | ((vp_id & 0x3) << 2) | (0x3 << 4) | RT_BIT(31); + + if (interface_pix_clk_sel) + { + mipi_val |= RT_BIT(20); + } + + if (interface_dclk_sel) + { + mipi_val |= RT_BIT(21); + } + + vop2fb_reg_write(vfb, RK3576_MIPI0_IF_CTRL, mipi_val); + + return vop2fb_vp_dclk_set_rate(vfb, vp_id, crtc_hz); +} + +rt_err_t vop2fb_vp_mode_set(struct vop2fb *vfb, rt_uint32_t vp_id, + const struct display_timing *tim) +{ + rt_uint32_t base = VOP2_VP_DSP_CTRL + vp_id * VOP2FB_VP_STRIDE; + rt_uint32_t hact_st, hact_end, vact_st, vact_end; + rt_uint32_t hsync_start, vsync_start; + rt_uint32_t out_mode; + rt_err_t err; + + if (!vfb || !tim || !vfb->regs) + { + return -RT_EINVAL; + } + + if (tim->pixelclock) + { + if ((err = vop2fb_vp_dclk_set_rate(vfb, vp_id, + (rt_ubase_t)tim->pixelclock))) + { + return err; + } + } + + /* + * RK3568 VOP2 expects the active-window start relative to the sync + * boundary on the back-porch side, matching Linux/U-Boot: + * + * hact_st = htotal - hsync_start = hsync_len + hback_porch + * vact_st = vtotal - vsync_start = vsync_len + vback_porch + * + * Using front-porch based values here shifts the whole active area and + * can leave HDMI running with valid clocks but no visible signal. + */ + hsync_start = tim->hactive + tim->hfront_porch; + vsync_start = tim->vactive + tim->vfront_porch; + + hact_st = tim->htotal - hsync_start; + hact_end = hact_st + tim->hactive; + vact_st = tim->vtotal - vsync_start; + vact_end = vact_st + tim->vactive; + + out_mode = vop2fb_vp_out_mode(vfb); + vop2fb_mask_write(vfb, base, VOP2_VP_OUT_MODE_MASK, VOP2_VP_OUT_MODE_SHIFT, out_mode); + LOG_D("VP%u out_mode=%u if=%d", vp_id, out_mode, vfb->output_if); + + HWREG32((rt_uint8_t *)vfb->regs + base + (VOP2_VP_DSP_HTOTAL_HS_END - VOP2_VP_DSP_CTRL)) = + (tim->htotal << 16) | tim->hsync_len; + + HWREG32((rt_uint8_t *)vfb->regs + base + (VOP2_VP_DSP_HACT_ST_END - VOP2_VP_DSP_CTRL)) = + (hact_st << 16) | hact_end; + + HWREG32((rt_uint8_t *)vfb->regs + base + (VOP2_VP_DSP_VACT_ST_END - VOP2_VP_DSP_CTRL)) = + (vact_st << 16) | vact_end; + + HWREG32((rt_uint8_t *)vfb->regs + base + (VOP2_VP_DSP_VTOTAL_VS_END - VOP2_VP_DSP_CTRL)) = + (tim->vtotal << 16) | tim->vsync_len; + + LOG_D("VP%u timing regs: HTOTAL_HS=0x%08x HACT=0x%08x VTOTAL_VS=0x%08x VACT=0x%08x", + vp_id, + (tim->htotal << 16) | tim->hsync_len, + (hact_st << 16) | hact_end, + (tim->vtotal << 16) | tim->vsync_len, + (vact_st << 16) | vact_end); + + vfb->display_w = tim->hactive; + vfb->display_h = tim->vactive; + + if (vfb->soc && vfb->soc->soc == VOP2FB_SOC_RK3576) + { + vop2fb_rk3576_cru_cfg(vfb, vp_id, tim); + } + else + { + vop2fb_rk3568_if_cfg(vfb, vp_id, tim); + } + + vop2fb_rk3568_dither_setup(vfb, vp_id); +#if DBG_LVL >= DBG_LOG + vop2fb_rk3568_dump_route_regs(vfb, vp_id); +#endif + + return RT_EOK; +} + +rt_err_t vop2fb_mipi_output_enable(struct vop2fb *vfb, rt_uint32_t vp_id, rt_bool_t enable) +{ + rt_uint32_t val; + + if (!vfb || !vfb->regs || !enable) + { + return RT_EOK; + } + + /* mipi0_en | dclk_out | mux=vp | hsync/vsync positive | regdone_imd */ + val = RT_BIT(0) | RT_BIT(1) | ((vp_id & 0x3) << 2) | (0x3 << 4) | RT_BIT(31); + vop2fb_reg_write(vfb, RK3576_MIPI0_IF_CTRL, val); + vop2fb_reg_write(vfb, VOP2_REG_CFG_DONE, + vop2fb_cfg_done_vp_val(vfb, vp_id)); + + return RT_EOK; +} + +rt_err_t vop2fb_vp_enable(struct vop2fb *vfb, rt_uint32_t vp_id, rt_bool_t enable) +{ + rt_uint32_t base = VOP2_VP_DSP_CTRL + vp_id * VOP2FB_VP_STRIDE; + + if (!vfb || !vfb->regs) + { + return -RT_EINVAL; + } + + vop2fb_vp_irq_ctrl(vfb, vp_id, enable); + vop2fb_mask_write(vfb, base, 1, VOP2_VP_STANDBY_SHIFT, enable ? 0 : 1); + vop2fb_reg_write(vfb, VOP2_REG_CFG_DONE, + vop2fb_cfg_done_vp_val(vfb, vp_id)); + + return RT_EOK; +} + +rt_err_t vop2fb_mix_alpha_set(struct vop2fb *vfb, rt_uint32_t mix_reg, rt_uint8_t alpha) +{ + if (!vfb || !vfb->regs) + { + return -RT_EINVAL; + } + + /* + * Opaque primary scanout should not rewrite RK3568 mix registers during + * bring-up. Clearing these registers can turn a valid timing stream into + * a fully black output, while the bootloader defaults are already good + * enough for the single-layer path we are using here. + */ + if (alpha == 0xff) + { + return RT_EOK; + } + + LOG_W("ignore partial alpha=%u on rk3568 simple scanout path", alpha); + + return RT_EOK; +} + +struct vop2fb_layer_cfg +{ + const struct vop2fb_win_desc *desc; + rt_uint32_t z; +}; + +static void vop2fb_layer_cfg_insert(struct vop2fb_layer_cfg *layers, + rt_size_t *count, rt_size_t max_layers, + const struct vop2fb_win_desc *desc, rt_uint32_t z) +{ + rt_size_t i; + + if (!layers || !count || !desc || *count >= max_layers) + { + return; + } + + i = *count; + + while (i > 0 && layers[i - 1].z > z) + { + layers[i] = layers[i - 1]; + i--; + } + + layers[i].desc = desc; + layers[i].z = z; + (*count)++; +} + +static void vop2fb_collect_plane_cfg(struct vop2fb_layer_cfg *layers, + rt_size_t *count, rt_size_t max_layers, + struct rt_graphic_plane *plane) +{ + struct vop2fb_plane_priv *priv; + + if (!plane) + { + return; + } + + priv = (struct vop2fb_plane_priv *)plane->priv; + + if (!priv->desc) + { + return; + } + + if (!priv->enabled || !plane->framebuffer) + { + return; + } + + vop2fb_layer_cfg_insert(layers, count, max_layers, priv->desc, plane->z); +} + +rt_err_t vop2fb_overlay_init(struct vop2fb *vfb) +{ + if (!vfb || !vfb->soc) + { + return -RT_EINVAL; + } + + /* RK3568 uses shared OVL_LAYER_SEL; newer VOP2 SoCs use per-VP port blocks. */ + if (vfb->soc->soc == VOP2FB_SOC_RK3568) + { + rt_uint32_t active_vps = vfb->active_vp_mask; + + if (active_vps && (active_vps & (active_vps - 1))) + { + rt_uint32_t layer_sel = 0; + rt_uint32_t port_sel = 0; + rt_uint32_t layer_count[VOP2FB_VP_MAX] = { 0 }; + rt_uint32_t owner, vp_id, used_layers = 0; + rt_size_t i, slot = 0; + + for (i = 0; i < vfb->soc->route_window_count; ++i) + { + layer_sel |= 0x5u << (i * 4); + } + + /* + * Layers feeding one VP must occupy adjacent mixer stages. + * Preserve the canonical RK3568 window order inside each VP, + * moving only the extra scanout windows to their target VPs. + */ + for (vp_id = 0; vp_id < vfb->soc->vp_count; ++vp_id) + { + for (i = 0; i < vfb->soc->route_window_count; ++i) + { + const struct vop2fb_win_desc *desc = + vfb->soc->route_windows[i]; + rt_uint32_t scanout_vp; + + owner = vfb->vp_id; + + for (scanout_vp = 0; + scanout_vp < vfb->soc->vp_count && + scanout_vp < VOP2FB_VP_MAX; ++scanout_vp) + { + if (vfb->vp[scanout_vp].enabled && + vfb->vp[scanout_vp].scanout == desc) + { + owner = scanout_vp; + break; + } + } + + if (owner != vp_id) + { + continue; + } + + layer_sel &= ~(0xfu << (slot * 4)); + layer_sel |= ((rt_uint32_t)desc->layer_sel_id & 0xfu) << + (slot * 4); + port_sel &= ~(0x3u << + (16 + desc->win_sel_port_offset * 2)); + port_sel |= (owner & 0x3u) << + (16 + desc->win_sel_port_offset * 2); + layer_count[owner]++; + slot++; + } + } + + for (vp_id = 0; vp_id + 1 < vfb->soc->vp_count; ++vp_id) + { + rt_uint32_t port_mux; + + used_layers += layer_count[vp_id]; + port_mux = used_layers ? used_layers - 1 : 8; + port_sel |= (port_mux & 0xfu) << (vp_id * 4); + } + + /* RK3568 VP2 is hard-wired to the final mixer stage. */ + port_sel |= 7u << ((vfb->soc->vp_count - 1) * 4); + + vop2fb_reg_write(vfb, VOP2_OVL_LAYER_SEL, layer_sel); + vop2fb_reg_write(vfb, VOP2_OVL_PORT_SEL, port_sel); + + for (vp_id = 0; vp_id < vfb->soc->vp_count; ++vp_id) + { + if (active_vps & RT_BIT(vp_id)) + { + vop2fb_mask_write(vfb, VOP2_OVL_CTRL, 1, + VOP2_OVL_MODE_SEL_SHIFT + vp_id, 0); + } + } + + vop2fb_mask_write(vfb, VOP2_OVL_CTRL, 1, + RK3568_OVL_LAYERSEL_REGDONE_IMD_SHIFT, 1); + vop2fb_reg_write(vfb, VOP2_REG_CFG_DONE, + vop2fb_cfg_done_mask_val(vfb, active_vps)); + + LOG_D("rk3568 ovl multi: active=0x%x layer_sel=0x%08x port_sel=0x%08x", + active_vps, layer_sel, port_sel); + + return RT_EOK; + } + + /* + * Match the working U-Boot single-display chain on RK3568: + * Cluster0 -> Esmart0 -> Smart0 -> Cluster1 -> Esmart1 -> Smart1 + * with VP0 taking mixer output 5. + * + * Using only the currently-active layer count here can route VP0 to + * mixer stage 0, which still produces valid HDMI timing but no + * visible pixels. + */ + if ((!active_vps && vfb->vp_id == 0) || + active_vps == RT_BIT(0)) + { + rt_uint32_t layer_sel = 0x00761320; + rt_uint32_t port_sel = 0x00000755; + + vop2fb_reg_write(vfb, VOP2_OVL_LAYER_SEL, layer_sel); + vop2fb_reg_write(vfb, VOP2_OVL_PORT_SEL, port_sel); + vop2fb_mask_write(vfb, VOP2_OVL_CTRL, 1, + VOP2_OVL_MODE_SEL_SHIFT + vfb->vp_id, 0); + vop2fb_mask_write(vfb, VOP2_OVL_CTRL, 1, + RK3568_OVL_LAYERSEL_REGDONE_IMD_SHIFT, 1); + + LOG_D("rk3568 ovl init: vp%u fixed layer_sel=0x%08x port_sel=0x%08x", + vfb->vp_id, layer_sel, port_sel); + + vop2fb_reg_write(vfb, VOP2_REG_CFG_DONE, vop2fb_cfg_done_val(vfb)); + return RT_EOK; + } + + struct vop2fb_layer_cfg layers[6]; + rt_uint32_t layer_sel = 0; + rt_uint32_t port_sel = 0; + rt_size_t i; + rt_size_t count = 0; + rt_uint32_t port_mux; + + for (i = 0; i < RT_ARRAY_SIZE(layers); ++i) + { + layer_sel |= 0x5u << (i * 4); + } + + port_sel |= 0x8u << 0; + port_sel |= 0x8u << 4; + port_sel |= 0x8u << 8; + + vop2fb_collect_plane_cfg(layers, &count, RT_ARRAY_SIZE(layers), vfb->primary); + + for (i = 0; i < vfb->overlay_count; ++i) + { + vop2fb_collect_plane_cfg(layers, &count, RT_ARRAY_SIZE(layers), vfb->overlays[i]); + } + + vop2fb_collect_plane_cfg(layers, &count, RT_ARRAY_SIZE(layers), vfb->cursor); + + if (!count && vfb->soc->primary) + { + vop2fb_layer_cfg_insert(layers, &count, RT_ARRAY_SIZE(layers), + vfb->soc->primary, 0); + } + + for (i = 0; i < count; ++i) + { + const struct vop2fb_win_desc *desc = layers[i].desc; + rt_uint32_t sel_shift = desc->win_sel_port_offset * 2; + + layer_sel &= ~(0xfu << (i * 4)); + layer_sel |= ((rt_uint32_t)desc->layer_sel_id & 0xfu) << (i * 4); + + port_sel &= ~(0x3u << (16 + sel_shift)); + port_sel |= (vfb->vp_id & 0x3u) << (16 + sel_shift); + } + + port_mux = count ? (rt_uint32_t)(count - 1) : 0x8u; + port_sel &= ~(0xfu << (vfb->vp_id * 4)); + port_sel |= (port_mux & 0xfu) << (vfb->vp_id * 4); + + vop2fb_reg_write(vfb, VOP2_OVL_LAYER_SEL, layer_sel); + vop2fb_reg_write(vfb, VOP2_OVL_PORT_SEL, port_sel); + vop2fb_mask_write(vfb, VOP2_OVL_CTRL, 1, + RK3568_OVL_LAYERSEL_REGDONE_IMD_SHIFT, 1); + + LOG_D("rk3568 ovl init: vp%u layers=%u layer_sel=0x%08x port_sel=0x%08x", + vfb->vp_id, (unsigned)count, layer_sel, port_sel); + } + else if (vfb->soc->soc == VOP2FB_SOC_RK3576) + { + rt_uint32_t port_ctrl = (vfb->vp_id == 2) ? 0x800 : + (vfb->vp_id == 1) ? 0x700 : 0x600; + + vop2fb_reg_write(vfb, port_ctrl, 1); + } + + vop2fb_reg_write(vfb, VOP2_REG_CFG_DONE, vop2fb_cfg_done_val(vfb)); + + return RT_EOK; +} + +static const struct vop2fb_win_desc *vop2fb_win_by_plane_id(struct vop2fb *vfb, rt_uint32_t plane_id) +{ + rt_size_t i; + + if (vfb->soc->primary && vfb->soc->primary->plane_id == plane_id) + { + return vfb->soc->primary; + } + + if (vfb->soc->cursor && vfb->soc->cursor->plane_id == plane_id) + { + return vfb->soc->cursor; + } + + for (i = 0; i < vfb->soc->overlay_count; ++i) + { + if (vfb->soc->overlays[i].plane_id == plane_id) + { + return &vfb->soc->overlays[i]; + } + } + + return RT_NULL; +} + +rt_err_t vop2fb_parse_port_planes(struct vop2fb *vfb, struct rt_ofw_node *vop_np, + rt_uint32_t vp_id) +{ + struct rt_ofw_node *ports_np, *port_np, *child; + rt_uint32_t reg, primary_id = RK_PLANE_ESMART0, cursor_id = RK_PLANE_SMART1; + + RT_UNUSED(vop2fb_win_by_plane_id); + + if (!vfb || !vop_np) + { + return -RT_EINVAL; + } + + ports_np = rt_ofw_get_child_by_tag(vop_np, "ports"); + + if (!ports_np) + { + return -RT_ENOENT; + } + + port_np = RT_NULL; + + rt_ofw_foreach_child_node(ports_np, child) + { + if (!rt_ofw_prop_read_u32(child, "reg", ®) && reg == vp_id) + { + port_np = child; + break; + } + } + + if (!port_np) + { + return -RT_ENOENT; + } + + rt_ofw_prop_read_u32(port_np, "rockchip,primary-plane", &primary_id); + rt_ofw_prop_read_u32(port_np, "cursor-win-id", &cursor_id); + + LOG_D("VP%u primary-plane=%u cursor-win-id=%u", vp_id, primary_id, cursor_id); + + return RT_EOK; +} diff --git a/bsp/rockchip/dm/graphic/framebuffer/fb-vop2-vp.h b/bsp/rockchip/dm/graphic/framebuffer/fb-vop2-vp.h new file mode 100644 index 000000000000..79796cf0ebf8 --- /dev/null +++ b/bsp/rockchip/dm/graphic/framebuffer/fb-vop2-vp.h @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-09-23 GuEe-GUI first version + */ + +#ifndef __FB_VOP2_VP_H__ +#define __FB_VOP2_VP_H__ + +#include "fb-vop2.h" +#include "rockchip-display.h" + +#define VOP2FB_VP_STRIDE 0x100 + +#define VOP2_VP_DSP_CTRL 0xC00 +#define VOP2_VP_DSP_BG 0xC2C +#define RK3568_VP0_PRE_SCAN_HTIMING 0xC30 +#define RK3568_VP0_POST_DSP_HACT_INFO 0xC34 +#define RK3568_VP0_POST_DSP_VACT_INFO 0xC38 +#define RK3568_VP0_POST_SCL_FACTOR_YRGB 0xC3C +#define RK3568_VP0_POST_SCL_CTRL 0xC40 +#define RK3568_VP0_POST_DSP_VACT_INFO_F1 0xC44 +#define VOP2_VP_DSP_HTOTAL_HS_END 0xC48 +#define VOP2_VP_DSP_HACT_ST_END 0xC4C +#define VOP2_VP_DSP_VTOTAL_VS_END 0xC50 +#define VOP2_VP_DSP_VACT_ST_END 0xC54 + +#define VOP2_OVL_CTRL 0x600 +#define VOP2_OVL_MODE_SEL_SHIFT 0 +#define VOP2_OVL_LAYER_SEL 0x604 +#define VOP2_OVL_PORT_SEL 0x608 +#define RK3568_VP0_BG_MIX_CTRL 0x6E0 +#define RK3568_BG_MIX_CTRL_MASK 0xff +#define RK3568_BG_MIX_CTRL_SHIFT 24 +#define RK3568_OVL_LAYERSEL_REGDONE_IMD_SHIFT 28 +#define RK3568_POST_HORIZONTAL_SCALEDOWN_EN_SHIFT 0 +#define RK3568_POST_VERTICAL_SCALEDOWN_EN_SHIFT 1 + +#define RK3568_DSP_IF_EN 0x028 +#define RK3568_DSP_IF_POL 0x030 + +#define RK3568_VP0_INT_EN 0x0A0 +#define RK3568_VP0_INT_CLR 0x0A4 +#define RK3568_VP0_INT_STATUS 0x0A8 + +#define VOP2_VP_STANDBY_SHIFT 31 +#define VOP2_VP_OUT_MODE_SHIFT 0 +#define VOP2_VP_OUT_MODE_MASK 0xf +#define VOP2_VP_PRE_DITHER_DOWN_EN_SHIFT 16 +#define VOP2_VP_DITHER_DOWN_EN_SHIFT 17 + +#define RK3568_HDMI0_EN_SHIFT 1 +#define RK3568_EDP0_EN_SHIFT 3 +#define RK3568_MIPI0_EN_SHIFT 4 +#define RK3568_LVDS0_EN_SHIFT 5 +#define RK3568_RGB_EN_SHIFT 0 +#define RK3568_MIPI1_EN_SHIFT 20 +#define RK3568_LVDS1_EN_SHIFT 24 + +#define RK3568_HDMI0_MUX_SHIFT 10 +#define RK3568_EDP0_MUX_SHIFT 14 +#define RK3568_MIPI0_MUX_SHIFT 16 +#define RK3568_LVDS0_MUX_SHIFT 18 +#define RK3568_RGB_MUX_SHIFT 8 +#define RK3568_MIPI1_MUX_SHIFT 21 +#define RK3568_LVDS1_MUX_SHIFT 25 +#define RK3568_IF_MUX_MASK 0x3 + +#define RK3568_IF_CTRL_REG_DONE_IMD_SHIFT 28 +#define RK3568_IF_CRTL_MIPI_DCLK_POL_SHIFT 19 +#define RK3568_IF_CTRL_MIPI_PIN_POL_SHIFT 16 +#define RK3568_IF_CRTL_EDP_DCLK_POL_SHIFT 15 +#define RK3568_IF_CTRL_EDP_PIN_POL_SHIFT 12 +#define RK3568_IF_CRTL_HDMI_DCLK_POL_SHIFT 7 +#define RK3568_IF_CRTL_HDMI_PIN_POL_SHIFT 4 +#define RK3568_IF_CTRL_RGB_DCLK_POL_SHIFT 3 +#define RK3568_IF_CTRL_RGB_PIN_POL_SHIFT 0 +#define RK3568_IF_PIN_POL_MASK 0x7 + +#define RK3568_HSYNC_POSITIVE RT_BIT(0) +#define RK3568_VSYNC_POSITIVE RT_BIT(1) + +#define VOP2_VP_FS_INTR RT_BIT(0) +#define VOP2_VP_FS_NEW_INTR RT_BIT(1) +#define VOP2_VP_POST_BUF_EMPTY_INTR RT_BIT(4) +#define VOP2_VP_FS_FIELD_INTR RT_BIT(5) + +#define RK3568_SYS0_INT_EN 0x080 +#define RK3568_SYS0_INT_CLR 0x084 +#define RK3568_SYS0_INT_STATUS 0x088 +#define RK3568_SYS1_INT_EN 0x090 +#define RK3568_SYS1_INT_CLR 0x094 +#define RK3568_SYS1_INT_STATUS 0x098 +#define RK3568_SYS_BUS_ERROR_INTR RT_BIT(1) + +#define RK3568_VP_INT_EN(vp_id) (RK3568_VP0_INT_EN + ((vp_id) * 0x10)) +#define RK3568_VP_INT_CLR(vp_id) (RK3568_VP0_INT_CLR + ((vp_id) * 0x10)) +#define RK3568_VP_INT_STATUS(vp_id) (RK3568_VP0_INT_STATUS + ((vp_id) * 0x10)) + +#define RK3576_MIPI0_IF_CTRL 0x180 +#define RK3576_VP_OUT_MODE_P888 0 +#define RK3568_VP_OUT_MODE_AAAA 15 + +rt_err_t vop2fb_vp_mode_set(struct vop2fb *vfb, rt_uint32_t vp_id, + const struct display_timing *tim); +void vop2fb_vp_irq_ctrl(struct vop2fb *vfb, rt_uint32_t vp_id, rt_bool_t enable); +rt_err_t vop2fb_vp_enable(struct vop2fb *vfb, rt_uint32_t vp_id, rt_bool_t enable); +void vop2fb_output_disable(struct vop2fb *vfb, enum vop2fb_output_if output_if); +rt_err_t vop2fb_vp_post_config(struct vop2fb *vfb, rt_uint32_t vp_id, + const struct display_timing *tim); +rt_err_t vop2fb_mipi_output_enable(struct vop2fb *vfb, rt_uint32_t vp_id, rt_bool_t enable); +rt_err_t vop2fb_overlay_init(struct vop2fb *vfb); +rt_err_t vop2fb_mix_alpha_set(struct vop2fb *vfb, rt_uint32_t mix_reg, rt_uint8_t alpha); +rt_err_t vop2fb_parse_port_planes(struct vop2fb *vfb, struct rt_ofw_node *vop_np, + rt_uint32_t vp_id); + +#endif /* __FB_VOP2_VP_H__ */ diff --git a/bsp/rockchip/dm/graphic/framebuffer/fb-vop2.c b/bsp/rockchip/dm/graphic/framebuffer/fb-vop2.c new file mode 100755 index 000000000000..0203bf25a6ef --- /dev/null +++ b/bsp/rockchip/dm/graphic/framebuffer/fb-vop2.c @@ -0,0 +1,2769 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-09-23 GuEe-GUI first version + */ + +#include "fb-vop2.h" +#include "fb-vop2-vp.h" + +#include + +#define DBG_TAG "fb.vop2" +#define DBG_LVL DBG_INFO +#include + +static enum vop2fb_output_if vop2fb_output_from_connector( + struct rt_ofw_node *connector_np); + +/* -------------------------------------------------------------------------- */ +/* SoC window maps */ +/* -------------------------------------------------------------------------- */ + +static const struct vop2fb_win_desc rk3568_primary = +{ + .name = "Smart0", + .type = VOP2FB_LAYER_SMART, + .base_offset = VOP2_SMART0_BASE, + .layer_sel_id = 3, + .win_sel_port_offset = 6, + .z_order = 2, + .plane_id = RK_PLANE_SMART0, + .mix_alpha_reg = 0x658, +}; + +static const struct vop2fb_win_desc rk3568_cursor = +{ + .name = "Smart1", + .type = VOP2FB_LAYER_SMART, + .base_offset = VOP2_SMART0_BASE + VOP2_SMART_STRIDE, + .layer_sel_id = 7, + .win_sel_port_offset = 7, + .z_order = 5, + .plane_id = RK_PLANE_SMART1, +}; + +static const struct vop2fb_win_desc rk3568_overlays[] = +{ + { + .name = "Cluster0", + .type = VOP2FB_LAYER_CLUSTER, + .base_offset = VOP2_CLUSTER0_BASE, + .layer_sel_id = 0, + .win_sel_port_offset = 0, + .z_order = 0, + .plane_id = RK_PLANE_CLUSTER0, + .mix_alpha_reg = 0x618, + }, + { + .name = "Esmart1", + .type = VOP2FB_LAYER_ESMART, + .base_offset = VOP2_ESMART0_BASE + VOP2_ESMART_STRIDE, + .layer_sel_id = 6, + .win_sel_port_offset = 5, + .z_order = 3, + .plane_id = RK_PLANE_ESMART1, + .mix_alpha_reg = 0x660, + }, + { + .name = "Esmart0", + .type = VOP2FB_LAYER_ESMART, + .base_offset = VOP2_ESMART0_BASE, + .layer_sel_id = 2, + .win_sel_port_offset = 4, + .z_order = 4, + .plane_id = RK_PLANE_ESMART0, + .mix_alpha_reg = 0x658, + }, +}; + +/* + * Cluster1 is not exposed as a userspace plane in the compact RK3568 + * framebuffer setup, but it still occupies one slot in the shared overlay + * mixer. Keep a routing-only descriptor so multi-VP layer selection matches + * the hardware window order used by Linux/U-Boot. + */ +static const struct vop2fb_win_desc rk3568_cluster1_route = +{ + .name = "Cluster1", + .type = VOP2FB_LAYER_CLUSTER, + .base_offset = VOP2_CLUSTER0_BASE + VOP2_CLUSTER_STRIDE, + .layer_sel_id = 1, + .win_sel_port_offset = 1, + .plane_id = -1, +}; + +static const struct vop2fb_win_desc *const rk3568_route_windows[] = +{ + &rk3568_overlays[0], /* Cluster0 */ + &rk3568_overlays[2], /* Esmart0 */ + &rk3568_primary, /* Smart0 */ + &rk3568_cluster1_route, /* Cluster1 */ + &rk3568_overlays[1], /* Esmart1 */ + &rk3568_cursor, /* Smart1 */ +}; + +static const struct vop2fb_win_desc rk3528_primary = +{ + .name = "Esmart0", + .type = VOP2FB_LAYER_ESMART, + .base_offset = VOP2_ESMART0_BASE, + .z_order = 2, + .axi_yrgb_id = 0x06, + .axi_uv_id = 0x07, +}; + +static const struct vop2fb_win_desc rk3528_cursor = +{ + .name = "Esmart3", + .type = VOP2FB_LAYER_ESMART, + .base_offset = VOP2_ESMART0_BASE + VOP2_ESMART_STRIDE * 3, + .z_order = 5, + .axi_yrgb_id = 0x0c, + .axi_uv_id = 0x0d, +}; + +static const struct vop2fb_win_desc rk3528_overlays[] = +{ + { + .name = "Cluster0", + .type = VOP2FB_LAYER_CLUSTER, + .base_offset = VOP2_CLUSTER0_BASE, + .z_order = 0, + .axi_yrgb_id = 0x02, + .axi_uv_id = 0x03, + }, + { + .name = "Esmart1", + .type = VOP2FB_LAYER_ESMART, + .base_offset = VOP2_ESMART0_BASE + VOP2_ESMART_STRIDE, + .z_order = 3, + .axi_yrgb_id = 0x08, + .axi_uv_id = 0x09, + }, + { + .name = "Esmart2", + .type = VOP2FB_LAYER_ESMART, + .base_offset = VOP2_ESMART0_BASE + VOP2_ESMART_STRIDE * 2, + .z_order = 4, + .axi_yrgb_id = 0x0a, + .axi_uv_id = 0x0b, + }, +}; + +static const struct vop2fb_win_desc rk3562_primary = +{ + .name = "Esmart0", + .type = VOP2FB_LAYER_ESMART, + .base_offset = VOP2_ESMART0_BASE, + .z_order = 2, + .axi_yrgb_id = 0x02, + .axi_uv_id = 0x03, +}; + +static const struct vop2fb_win_desc rk3562_cursor = +{ + .name = "Esmart3", + .type = VOP2FB_LAYER_ESMART, + .base_offset = VOP2_ESMART0_BASE + VOP2_ESMART_STRIDE * 3, + .z_order = 5, + .axi_yrgb_id = 0x08, + .axi_uv_id = 0x09, +}; + +static const struct vop2fb_win_desc rk3562_overlays[] = +{ + { + .name = "Esmart1", + .type = VOP2FB_LAYER_ESMART, + .base_offset = VOP2_ESMART0_BASE + VOP2_ESMART_STRIDE, + .z_order = 3, + .axi_yrgb_id = 0x04, + .axi_uv_id = 0x05, + }, + { + .name = "Esmart2", + .type = VOP2FB_LAYER_ESMART, + .base_offset = VOP2_ESMART0_BASE + VOP2_ESMART_STRIDE * 2, + .z_order = 4, + .axi_yrgb_id = 0x06, + .axi_uv_id = 0x07, + }, +}; + +static const struct vop2fb_win_desc rk3588_primary = +{ + .name = "Esmart0", + .type = VOP2FB_LAYER_ESMART, + .base_offset = VOP2_ESMART0_BASE, + .z_order = 4, + .axi_yrgb_id = 0x10, + .axi_uv_id = 0x11, +}; + +static const struct vop2fb_win_desc rk3588_cursor = +{ + .name = "Esmart3", + .type = VOP2FB_LAYER_ESMART, + .base_offset = VOP2_ESMART0_BASE + VOP2_ESMART_STRIDE * 3, + .z_order = 7, + .axi_yrgb_id = 0x16, + .axi_uv_id = 0x17, +}; + +static const struct vop2fb_win_desc rk3588_overlays[] = +{ + { + .name = "Cluster0", + .type = VOP2FB_LAYER_CLUSTER, + .base_offset = VOP2_CLUSTER0_BASE, + .z_order = 0, + .axi_yrgb_id = 0x02, + .axi_uv_id = 0x03, + }, + { + .name = "Cluster1", + .type = VOP2FB_LAYER_CLUSTER, + .base_offset = VOP2_CLUSTER0_BASE + VOP2_CLUSTER_STRIDE, + .z_order = 1, + .axi_yrgb_id = 0x04, + .axi_uv_id = 0x05, + }, + { + .name = "Esmart1", + .type = VOP2FB_LAYER_ESMART, + .base_offset = VOP2_ESMART0_BASE + VOP2_ESMART_STRIDE, + .z_order = 5, + .axi_yrgb_id = 0x12, + .axi_uv_id = 0x13, + }, + { + .name = "Esmart2", + .type = VOP2FB_LAYER_ESMART, + .base_offset = VOP2_ESMART0_BASE + VOP2_ESMART_STRIDE * 2, + .z_order = 6, + .axi_yrgb_id = 0x14, + .axi_uv_id = 0x15, + }, +}; + +/* RK3576 reuses RK3588-class layer map (same register layout). */ +static const struct vop2fb_win_desc rk3576_primary = +{ + .name = "Esmart0", + .type = VOP2FB_LAYER_ESMART, + .base_offset = VOP2_ESMART0_BASE, + .z_order = 4, + .axi_yrgb_id = 0x10, + .axi_uv_id = 0x11, +}; + +static const struct vop2fb_win_desc rk3576_cursor = +{ + .name = "Esmart3", + .type = VOP2FB_LAYER_ESMART, + .base_offset = VOP2_ESMART0_BASE + VOP2_ESMART_STRIDE * 3, + .z_order = 7, + .axi_yrgb_id = 0x0c, + .axi_uv_id = 0x0d, +}; + +static const struct vop2fb_win_desc rk3576_overlays[] = +{ + { + .name = "Cluster0", + .type = VOP2FB_LAYER_CLUSTER, + .base_offset = VOP2_CLUSTER0_BASE, + .z_order = 0, + .axi_yrgb_id = 0x0a, + .axi_uv_id = 0x0b, + }, + { + .name = "Cluster1", + .type = VOP2FB_LAYER_CLUSTER, + .base_offset = VOP2_CLUSTER0_BASE + VOP2_CLUSTER_STRIDE, + .z_order = 1, + .axi_yrgb_id = 0x0e, + .axi_uv_id = 0x0f, + }, + { + .name = "Esmart1", + .type = VOP2FB_LAYER_ESMART, + .base_offset = VOP2_ESMART0_BASE + VOP2_ESMART_STRIDE, + .z_order = 5, + .axi_yrgb_id = 0x12, + .axi_uv_id = 0x13, + }, + { + .name = "Esmart2", + .type = VOP2FB_LAYER_ESMART, + .base_offset = VOP2_ESMART0_BASE + VOP2_ESMART_STRIDE * 2, + .z_order = 6, + .axi_yrgb_id = 0x0a, + .axi_uv_id = 0x0b, + .axi_id = 1, + }, +}; + +static const struct vop2fb_soc_data rk3568_soc_data = +{ + .soc = VOP2FB_SOC_RK3568, + .version = "rk3568", + .reg_size = 0x3000, + .regbak_words = 0x3000 / 4, + .primary = &rk3568_primary, + .cursor = &rk3568_cursor, + .overlays = rk3568_overlays, + /* + * Esmart0/Esmart1 are reserved as primary scanout windows for additional + * VPs. Cluster0 remains available as the first framebuffer's overlay. + */ + .overlay_count = 1, + .route_windows = rk3568_route_windows, + .route_window_count = RT_ARRAY_SIZE(rk3568_route_windows), + .axi_config = RT_FALSE, + .vp_count = 3, +}; + +static const struct vop2fb_soc_data rk3588_soc_data = +{ + .soc = VOP2FB_SOC_RK3588, + .version = "rk3588", + .reg_size = 0x4200, + .regbak_words = 0x4200 / 4, + .primary = &rk3588_primary, + .cursor = &rk3588_cursor, + .overlays = rk3588_overlays, + .overlay_count = RT_ARRAY_SIZE(rk3588_overlays), + .axi_config = RT_TRUE, + .vp_count = 4, +}; + +static const struct vop2fb_soc_data rk3528_soc_data = +{ + .soc = VOP2FB_SOC_RK3528, + .version = "rk3528", + .reg_size = 0x3000, + .regbak_words = 0x3000 / 4, + .primary = &rk3528_primary, + .cursor = &rk3528_cursor, + .overlays = rk3528_overlays, + .overlay_count = RT_ARRAY_SIZE(rk3528_overlays), + .axi_config = RT_TRUE, + .vp_count = 2, +}; + +static const struct vop2fb_soc_data rk3562_soc_data = +{ + .soc = VOP2FB_SOC_RK3562, + .version = "rk3562", + .reg_size = 0x2000, + .regbak_words = 0x2000 / 4, + .primary = &rk3562_primary, + .cursor = &rk3562_cursor, + .overlays = rk3562_overlays, + .overlay_count = RT_ARRAY_SIZE(rk3562_overlays), + .axi_config = RT_TRUE, + .vp_count = 1, +}; + +static const struct vop2fb_soc_data rk3576_soc_data = +{ + .soc = VOP2FB_SOC_RK3576, + .version = "rk3576", + .reg_size = 0x3000, + .regbak_words = 0x3000 / 4, + .primary = &rk3576_primary, + .cursor = &rk3576_cursor, + .overlays = rk3576_overlays, + .overlay_count = RT_ARRAY_SIZE(rk3576_overlays), + .axi_config = RT_TRUE, + .irq_by_vp = RT_TRUE, + .vp_count = 3, +}; + +static rt_uint32_t vop2fb_modes[] = +{ + RTGRAPHIC_PIXEL_FORMAT_ARGB888, + RTGRAPHIC_PIXEL_FORMAT_RGB888, + RTGRAPHIC_PIXEL_FORMAT_RGB565, +}; + +/* -------------------------------------------------------------------------- */ +/* Helpers */ +/* -------------------------------------------------------------------------- */ + +rt_uint32_t vop2fb_mode_to_hw(rt_uint32_t mode) +{ + switch (mode) + { + case RTGRAPHIC_PIXEL_FORMAT_ARGB888: + case RTGRAPHIC_PIXEL_FORMAT_ABGR888: + return VOP2FB_FMT_ARGB8888; + case RTGRAPHIC_PIXEL_FORMAT_RGB888: + case RTGRAPHIC_PIXEL_FORMAT_BGR888: + return VOP2FB_FMT_RGB888; + case RTGRAPHIC_PIXEL_FORMAT_RGB565: + case RTGRAPHIC_PIXEL_FORMAT_BGR565: + return VOP2FB_FMT_RGB565; + default: + return VOP2FB_FMT_ARGB8888; + } +} + +rt_uint32_t vop2fb_hw_to_bpp(rt_uint32_t hw_fmt) +{ + switch (hw_fmt) + { + case VOP2FB_FMT_RGB565: + return 16; + case VOP2FB_FMT_RGB888: + return 24; + default: + return 32; + } +} + +static struct vop2fb *vop2fb_from_plane(struct rt_graphic_plane *plane) +{ + struct vop2fb_plane_priv *priv; + + if (!plane) + { + return RT_NULL; + } + + priv = (struct vop2fb_plane_priv *)plane->priv; + + return priv->vfb; +} + +static struct vop2fb_plane_priv *vop2fb_plane_priv(struct rt_graphic_plane *plane) +{ + return (struct vop2fb_plane_priv *)plane->priv; +} + +static struct vop2fb_vp_state *vop2fb_output_from_graphic( + struct rt_graphic_device *gdev) +{ + if (!gdev) + { + return RT_NULL; + } + + return (struct vop2fb_vp_state *)gdev->parent.user_data; +} + +static rt_uint32_t vop2fb_xvir(rt_uint32_t line_length) +{ + /* + * Rockchip VOP2 VIR registers use a 32-bit word stride, not the older + * VOP-style 32-byte unit. Linux/U-Boot program this as pitch / 4. + */ + return line_length >> 2; +} + +static rt_bool_t vop2fb_mode_rb_swap(rt_uint32_t mode) +{ + switch (mode) + { + case RTGRAPHIC_PIXEL_FORMAT_ABGR888: + case RTGRAPHIC_PIXEL_FORMAT_BGR888: + case RTGRAPHIC_PIXEL_FORMAT_BGR565: + return RT_TRUE; + default: + return RT_FALSE; + } +} + +static rt_bool_t vop2fb_hw_fmt_dither_up(rt_uint32_t hw_fmt) +{ + return hw_fmt == VOP2FB_FMT_RGB565; +} + +static void vop2fb_regsbak_sync(struct vop2fb *vfb) +{ + rt_size_t i; + volatile rt_uint32_t *regs; + + if (!vfb || !vfb->regs || !vfb->regsbak || !vfb->soc) + { + return; + } + + regs = (volatile rt_uint32_t *)vfb->regs; + + for (i = 0; i < vfb->soc->regbak_words; ++i) + { + vfb->regsbak[i] = regs[i]; + } +} + +static void vop2fb_rk3568_smart_prepare(struct vop2fb *vfb, + const struct vop2fb_win_desc *desc, rt_uint32_t hw_fmt, rt_uint32_t mode) +{ + rt_uint32_t base; + + if (!vfb || !vfb->soc || !desc || vfb->soc->soc != VOP2FB_SOC_RK3568) + { + return; + } + + if (desc->type != VOP2FB_LAYER_SMART && desc->type != VOP2FB_LAYER_ESMART) + { + return; + } + + base = desc->base_offset; + + /* + * Force Smart/Esmart into a known-good 1:1 RGB scanout state. + * The RT bring-up path previously only touched format/addr/size, so any + * stale boot ROM/U-Boot scale or swap bits could keep HDMI black even + * though timing and DMA were already alive. + */ + vop2fb_mask_write(vfb, base + VOP2_ESMART_CTRL0, + 1, VOP2_RGB2YUV_EN_SHIFT, 0); + vop2fb_mask_write(vfb, base + VOP2_ESMART_CTRL0, + VOP2_CSC_MODE_MASK, VOP2_CSC_MODE_SHIFT, 0); + vop2fb_mask_write(vfb, base + VOP2_ESMART_CTRL1, + 1, VOP2_YMIRROR_EN_SHIFT, 0); + vop2fb_mask_write(vfb, base + VOP2_REGION0_CTRL, + 1, VOP2_REGION0_DITHER_UP_EN_SHIFT, + vop2fb_hw_fmt_dither_up(hw_fmt) ? 1 : 0); + vop2fb_mask_write(vfb, base + VOP2_REGION0_CTRL, + 1, VOP2_REGION0_RB_SWAP_SHIFT, + vop2fb_mode_rb_swap(mode) ? 1 : 0); + vop2fb_mask_write(vfb, base + VOP2_REGION0_CTRL, + 1, VOP2_YRGB_GT2_SHIFT, 0); + vop2fb_mask_write(vfb, base + VOP2_REGION0_CTRL, + 1, VOP2_YRGB_GT4_SHIFT, 0); +} + +static void vop2fb_rk3568_dump_win_regs(struct vop2fb *vfb, + const struct vop2fb_win_desc *desc) +{ + rt_uint32_t base; + + if (!vfb || !vfb->regs || !vfb->soc || !desc || vfb->soc->soc != VOP2FB_SOC_RK3568) + { + return; + } + + if (desc->type != VOP2FB_LAYER_SMART && desc->type != VOP2FB_LAYER_ESMART) + { + return; + } + + base = desc->base_offset; + RT_UNUSED(base); + + LOG_D("%s regs: CTRL0=0x%08x CTRL1=0x%08x R0_CTRL=0x%08x YRGB_MST=0x%08x CBR_MST=0x%08x VIR=0x%08x ACT=0x%08x DSP=0x%08x ST=0x%08x SCL=0x%08x FAC=0x%08x", + desc->name, + HWREG32((rt_uint8_t *)vfb->regs + base + VOP2_ESMART_CTRL0), + HWREG32((rt_uint8_t *)vfb->regs + base + VOP2_ESMART_CTRL1), + HWREG32((rt_uint8_t *)vfb->regs + base + VOP2_REGION0_CTRL), + HWREG32((rt_uint8_t *)vfb->regs + base + VOP2_REGION0_YRGB_MST), + HWREG32((rt_uint8_t *)vfb->regs + base + VOP2_REGION0_CBR_MST), + HWREG32((rt_uint8_t *)vfb->regs + base + VOP2_REGION0_VIR), + HWREG32((rt_uint8_t *)vfb->regs + base + VOP2_REGION0_ACT_INFO), + HWREG32((rt_uint8_t *)vfb->regs + base + VOP2_REGION0_DSP_INFO), + HWREG32((rt_uint8_t *)vfb->regs + base + VOP2_REGION0_DSP_ST), + HWREG32((rt_uint8_t *)vfb->regs + base + VOP2_REGION0_SCL_CTRL), + HWREG32((rt_uint8_t *)vfb->regs + base + VOP2_REGION0_SCL_FACTOR_YRGB)); + + if (desc->mix_alpha_reg >= 0x8) + { + LOG_D("%s mix regs: SRC_COLOR=0x%08x DST_COLOR=0x%08x SRC_ALPHA=0x%08x DST_ALPHA=0x%08x", + desc->name, + HWREG32((rt_uint8_t *)vfb->regs + desc->mix_alpha_reg - 0x8), + HWREG32((rt_uint8_t *)vfb->regs + desc->mix_alpha_reg - 0x4), + HWREG32((rt_uint8_t *)vfb->regs + desc->mix_alpha_reg), + HWREG32((rt_uint8_t *)vfb->regs + desc->mix_alpha_reg + 0x4)); + } +} + +static void vop2fb_axi_config(struct vop2fb *vfb, const struct vop2fb_win_desc *desc) +{ + rt_uint32_t base = desc->base_offset; + + if (!vfb->soc->axi_config) + { + return; + } + + switch (desc->type) + { + case VOP2FB_LAYER_CLUSTER: + vop2fb_mask_write(vfb, base + VOP2_CLUSTER_CTRL, + VOP2_CLUSTER_AXI_ID_MASK, VOP2_CLUSTER_AXI_ID_SHIFT, desc->axi_id); + vop2fb_mask_write(vfb, base + VOP2_CLUSTER_WIN0_CTRL2, + VOP2_CLUSTER_AXI_YRGB_ID_MASK, VOP2_CLUSTER_AXI_YRGB_ID_SHIFT, + desc->axi_yrgb_id); + vop2fb_mask_write(vfb, base + VOP2_CLUSTER_WIN0_CTRL2, + VOP2_CLUSTER_AXI_UV_ID_MASK, VOP2_CLUSTER_AXI_UV_ID_SHIFT, + desc->axi_uv_id); + break; + + case VOP2FB_LAYER_ESMART: + case VOP2FB_LAYER_SMART: + vop2fb_mask_write(vfb, base + VOP2_ESMART_AXI_CTRL, + VOP2_ESMART_AXI_ID_MASK, VOP2_ESMART_AXI_ID_SHIFT, desc->axi_id); + vop2fb_mask_write(vfb, base + VOP2_ESMART_CTRL1, + VOP2_ESMART_AXI_YRGB_ID_MASK, VOP2_ESMART_AXI_YRGB_ID_SHIFT, + desc->axi_yrgb_id); + vop2fb_mask_write(vfb, base + VOP2_ESMART_CTRL1, + VOP2_ESMART_AXI_UV_ID_MASK, VOP2_ESMART_AXI_UV_ID_SHIFT, + desc->axi_uv_id); + break; + } +} + +static void vop2fb_win_disable(struct vop2fb *vfb, const struct vop2fb_win_desc *desc) +{ + rt_uint32_t base = desc->base_offset; + + switch (desc->type) + { + case VOP2FB_LAYER_CLUSTER: + vop2fb_mask_write(vfb, base + VOP2_CLUSTER_WIN0_CTRL0, + VOP2_EN_MASK, VOP2_WIN_EN_SHIFT, 0); + vop2fb_mask_write(vfb, base + VOP2_CLUSTER_CTRL, + VOP2_EN_MASK, VOP2_CLUSTER_EN_SHIFT, 0); + break; + case VOP2FB_LAYER_ESMART: + case VOP2FB_LAYER_SMART: + vop2fb_mask_write(vfb, base + VOP2_REGION0_CTRL, + VOP2_EN_MASK, VOP2_WIN_EN_SHIFT, 0); + break; + } +} + +static rt_uint32_t vop2fb_scale_mode(rt_uint32_t src, rt_uint32_t dst) +{ + if (src == dst) + { + return 0; + } + + return src < dst ? 1 : 2; +} + +static rt_uint32_t vop2fb_scale_factor(rt_uint32_t mode, + rt_uint32_t src, rt_uint32_t dst) +{ + rt_uint32_t factor, shift; + int i; + + if (!mode || src < 2 || dst < 2) + { + return 0; + } + + shift = mode == 2 ? 12 : 16; + factor = (rt_uint32_t)(((rt_uint64_t)(src - 1) << shift) / + (dst - 1)); + + for (i = 0; i < 100 && factor; ++i) + { + if ((((rt_uint64_t)factor * (dst - 1)) >> shift) < src - 1) + { + break; + } + + factor--; + } + + return factor; +} + +static void vop2fb_smart_scale_setup(struct vop2fb *vfb, + const struct vop2fb_win_desc *desc, + rt_uint32_t src_w, rt_uint32_t src_h, + rt_uint32_t dst_w, rt_uint32_t dst_h) +{ + rt_uint32_t base, hmode, vmode, hfilter, vfilter; + rt_uint32_t hfactor, vfactor, scl_ctrl; + + if (!vfb->soc || vfb->soc->soc != VOP2FB_SOC_RK3568 || + (desc->type != VOP2FB_LAYER_ESMART && + desc->type != VOP2FB_LAYER_SMART)) + { + return; + } + + base = desc->base_offset; + hmode = vop2fb_scale_mode(src_w, dst_w); + vmode = vop2fb_scale_mode(src_h, dst_h); + + /* + * RK3568 Smart/Esmart filter encodings follow Linux VOP2: + * upscale uses bicubic (2), downscale uses bilinear (1). + */ + hfilter = hmode == 1 ? 2 : hmode == 2 ? 1 : 0; + vfilter = vmode == 1 ? 2 : vmode == 2 ? 1 : 0; + hfactor = vop2fb_scale_factor(hmode, src_w, dst_w); + vfactor = vop2fb_scale_factor(vmode, src_h, dst_h); + scl_ctrl = hmode | (hfilter << 2) | (vmode << 4) | (vfilter << 6); + + vop2fb_reg_write(vfb, base + VOP2_REGION0_SCL_CTRL, scl_ctrl); + vop2fb_reg_write(vfb, base + VOP2_REGION0_SCL_FACTOR_YRGB, + (vfactor << 16) | hfactor); + vop2fb_reg_write(vfb, base + VOP2_REGION0_SCL_FACTOR_CBR, + (vfactor << 16) | hfactor); +} + +static rt_err_t vop2fb_win_commit(struct vop2fb *vfb, rt_uint32_t vp_id, + const struct vop2fb_win_desc *desc, + rt_ubase_t dma_addr, rt_uint32_t mode, rt_uint32_t hw_fmt, + rt_uint32_t src_w, rt_uint32_t src_h, + rt_uint32_t dst_x, rt_uint32_t dst_y, + rt_uint32_t dst_w, rt_uint32_t dst_h, + rt_uint32_t xvir, rt_bool_t enable) +{ + rt_uint32_t base = desc->base_offset; + rt_uint32_t act_info, dsp_info, dsp_st; + + if (!enable) + { + vop2fb_win_disable(vfb, desc); + vop2fb_reg_write(vfb, VOP2_REG_CFG_DONE, + vop2fb_cfg_done_vp_val(vfb, vp_id)); + return RT_EOK; + } + + act_info = ((src_h - 1) << 16) | ((src_w - 1) & 0xffff); + dsp_info = ((dst_h - 1) << 16) | ((dst_w - 1) & 0xffff); + dsp_st = (dst_y << 16) | (dst_x & 0xffff); + + vop2fb_axi_config(vfb, desc); + vop2fb_rk3568_smart_prepare(vfb, desc, hw_fmt, mode); + vop2fb_smart_scale_setup(vfb, desc, src_w, src_h, dst_w, dst_h); + + switch (desc->type) + { + case VOP2FB_LAYER_CLUSTER: + vop2fb_mask_write(vfb, base + VOP2_CLUSTER_WIN0_CTRL0, + VOP2_WIN_FORMAT_MASK, VOP2_WIN_FORMAT_SHIFT, hw_fmt); + vop2fb_reg_write(vfb, base + VOP2_CLUSTER_WIN0_VIR, xvir); + vop2fb_reg_write(vfb, base + VOP2_CLUSTER_WIN0_YRGB_MST, (rt_uint32_t)dma_addr); + vop2fb_reg_write(vfb, base + VOP2_CLUSTER_WIN0_ACT_INFO, act_info); + vop2fb_reg_write(vfb, base + VOP2_CLUSTER_WIN0_DSP_INFO, dsp_info); + vop2fb_reg_write(vfb, base + VOP2_CLUSTER_WIN0_DSP_ST, dsp_st); + vop2fb_mask_write(vfb, base + VOP2_CLUSTER_WIN0_CTRL0, + VOP2_EN_MASK, VOP2_WIN_EN_SHIFT, 1); + vop2fb_mask_write(vfb, base + VOP2_CLUSTER_CTRL, + VOP2_EN_MASK, VOP2_CLUSTER_EN_SHIFT, 1); + break; + + case VOP2FB_LAYER_ESMART: + case VOP2FB_LAYER_SMART: + vop2fb_mask_write(vfb, base + VOP2_REGION0_CTRL, + VOP2_WIN_FORMAT_MASK, VOP2_WIN_FORMAT_SHIFT, hw_fmt); + vop2fb_reg_write(vfb, base + VOP2_REGION0_VIR, xvir); + vop2fb_reg_write(vfb, base + VOP2_REGION0_YRGB_MST, (rt_uint32_t)dma_addr); + vop2fb_reg_write(vfb, base + VOP2_REGION0_ACT_INFO, act_info); + vop2fb_reg_write(vfb, base + VOP2_REGION0_DSP_INFO, dsp_info); + vop2fb_reg_write(vfb, base + VOP2_REGION0_DSP_ST, dsp_st); + vop2fb_mask_write(vfb, base + VOP2_REGION0_CTRL, + VOP2_EN_MASK, VOP2_WIN_EN_SHIFT, 1); + break; + } + + vop2fb_reg_write(vfb, VOP2_REG_CFG_DONE, + vop2fb_cfg_done_vp_val(vfb, vp_id)); + vop2fb_rk3568_dump_win_regs(vfb, desc); + + return RT_EOK; +} + +static const struct vop2fb_win_desc *vop2fb_alloc_scanout(struct vop2fb *vfb, + rt_uint32_t vp_id) +{ + static const rt_uint8_t scanout_indices[] = { 2, 1 }; + rt_size_t i, j; + const struct vop2fb_win_desc *candidate; + + if (!vfb || !vfb->soc || vfb->soc->soc != VOP2FB_SOC_RK3568 || + vp_id >= VOP2FB_VP_MAX) + { + return RT_NULL; + } + + if (vfb->vp[vp_id].scanout) + { + return vfb->vp[vp_id].scanout; + } + + for (i = 0; i < RT_ARRAY_SIZE(scanout_indices); ++i) + { + candidate = &rk3568_overlays[scanout_indices[i]]; + + for (j = 0; j < VOP2FB_VP_MAX; ++j) + { + if (vfb->vp[j].scanout == candidate) + { + break; + } + } + + if (j == VOP2FB_VP_MAX) + { + return candidate; + } + } + + return RT_NULL; +} + +static rt_err_t vop2fb_plane_commit(struct rt_graphic_plane *plane, rt_bool_t enable) +{ + struct vop2fb *vfb = vop2fb_from_plane(plane); + struct vop2fb_plane_priv *priv = vop2fb_plane_priv(plane); + rt_err_t err; + rt_uint32_t xvir; + rt_ubase_t dma; + rt_uint32_t dst_w, dst_h, dst_x, dst_y; + + if (!priv || !priv->desc) + { + return -RT_EINVAL; + } + + if (!enable || !plane->framebuffer) + { + priv->enabled = RT_FALSE; + rt_spin_lock(&vfb->reg_lock); + vop2fb_win_disable(vfb, priv->desc); + vop2fb_reg_write(vfb, VOP2_REG_CFG_DONE, + vop2fb_cfg_done_vp_val(vfb, priv->vp_id)); + rt_spin_unlock(&vfb->reg_lock); + + return RT_EOK; + } + + if (!vfb->powered) + { + priv->enabled = RT_TRUE; + return RT_EOK; + } + + if (priv->dma_flags & RT_DMA_F_NOCACHE) + { + dma = priv->dma_handle + priv->pan_offset; + } + else + { + /* + * RK3568 VOP is non-coherent. The generic DMA fallback currently + * treats a non-coherent device as if its allocation were uncached, + * so sync_out_data() can skip the writeback for this cached LINEAR + * framebuffer. Flush it explicitly before the continuously running + * scanout engine reads it. + */ + rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, + plane->framebuffer + priv->pan_offset, plane->screen_len); + dma = priv->dma_handle + priv->pan_offset; + } + + xvir = vop2fb_xvir(plane->line_length); + + if (plane->type == RT_GRAPHIC_PLANE_TYPE_PRIMARY) + { + dst_x = 0; + dst_y = 0; + dst_w = plane->width; + dst_h = plane->height; + } + else + { + dst_x = plane->x; + dst_y = plane->y; + dst_w = plane->width; + dst_h = plane->height; + } + + priv->enabled = RT_TRUE; + + rt_spin_lock(&vfb->reg_lock); + + if (priv->desc->mix_alpha_reg) + { + vop2fb_mix_alpha_set(vfb, priv->desc->mix_alpha_reg, plane->alpha); + } + + LOG_D("%s commit: dma=0x%08x xvir=%u src=%ux%u dst=%u,%u %ux%u pitch=%u alpha=%u", + plane->name, (rt_uint32_t)dma, xvir, + plane->width, plane->height, + dst_x, dst_y, dst_w, dst_h, + plane->line_length, plane->alpha); + + err = vop2fb_win_commit(vfb, priv->vp_id, priv->desc, dma, + plane->mode, vop2fb_mode_to_hw(plane->mode), + plane->width, plane->height, dst_x, dst_y, dst_w, dst_h, + xvir, RT_TRUE); + + rt_spin_unlock(&vfb->reg_lock); + + return err; +} + +static void vop2fb_fill_primary_background(struct rt_graphic_plane *plane) +{ + rt_uint8_t *fb; + rt_size_t pixels, i; + + if (!plane || !plane->framebuffer || !plane->framebuffer_len) + { + return; + } + + fb = plane->framebuffer; + + if (plane->bits_per_pixel != 32) + { + rt_memset(fb, 0, plane->framebuffer_len); + return; + } + + pixels = plane->framebuffer_len / sizeof(rt_uint32_t); + + for (i = 0; i < pixels; ++i) + { + ((rt_uint32_t *)fb)[i] = 0xff000000; + } +} + +static void vop2fb_plane_free_fb(struct rt_graphic_plane *plane) +{ + struct vop2fb *vfb = vop2fb_from_plane(plane); + struct vop2fb_plane_priv *priv = vop2fb_plane_priv(plane); + struct rt_device *dev = vfb->dev; + + if (plane->framebuffer) + { + rt_dma_free(dev, 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; + } +} + +/* -------------------------------------------------------------------------- */ +/* Plane ops */ +/* -------------------------------------------------------------------------- */ + +static rt_err_t vop2fb_plane_update(struct rt_graphic_plane *plane, + struct rt_device_rect_info *rect) +{ + struct vop2fb_plane_priv *priv = vop2fb_plane_priv(plane); + + RT_UNUSED(rect); + + if (priv) + { + priv->enabled = RT_TRUE; + } + + return vop2fb_plane_commit(plane, RT_TRUE); +} + +static rt_err_t vop2fb_plane_fb_remap(struct rt_graphic_plane *plane, + rt_uint32_t mode, struct rt_device_rect_info *rect) +{ + rt_err_t err; + struct vop2fb *vfb = vop2fb_from_plane(plane); + struct vop2fb_plane_priv *priv = vop2fb_plane_priv(plane); + struct rt_device *dev = vfb->dev; + rt_uint32_t bpp = rt_graphic_mode_bpp(mode); + rt_size_t screen_len, fb_len; + rt_ubase_t dma_flags; + void *fb; + + if (!rect->width || !rect->height || !bpp) + { + return -RT_EINVAL; + } + + vop2fb_plane_free_fb(plane); + + plane->line_length = RT_ALIGN(rect->width * bpp, 32) / 8; + plane->bits_per_pixel = bpp; + screen_len = plane->line_length * rect->height; + + if (plane->type == RT_GRAPHIC_PLANE_TYPE_PRIMARY) + { + fb_len = screen_len * 2; + dma_flags = RT_DMA_F_LINEAR; + } + else + { + fb_len = screen_len; + dma_flags = RT_DMA_F_NOCACHE | RT_DMA_F_LINEAR; + } + + fb = rt_dma_alloc(dev, fb_len, &priv->dma_handle, dma_flags); + + if (!fb && plane->type == RT_GRAPHIC_PLANE_TYPE_PRIMARY && fb_len > screen_len) + { + LOG_W("%s: alloc double buffer failed, fallback to single buffer", plane->name); + fb_len = screen_len; + fb = rt_dma_alloc(dev, fb_len, &priv->dma_handle, dma_flags); + } + + if (!fb) + { + LOG_E("%s: alloc fb failed mode=%u rect=%ux%u fb_len=%u", + plane->name, mode, rect->width, rect->height, (unsigned)fb_len); + return -RT_ENOMEM; + } + + rt_memset(fb, 0, fb_len); + + plane->framebuffer = fb; + plane->screen_len = screen_len; + plane->framebuffer_len = fb_len; + plane->width = rect->width; + plane->height = rect->height; + plane->mode = mode; + priv->dma_flags = dma_flags; + priv->pan_offset = 0; + + if (plane->type == RT_GRAPHIC_PLANE_TYPE_PRIMARY) + { + vop2fb_fill_primary_background(plane); + } + + if (vfb->powered && plane->type == RT_GRAPHIC_PLANE_TYPE_PRIMARY) + { + err = vop2fb_plane_commit(plane, RT_TRUE); + } + else + { + err = RT_EOK; + } + + return err; +} + +static rt_err_t vop2fb_plane_fb_pan_display(struct rt_graphic_plane *plane, + struct rt_device_rect_info *rect) +{ + struct vop2fb_plane_priv *priv = vop2fb_plane_priv(plane); + + if (rect->width != plane->width || rect->height != plane->height) + { + return vop2fb_plane_fb_remap(plane, plane->mode, rect); + } + + if (plane->framebuffer_len <= plane->screen_len) + { + plane->x = rect->x; + plane->y = rect->y; + return RT_EOK; + } + + priv->pan_offset = rect->y * plane->line_length + rect->x * (plane->bits_per_pixel / 8); + + if (priv->pan_offset + plane->screen_len > plane->framebuffer_len) + { + priv->pan_offset = 0; + return -RT_EINVAL; + } + + plane->x = rect->x; + plane->y = rect->y; + + return vop2fb_plane_commit(plane, RT_TRUE); +} + +static rt_err_t vop2fb_plane_fb_cleanup(struct rt_graphic_plane *plane) +{ + struct vop2fb *vfb = vop2fb_from_plane(plane); + struct vop2fb_plane_priv *priv = vop2fb_plane_priv(plane); + + if (priv && priv->enabled && priv->desc) + { + rt_spin_lock(&vfb->reg_lock); + vop2fb_win_disable(vfb, priv->desc); + vop2fb_reg_write(vfb, VOP2_REG_CFG_DONE, + vop2fb_cfg_done_vp_val(vfb, priv->vp_id)); + rt_spin_unlock(&vfb->reg_lock); + priv->enabled = RT_FALSE; + } + + vop2fb_plane_free_fb(plane); + + return RT_EOK; +} + +static rt_err_t vop2fb_plane_prop_set(struct rt_graphic_plane *plane, + enum rt_graphic_plane_prop prop, void *value) +{ + struct vop2fb *vfb = vop2fb_from_plane(plane); + struct vop2fb_plane_priv *priv = vop2fb_plane_priv(plane); + rt_uint32_t base; + + if (!priv || !priv->desc) + { + return -RT_EINVAL; + } + + base = priv->desc->base_offset; + + switch (prop) + { + case RT_GRAPHIC_PLANE_PROP_Z: + if (value) + { + plane->z = (rt_uint32_t)(rt_ubase_t)value; + } + return RT_EOK; + + case RT_GRAPHIC_PLANE_PROP_ALPHA: + if (value) + { + plane->alpha = (rt_uint8_t)(rt_ubase_t)value; + + if (priv->desc->mix_alpha_reg) + { + rt_spin_lock(&vfb->reg_lock); + vop2fb_mix_alpha_set(vfb, priv->desc->mix_alpha_reg, plane->alpha); + vop2fb_reg_write(vfb, VOP2_REG_CFG_DONE, + vop2fb_cfg_done_vp_val(vfb, priv->vp_id)); + rt_spin_unlock(&vfb->reg_lock); + } + } + return RT_EOK; + + case RT_GRAPHIC_PLANE_PROP_ROTATE: + if (value) + { + rt_uint8_t rot = (rt_uint8_t)(rt_ubase_t)value; + + plane->rotate = rot; + + if (priv->desc->type == VOP2FB_LAYER_ESMART || + priv->desc->type == VOP2FB_LAYER_SMART) + { + rt_spin_lock(&vfb->reg_lock); + vop2fb_mask_write(vfb, base + VOP2_ESMART_CTRL1, + VOP2_EN_MASK, VOP2_YMIRROR_EN_SHIFT, + rot == RT_GRAPHIC_PLANE_ROTATE_180 ? 1 : 0); + vop2fb_reg_write(vfb, VOP2_REG_CFG_DONE, + vop2fb_cfg_done_vp_val(vfb, priv->vp_id)); + rt_spin_unlock(&vfb->reg_lock); + } + } + return RT_EOK; + + default: + return -RT_ENOSYS; + } +} + +static const struct rt_graphic_plane_ops vop2fb_primary_ops = +{ + .update = vop2fb_plane_update, + .fb_remap = vop2fb_plane_fb_remap, + .fb_pan_display = vop2fb_plane_fb_pan_display, + .fb_cleanup = vop2fb_plane_fb_cleanup, + .prop_set = vop2fb_plane_prop_set, +}; + +static const struct rt_graphic_plane_ops vop2fb_overlay_ops = +{ + .update = vop2fb_plane_update, + .fb_remap = vop2fb_plane_fb_remap, + .fb_cleanup = vop2fb_plane_fb_cleanup, + .prop_set = vop2fb_plane_prop_set, +}; + +static const struct rt_graphic_plane_ops vop2fb_cursor_ops = +{ + .update = vop2fb_plane_update, + .fb_remap = vop2fb_plane_fb_remap, + .fb_cleanup = vop2fb_plane_fb_cleanup, +}; + +/* -------------------------------------------------------------------------- */ +/* Device ops */ +/* -------------------------------------------------------------------------- */ + +static struct rt_clk *vop2fb_clk_find(struct vop2fb *vfb, const char *name) +{ + rt_size_t i; + + if (!vfb || rt_is_err_or_null(vfb->clks) || !name) + { + return RT_NULL; + } + + for (i = 0; i < vfb->clks->count; ++i) + { + struct rt_clk *clk = vfb->clks->clks[i]; + + if (!rt_is_err_or_null(clk) && clk->con_id && + !rt_strcmp(clk->con_id, name)) + { + return clk; + } + } + + return RT_NULL; +} + +static rt_err_t vop2fb_clk_enable(struct vop2fb *vfb) +{ + struct rt_clk *hclk, *aclk, *pclk; + rt_err_t err; + + if (vfb->clk_enabled) + { + return RT_EOK; + } + + hclk = vop2fb_clk_find(vfb, "hclk_vop"); + aclk = vop2fb_clk_find(vfb, "aclk_vop"); + pclk = vop2fb_clk_find(vfb, "pclk_vop"); + + if (!hclk || !aclk) + { + LOG_E("vop2: missing core clock hclk_vop=%s aclk_vop=%s", + hclk ? "yes" : "no", aclk ? "yes" : "no"); + return -RT_ENOENT; + } + + if ((err = rt_clk_prepare_enable(hclk))) + { + return err; + } + + if ((err = rt_clk_prepare_enable(aclk))) + { + rt_clk_disable_unprepare(hclk); + return err; + } + + if (pclk && (err = rt_clk_prepare_enable(pclk))) + { + rt_clk_disable_unprepare(aclk); + rt_clk_disable_unprepare(hclk); + return err; + } + + vfb->clk_enabled = RT_TRUE; + + return RT_EOK; +} + +static void vop2fb_clk_disable(struct vop2fb *vfb) +{ + struct rt_clk *hclk, *aclk, *pclk; + + if (!vfb->clk_enabled) + { + return; + } + + hclk = vop2fb_clk_find(vfb, "hclk_vop"); + aclk = vop2fb_clk_find(vfb, "aclk_vop"); + pclk = vop2fb_clk_find(vfb, "pclk_vop"); + + if (pclk) + { + rt_clk_disable_unprepare(pclk); + } + if (aclk) + { + rt_clk_disable_unprepare(aclk); + } + if (hclk) + { + rt_clk_disable_unprepare(hclk); + } + + vfb->clk_enabled = RT_FALSE; +} + +static struct rt_clk *vop2fb_vp_clk_find(struct vop2fb *vfb, + rt_uint32_t vp_id) +{ + char name[16]; + struct rt_clk *clk; + + rt_snprintf(name, sizeof(name), "dclk_vp%u", vp_id); + clk = vop2fb_clk_find(vfb, name); + + if (!clk) + { + rt_snprintf(name, sizeof(name), "dclk_vop%u", vp_id); + clk = vop2fb_clk_find(vfb, name); + } + + return clk; +} + +static rt_err_t vop2fb_vp_clk_enable(struct vop2fb *vfb, rt_uint32_t vp_id) +{ + rt_err_t err; + struct rt_clk *dclk; + struct vop2fb_vp_state *state; + + if (!vfb || vp_id >= vfb->soc->vp_count || vp_id >= VOP2FB_VP_MAX) + { + return -RT_EINVAL; + } + + state = &vfb->vp[vp_id]; + + if (state->dclk_enabled) + { + return RT_EOK; + } + + dclk = vop2fb_vp_clk_find(vfb, vp_id); + if (!dclk) + { + return -RT_ENOENT; + } + + err = rt_clk_prepare_enable(dclk); + if (!err) + { + state->dclk_enabled = RT_TRUE; + } + + return err; +} + +static void vop2fb_vp_clk_disable(struct vop2fb *vfb, rt_uint32_t vp_id) +{ + struct rt_clk *dclk; + struct vop2fb_vp_state *state; + + if (!vfb || vp_id >= vfb->soc->vp_count || vp_id >= VOP2FB_VP_MAX) + { + return; + } + + state = &vfb->vp[vp_id]; + if (!state->dclk_enabled) + { + return; + } + + dclk = vop2fb_vp_clk_find(vfb, vp_id); + if (dclk) + { + rt_clk_disable_unprepare(dclk); + } + + state->dclk_enabled = RT_FALSE; +} + +static void vop2fb_output_wins_disable(struct vop2fb_vp_state *state) +{ + rt_size_t i; + struct vop2fb *vfb; + + if (!state || !(vfb = state->vfb)) + { + return; + } + + if (state->primary) + { + vop2fb_plane_commit(state->primary, RT_FALSE); + } + + if (state->graphic != &vfb->parent) + { + return; + } + + if (vfb->cursor) + { + vop2fb_plane_commit(vfb->cursor, RT_FALSE); + } + + for (i = 0; i < vfb->overlay_count; ++i) + { + if (vfb->overlays[i]) + { + vop2fb_plane_commit(vfb->overlays[i], RT_FALSE); + } + } +} + +static rt_err_t vop2fb_output_wins_enable(struct vop2fb_vp_state *state) +{ + rt_err_t err; + rt_size_t i; + struct vop2fb *vfb; + + if (!state || !(vfb = state->vfb)) + { + return -RT_EINVAL; + } + + if (state->primary && state->primary->framebuffer) + { + if ((err = vop2fb_plane_commit(state->primary, RT_TRUE))) + { + return err; + } + } + + if (state->graphic != &vfb->parent) + { + return RT_EOK; + } + + for (i = 0; i < vfb->overlay_count; ++i) + { + struct rt_graphic_plane *plane = vfb->overlays[i]; + struct vop2fb_plane_priv *priv; + + if (!plane || !plane->framebuffer) + { + continue; + } + + priv = vop2fb_plane_priv(plane); + + if (priv && priv->enabled) + { + vop2fb_plane_commit(plane, RT_TRUE); + } + } + + if (vfb->cursor && vfb->cursor->framebuffer) + { + struct vop2fb_plane_priv *priv = vop2fb_plane_priv(vfb->cursor); + + if (priv && priv->enabled) + { + vop2fb_plane_commit(vfb->cursor, RT_TRUE); + } + } + + return RT_EOK; +} + +static rt_err_t vop2fb_dpms_switch(struct rt_graphic_device *gdev, rt_uint32_t dpms) +{ + rt_err_t err; + struct vop2fb_vp_state *state = vop2fb_output_from_graphic(gdev); + + if (!state || !state->vfb) + { + return -RT_EINVAL; + } + + switch (dpms) + { + case RT_GRAPHIC_DPMS_ON: + err = vop2fb_output_wins_enable(state); + break; + + case RT_GRAPHIC_DPMS_STANDBY: + case RT_GRAPHIC_DPMS_SUSPEND: + vop2fb_output_wins_disable(state); + err = RT_EOK; + break; + + case RT_GRAPHIC_DPMS_OFF: + vop2fb_output_wins_disable(state); + err = RT_EOK; + break; + + default: + return -RT_EINVAL; + } + + gdev->dpms = dpms; + + return err; +} + +static rt_err_t vop2fb_wait_vsync(struct rt_graphic_device *gdev) +{ + struct vop2fb_vp_state *state = vop2fb_output_from_graphic(gdev); + struct vop2fb *vfb; + rt_err_t err; + + if (!state || !(vfb = state->vfb)) + { + return -RT_EINVAL; + } + + /* No frame can arrive before a route has completed fb registration. */ + if (!state->registered) + { + return RT_EOK; + } + + if (vfb->irq >= 0) + { + if ((err = rt_mutex_take(&state->vsync_lock, + rt_tick_from_millisecond(100)))) + { + LOG_W("vop2: wait vsync lock timeout on vp%u", state->vp_id); + return err; + } + + /* + * Do not consume an interrupt token left by an older frame. The ISR + * only releases the semaphore on the 0 -> 1 transition, so this also + * prevents the semaphore count from growing while nobody is waiting. + */ + rt_atomic_store(&state->vsync, 0); + + while (rt_sem_trytake(&state->vsync_sem) == RT_EOK) + { + } + + if (rt_atomic_load(&state->vsync)) + { + err = RT_EOK; + goto _unlock; + } + + if (rt_sem_take(&state->vsync_sem, rt_tick_from_millisecond(100)) == RT_EOK) + { + err = RT_EOK; + goto _unlock; + } + + LOG_W("vop2: wait vsync timeout on vp%u", state->vp_id); + err = -RT_ETIMEOUT; + +_unlock: + rt_mutex_release(&state->vsync_lock); + + return err; + } + + rt_thread_mdelay(16); + + return RT_EOK; +} + +static const struct rt_graphic_device_ops vop2fb_ops = +{ + .dpms_switch = vop2fb_dpms_switch, + .wait_vsync = vop2fb_wait_vsync, +}; + +static void vop2fb_rk3568_irqs_quiesce(struct vop2fb *vfb) +{ + rt_uint32_t vp_id; + const rt_uint32_t vp_irqs = 0xffff; + const rt_uint32_t sys_irqs = 0xfe; + + if (!vfb || !vfb->regs || !vfb->soc || + vfb->soc->soc != VOP2FB_SOC_RK3568 || !vfb->clk_enabled) + { + return; + } + + /* + * The merged VOP2 interrupt is level-triggered. Mask and clear every + * source before exposing it to GIC, including state inherited from the + * bootloader on VPs that RT-Thread does not use. + */ + for (vp_id = 0; vp_id < vfb->soc->vp_count && + vp_id < VOP2FB_VP_MAX; ++vp_id) + { + HWREG32((rt_uint8_t *)vfb->regs + RK3568_VP_INT_EN(vp_id)) = + vp_irqs << 16; + HWREG32((rt_uint8_t *)vfb->regs + RK3568_VP_INT_CLR(vp_id)) = + (vp_irqs << 16) | vp_irqs; + } + + HWREG32((rt_uint8_t *)vfb->regs + RK3568_SYS0_INT_EN) = sys_irqs << 16; + HWREG32((rt_uint8_t *)vfb->regs + RK3568_SYS0_INT_CLR) = + (sys_irqs << 16) | sys_irqs; + HWREG32((rt_uint8_t *)vfb->regs + RK3568_SYS1_INT_EN) = sys_irqs << 16; + HWREG32((rt_uint8_t *)vfb->regs + RK3568_SYS1_INT_CLR) = + (sys_irqs << 16) | sys_irqs; +} + +static void vop2fb_isr(int irqno, void *param) +{ + struct vop2fb *vfb = param; + rt_uint32_t vp_id, vp_mask, irqs, sys0_irqs, sys1_irqs; + rt_uint32_t vp_irqs[VOP2FB_VP_MAX] = { 0 }; + rt_bool_t pending = RT_FALSE; + + RT_UNUSED(irqno); + + if (!vfb || !vfb->regs) + { + return; + } + + sys0_irqs = HWREG32((rt_uint8_t *)vfb->regs + RK3568_SYS0_INT_STATUS) & + RK3568_SYS_BUS_ERROR_INTR; + sys1_irqs = HWREG32((rt_uint8_t *)vfb->regs + RK3568_SYS1_INT_STATUS) & + RK3568_SYS_BUS_ERROR_INTR; + vp_mask = vfb->configured_vp_mask | vfb->active_vp_mask; + + for (vp_id = 0; vp_id < vfb->soc->vp_count && + vp_id < VOP2FB_VP_MAX; ++vp_id) + { + vp_irqs[vp_id] = + HWREG32((rt_uint8_t *)vfb->regs + RK3568_VP_INT_STATUS(vp_id)); + pending |= vp_irqs[vp_id] ? RT_TRUE : RT_FALSE; + } + + if (!pending && !sys0_irqs && !sys1_irqs) + { + return; + } + + if (sys0_irqs) + { + HWREG32((rt_uint8_t *)vfb->regs + RK3568_SYS0_INT_CLR) = + (sys0_irqs << 16) | sys0_irqs; + vfb->axi_bus_error_count[0]++; + + if (!(vfb->axi_bus_error_count[0] & (vfb->axi_bus_error_count[0] - 1))) + { + LOG_W("vop2: AXI0 bus error count=%u", vfb->axi_bus_error_count[0]); + } + } + + if (sys1_irqs) + { + HWREG32((rt_uint8_t *)vfb->regs + RK3568_SYS1_INT_CLR) = + (sys1_irqs << 16) | sys1_irqs; + vfb->axi_bus_error_count[1]++; + + if (!(vfb->axi_bus_error_count[1] & (vfb->axi_bus_error_count[1] - 1))) + { + LOG_W("vop2: AXI1 bus error count=%u", vfb->axi_bus_error_count[1]); + } + } + + for (vp_id = 0; vp_id < vfb->soc->vp_count && + vp_id < VOP2FB_VP_MAX; ++vp_id) + { + irqs = vp_irqs[vp_id]; + + if (!irqs) + { + continue; + } + + HWREG32((rt_uint8_t *)vfb->regs + RK3568_VP_INT_CLR(vp_id)) = + (irqs << 16) | irqs; + + if (!(vp_mask & RT_BIT(vp_id))) + { + continue; + } + + if (irqs & VOP2_VP_POST_BUF_EMPTY_INTR) + { + vfb->post_buf_empty_count[vp_id]++; + + if (!(vfb->post_buf_empty_count[vp_id] & + (vfb->post_buf_empty_count[vp_id] - 1))) + { + LOG_W("vop2: vp%u post buffer empty count=%u", + vp_id, vfb->post_buf_empty_count[vp_id]); + } + } + + if (!(irqs & VOP2_VP_FS_FIELD_INTR) || + !vfb->vp[vp_id].ipc_ready) + { + continue; + } + + if (rt_atomic_exchange(&vfb->vp[vp_id].vsync, 1) == 0) + { + rt_sem_release(&vfb->vp[vp_id].vsync_sem); + } + } +} + +/* -------------------------------------------------------------------------- */ +/* Plane setup */ +/* -------------------------------------------------------------------------- */ + +static void vop2fb_plane_init_fb_state(struct rt_graphic_plane *plane, rt_uint32_t mode) +{ + rt_uint32_t bpp = rt_graphic_mode_bpp(mode); + + plane->mode = mode; + plane->bits_per_pixel = bpp; + plane->line_length = RT_ALIGN(plane->width * bpp, 32) / 8; + plane->screen_len = plane->line_length * plane->height; + plane->framebuffer = RT_NULL; + plane->framebuffer_len = 0; +} + +static void vop2fb_primary_plane_prepare_register(struct rt_graphic_plane *plane) +{ + plane->x = 0; + plane->y = 0; + plane->width = 0; + plane->height = 0; + plane->line_length = 0; + plane->screen_len = 0; + plane->framebuffer = RT_NULL; + plane->framebuffer_len = 0; +} + +static void vop2fb_clear_plane_refs(struct vop2fb *vfb) +{ + rt_size_t i; + + vfb->primary = RT_NULL; + vfb->cursor = RT_NULL; + + for (i = 0; i < RT_ARRAY_SIZE(vfb->overlays); ++i) + { + vfb->overlays[i] = RT_NULL; + } +} + +static void vop2fb_clear_output_refs(struct vop2fb_vp_state *state) +{ + struct vop2fb *vfb; + + if (!state || !(vfb = state->vfb)) + { + return; + } + + if (state->graphic == &vfb->parent) + { + vop2fb_clear_plane_refs(vfb); + vfb->registered = RT_FALSE; + } + + state->primary = RT_NULL; + state->registered = RT_FALSE; +} + +static rt_err_t vop2fb_cleanup_planes(struct vop2fb *vfb) +{ + rt_uint32_t vp_id; + rt_size_t i; + rt_err_t err; + + for (vp_id = 0; vp_id < vfb->soc->vp_count && + vp_id < VOP2FB_VP_MAX; ++vp_id) + { + struct vop2fb_vp_state *state = &vfb->vp[vp_id]; + + if (state->registered) + { + err = rt_graphic_device_unregister(state->graphic); + if (err) + { + return err; + } + vop2fb_clear_output_refs(state); + } + else if (state->primary && state->graphic) + { + rt_graphic_device_del_plane(state->graphic, state->primary); + rt_graphic_device_free_plane(state->primary); + if (state->graphic == &vfb->parent) + { + vfb->primary = RT_NULL; + } + state->primary = RT_NULL; + } + } + + /* + * Probe creates the first primary before a route chooses its VP. Release + * it here if no route ever claimed it. + */ + for (i = 0; i < vfb->overlay_count; ++i) + { + if (vfb->overlays[i]) + { + rt_graphic_device_del_plane(&vfb->parent, vfb->overlays[i]); + rt_graphic_device_free_plane(vfb->overlays[i]); + vfb->overlays[i] = RT_NULL; + } + } + + if (vfb->cursor) + { + rt_graphic_device_del_plane(&vfb->parent, vfb->cursor); + rt_graphic_device_free_plane(vfb->cursor); + vfb->cursor = RT_NULL; + } + + if (vfb->primary) + { + rt_graphic_device_del_plane(&vfb->parent, vfb->primary); + rt_graphic_device_free_plane(vfb->primary); + vfb->primary = RT_NULL; + } + + return RT_EOK; +} + +static rt_err_t vop2fb_plane_init(struct vop2fb *vfb, + struct vop2fb_vp_state *state, + struct rt_graphic_plane *plane, + const struct vop2fb_win_desc *desc, + rt_uint32_t width, rt_uint32_t height, + rt_uint8_t type) +{ + struct vop2fb_plane_priv *priv = vop2fb_plane_priv(plane); + + priv->vfb = vfb; + priv->desc = desc; + priv->enabled = RT_FALSE; + priv->pan_offset = 0; + priv->vp_id = state->vp_id; + plane->z = desc->z_order; + plane->alpha = 0xff; + + if (type == RT_GRAPHIC_PLANE_TYPE_CURSOR) + { + plane->width = VOP2FB_CURSOR_W; + plane->height = VOP2FB_CURSOR_H; + } + else if (type == RT_GRAPHIC_PLANE_TYPE_OVERLAY) + { + plane->width = width / 4; + plane->height = height / 4; + plane->x = plane->width; + plane->y = plane->height; + } + else + { + plane->width = width; + plane->height = height; + } + + vop2fb_plane_init_fb_state(plane, RTGRAPHIC_PIXEL_FORMAT_ARGB888); + + return RT_EOK; +} + +static rt_err_t vop2fb_primary_plane_create(struct vop2fb *vfb, + struct vop2fb_vp_state *state, + const struct vop2fb_win_desc *desc, + rt_uint32_t width, rt_uint32_t height) +{ + rt_err_t err; + struct rt_graphic_plane *plane; + struct rt_graphic_device *gdev = state->graphic; + + plane = rt_graphic_device_alloc_plane(gdev, sizeof(struct vop2fb_plane_priv), + &vop2fb_primary_ops, vop2fb_modes, RT_ARRAY_SIZE(vop2fb_modes), + RT_GRAPHIC_PLANE_TYPE_PRIMARY); + + if (!plane) + { + return -RT_ENOMEM; + } + + if ((err = rt_graphic_device_add_plane(gdev, plane))) + { + rt_graphic_device_free_plane(plane); + return err; + } + + state->primary = plane; + if (gdev == &vfb->parent) + { + vfb->primary = plane; + } + + err = vop2fb_plane_init(vfb, state, plane, desc, width, height, + RT_GRAPHIC_PLANE_TYPE_PRIMARY); + if (err) + { + rt_graphic_device_del_plane(gdev, plane); + state->primary = RT_NULL; + if (gdev == &vfb->parent) + { + vfb->primary = RT_NULL; + } + rt_graphic_device_free_plane(plane); + return err; + } + + vop2fb_primary_plane_prepare_register(plane); + + return RT_EOK; +} + +static rt_err_t vop2fb_overlay_planes_create(struct vop2fb *vfb, + struct vop2fb_vp_state *state, + rt_uint32_t width, rt_uint32_t height) +{ + rt_err_t err; + rt_size_t i; + struct rt_graphic_plane *plane; + + for (i = 0; i < vfb->overlay_count; ++i) + { + plane = rt_graphic_device_alloc_plane(&vfb->parent, sizeof(struct vop2fb_plane_priv), + &vop2fb_overlay_ops, vop2fb_modes, RT_ARRAY_SIZE(vop2fb_modes), + RT_GRAPHIC_PLANE_TYPE_OVERLAY); + + if (!plane) + { + return -RT_ENOMEM; + } + + rt_snprintf(plane->name, sizeof(plane->name), "ovl-%s", vfb->soc->overlays[i].name); + + if ((err = rt_graphic_device_add_plane(&vfb->parent, plane))) + { + rt_graphic_device_free_plane(plane); + return err; + } + + vfb->overlays[i] = plane; + + if ((err = vop2fb_plane_init(vfb, state, plane, &vfb->soc->overlays[i], + width, height, RT_GRAPHIC_PLANE_TYPE_OVERLAY))) + { + return err; + } + } + + return RT_EOK; +} + +static rt_err_t vop2fb_cursor_plane_create(struct vop2fb *vfb, + struct vop2fb_vp_state *state, + rt_uint32_t width, rt_uint32_t height) +{ + rt_err_t err; + struct rt_graphic_plane *plane; + + plane = rt_graphic_device_alloc_plane(&vfb->parent, sizeof(struct vop2fb_plane_priv), + &vop2fb_cursor_ops, vop2fb_modes, RT_ARRAY_SIZE(vop2fb_modes), + RT_GRAPHIC_PLANE_TYPE_CURSOR); + + if (!plane) + { + return -RT_ENOMEM; + } + + if ((err = rt_graphic_device_add_plane(&vfb->parent, plane))) + { + rt_graphic_device_free_plane(plane); + return err; + } + + vfb->cursor = plane; + + return vop2fb_plane_init(vfb, state, plane, vfb->soc->cursor, width, height, + RT_GRAPHIC_PLANE_TYPE_CURSOR); +} + +/* -------------------------------------------------------------------------- */ +/* Display pipeline hooks */ +/* -------------------------------------------------------------------------- */ + +static rt_err_t vop2fb_crtc_mode_set(void *priv, + const struct display_route *route, const struct display_timing *tim) +{ + struct vop2fb *vfb = priv; + struct vop2fb_vp_state *state; + const struct vop2fb_win_desc *saved_scanout; + enum vop2fb_output_if saved_output_if; + enum vop2fb_output_if state_output_if; + struct display_timing state_timing; + struct display_timing saved_timing; + rt_uint32_t saved_vp, saved_w, saved_h; + rt_bool_t state_mode_valid; + rt_bool_t saved_timing_valid; + rt_bool_t primary_output; + rt_err_t err; + rt_uint32_t vp_id; + + if (!vfb || !route || !tim) + { + return -RT_EINVAL; + } + + vp_id = route->vp_id; + + if (vp_id >= vfb->soc->vp_count || + vp_id >= VOP2FB_VP_MAX) + { + return -RT_EINVAL; + } + + saved_vp = vfb->vp_id; + saved_output_if = vfb->output_if; + saved_timing = vfb->output_tim; + saved_timing_valid = vfb->output_tim_valid; + saved_w = vfb->display_w; + saved_h = vfb->display_h; + primary_output = !saved_timing_valid || vp_id == saved_vp; + state = &vfb->vp[vp_id]; + state_timing = state->timing; + state_output_if = state->output_if; + saved_scanout = state->scanout; + state_mode_valid = state->mode_valid; + + vfb->vp_id = vp_id; + vfb->output_if = vop2fb_output_from_connector(route->connector_np); + + if (vfb->output_if == VOP2FB_OUTPUT_NONE) + { + err = -RT_ENOSYS; + goto _restore; + } + + state->timing = *tim; + state->output_if = vfb->output_if; + state->mode_valid = RT_TRUE; + + if (primary_output) + { + state->scanout = vfb->soc->primary; + state->graphic = &vfb->parent; + } + else + { + state->scanout = vop2fb_alloc_scanout(vfb, vp_id); + + if (!state->scanout) + { + state->mode_valid = RT_FALSE; + err = -RT_ENOSYS; + goto _restore; + } + + state->graphic = &state->auxiliary; + } + + state->vfb = vfb; + state->vp_id = vp_id; + state->graphic->ops = &vop2fb_ops; + state->graphic->parent.ofw_node = vfb->dev->ofw_node; + state->graphic->parent.user_data = state; + + err = vop2fb_vp_mode_set(vfb, vp_id, tim); + + if (err) + { + state->mode_valid = RT_FALSE; + goto _restore; + } + + if (!state->primary && + (err = vop2fb_primary_plane_create(vfb, state, state->scanout, + tim->hactive, tim->vactive))) + { + state->mode_valid = RT_FALSE; + goto _restore; + } + + vfb->configured_vp_mask |= RT_BIT(vp_id); + + if (primary_output) + { + vfb->output_tim = *tim; + vfb->output_tim_valid = RT_TRUE; + vfb->display_w = tim->hactive; + vfb->display_h = tim->vactive; + return RT_EOK; + } + +_restore: + if (err) + { + state->timing = state_timing; + state->output_if = state_output_if; + state->scanout = saved_scanout; + state->mode_valid = state_mode_valid; + } + vfb->vp_id = saved_vp; + vfb->output_if = saved_output_if; + vfb->output_tim = saved_timing; + vfb->output_tim_valid = saved_timing_valid; + vfb->display_w = saved_w; + vfb->display_h = saved_h; + + return err; +} + +static rt_err_t vop2fb_graphic_register(struct vop2fb *vfb, rt_uint32_t vp_id) +{ + rt_err_t err; + struct vop2fb_vp_state *state = &vfb->vp[vp_id]; + struct rt_graphic_device *gdev = state->graphic; + rt_uint32_t width = state->timing.hactive; + rt_uint32_t height = state->timing.vactive; + + if (state->registered) + { + LOG_D("vop2: graphic device already registered on vp%u", vp_id); + return RT_EOK; + } + + if (!gdev || !state->primary || !width || !height) + { + LOG_W("vop2: register skipped primary=%p size=%ux%u", + state->primary, width, height); + return -RT_EINVAL; + } + + LOG_D("vop2: register graphic device %ux%u on vp%u", + width, height, vp_id); + rt_graphic_device_simple_edid(gdev, width, height, 60); + vop2fb_primary_plane_prepare_register(state->primary); + + if ((err = rt_graphic_device_register(gdev))) + { + LOG_E("vop2: register vp%u graphic device failed: %s", + vp_id, rt_strerror(err)); + return err; + } + + state->registered = RT_TRUE; + + if (gdev == &vfb->parent) + { + vfb->registered = RT_TRUE; + + if ((err = vop2fb_overlay_planes_create(vfb, state, width, height))) + { + LOG_W("vop2: create overlay planes failed, use primary only: %s", + rt_strerror(err)); + } + + if ((err = vop2fb_cursor_plane_create(vfb, state, width, height))) + { + LOG_W("vop2: create cursor plane failed, continue without cursor: %s", + rt_strerror(err)); + } + } + + /* + * The route has already enabled VOP2, its VP clock and the connector. + * Calling DPMS ON here would repeat window commits during registration. + * VOP2 scans out continuously; callers flush cached drawing through the + * plane update API instead of a periodic hard-timer commit. + */ + gdev->dpms = RT_GRAPHIC_DPMS_ON; + LOG_I("vop2: vp%u %s registered as %s (%ux%u)", + vp_id, state->scanout->name, + rt_dm_dev_get_name(&gdev->parent), width, height); + + return RT_EOK; +} + +static rt_err_t vop2fb_crtc_enable(void *priv, rt_uint32_t vp_id, rt_bool_t enable) +{ + struct vop2fb *vfb = priv; + struct vop2fb_vp_state *state; + enum vop2fb_output_if saved_output_if; + rt_err_t err; + rt_bool_t vp_started = RT_FALSE; + rt_bool_t dclk_started = RT_FALSE; + + if (!vfb || vp_id >= vfb->soc->vp_count || vp_id >= VOP2FB_VP_MAX) + { + return -RT_EINVAL; + } + + state = &vfb->vp[vp_id]; + saved_output_if = vfb->output_if; + + if (enable) + { + LOG_D("vop2: crtc enable vp%u registered=%d mode_valid=%d size=%ux%u", + vp_id, state->registered, state->mode_valid, + state->timing.hactive, state->timing.vactive); + + if (!state->mode_valid) + { + return -RT_EINVAL; + } + + if (!state->dclk_enabled) + { + if ((err = vop2fb_vp_clk_enable(vfb, vp_id))) + { + LOG_W("vop2: vp%u dclk enable failed: %s", + vp_id, rt_strerror(err)); + return err; + } + dclk_started = RT_TRUE; + } + + state->enabled = RT_TRUE; + vfb->active_vp_mask |= RT_BIT(vp_id); + vfb->output_if = state->output_if; + + if ((err = vop2fb_overlay_init(vfb))) + { + LOG_W("vop2: overlay init failed on vp%u: %s", vp_id, rt_strerror(err)); + goto _rollback; + } + + if ((err = vop2fb_vp_post_config(vfb, vp_id, &state->timing))) + { + LOG_W("vop2: vp%u post config failed: %s", vp_id, rt_strerror(err)); + goto _rollback; + } + + if ((err = vop2fb_vp_enable(vfb, vp_id, enable))) + { + LOG_W("vop2: vp%u enable failed: %s", vp_id, rt_strerror(err)); + goto _rollback; + } + vp_started = RT_TRUE; + + vfb->output_if = saved_output_if; + return RT_EOK; + +_rollback: + if (vp_started) + { + (void)vop2fb_vp_enable(vfb, vp_id, RT_FALSE); + } + vop2fb_output_disable(vfb, state->output_if); + vop2fb_reg_write(vfb, VOP2_REG_CFG_DONE, + vop2fb_cfg_done_vp_val(vfb, vp_id)); + if (state->scanout) + { + vop2fb_win_disable(vfb, state->scanout); + vop2fb_reg_write(vfb, VOP2_REG_CFG_DONE, + vop2fb_cfg_done_vp_val(vfb, vp_id)); + } + state->enabled = RT_FALSE; + vfb->active_vp_mask &= ~RT_BIT(vp_id); + vfb->configured_vp_mask &= ~RT_BIT(vp_id); + state->mode_valid = RT_FALSE; + state->output_if = VOP2FB_OUTPUT_NONE; + state->scanout = RT_NULL; + rt_memset(&state->timing, 0, sizeof(state->timing)); + if (vp_id == vfb->vp_id && !vfb->active_vp_mask) + { + vfb->output_if = VOP2FB_OUTPUT_NONE; + vfb->output_tim_valid = RT_FALSE; + rt_memset(&vfb->output_tim, 0, sizeof(vfb->output_tim)); + } + else + { + vfb->output_if = saved_output_if; + } + (void)vop2fb_overlay_init(vfb); + if (dclk_started) + { + vop2fb_vp_clk_disable(vfb, vp_id); + } + + return err; + } + + LOG_D("vop2: crtc disable vp%u", vp_id); + vfb->output_if = state->output_if; + + if (state->scanout) + { + vop2fb_win_disable(vfb, state->scanout); + vop2fb_reg_write(vfb, VOP2_REG_CFG_DONE, + vop2fb_cfg_done_vp_val(vfb, vp_id)); + } + + err = vop2fb_vp_enable(vfb, vp_id, enable); + vop2fb_output_disable(vfb, state->output_if); + vop2fb_reg_write(vfb, VOP2_REG_CFG_DONE, + vop2fb_cfg_done_vp_val(vfb, vp_id)); + state->enabled = RT_FALSE; + vfb->active_vp_mask &= ~RT_BIT(vp_id); + vfb->configured_vp_mask &= ~RT_BIT(vp_id); + state->mode_valid = RT_FALSE; + state->output_if = VOP2FB_OUTPUT_NONE; + state->scanout = RT_NULL; + rt_memset(&state->timing, 0, sizeof(state->timing)); + if (vp_id == vfb->vp_id && !vfb->active_vp_mask) + { + vfb->output_if = VOP2FB_OUTPUT_NONE; + vfb->output_tim_valid = RT_FALSE; + rt_memset(&vfb->output_tim, 0, sizeof(vfb->output_tim)); + } + else + { + vfb->output_if = saved_output_if; + } + (void)vop2fb_overlay_init(vfb); + vop2fb_vp_clk_disable(vfb, vp_id); + + return err; +} + +static rt_err_t vop2fb_crtc_complete(void *priv, rt_uint32_t vp_id) +{ + rt_err_t err; + struct vop2fb *vfb = priv; + + if (!vfb || vp_id >= vfb->soc->vp_count || vp_id >= VOP2FB_VP_MAX || + !vfb->vp[vp_id].enabled) + { + return -RT_EINVAL; + } + + if ((err = vop2fb_graphic_register(vfb, vp_id))) + { + return err; + } + + return RT_EOK; +} + +static const struct rockchip_crtc_ops vop2fb_crtc_ops = +{ + .mode_set = vop2fb_crtc_mode_set, + .enable = vop2fb_crtc_enable, + .complete = vop2fb_crtc_complete, +}; + +/* -------------------------------------------------------------------------- */ +/* Probe / remove */ +/* -------------------------------------------------------------------------- */ + +static const struct vop2fb_soc_data *vop2fb_soc_from_id(const struct rt_ofw_node_id *id) +{ + if (!id || !id->compatible[0]) + { + return RT_NULL; + } + + if (!rt_strcmp(id->compatible, "rockchip,rk3568-vop")) + { + return &rk3568_soc_data; + } + + if (!rt_strcmp(id->compatible, "rockchip,rk3588-vop")) + { + return &rk3588_soc_data; + } + + if (!rt_strcmp(id->compatible, "rockchip,rk3528-vop")) + { + return &rk3528_soc_data; + } + + if (!rt_strcmp(id->compatible, "rockchip,rk3562-vop")) + { + return &rk3562_soc_data; + } + + if (!rt_strcmp(id->compatible, "rockchip,rk3576-vop")) + { + return &rk3576_soc_data; + } + + return RT_NULL; +} + +static void vop2fb_axi_init_all(struct vop2fb *vfb) +{ + rt_size_t i; + + if (!vfb->soc->axi_config) + { + return; + } + + vop2fb_axi_config(vfb, vfb->soc->primary); + vop2fb_axi_config(vfb, vfb->soc->cursor); + + for (i = 0; i < vfb->soc->overlay_count; ++i) + { + vop2fb_axi_config(vfb, &vfb->soc->overlays[i]); + } +} + +static int vop2fb_request_irq(struct vop2fb *vfb, struct rt_device *dev) +{ + char irq_name[16]; + + if (vfb->soc->irq_by_vp && vfb->vp_id < vfb->soc->vp_count) + { + rt_snprintf(irq_name, sizeof(irq_name), "vop-vp%u", vfb->vp_id); + vfb->irq = rt_dm_dev_get_irq_by_name(dev, irq_name); + + if (vfb->irq < 0) + { + vfb->irq = rt_dm_dev_get_irq(dev, vfb->vp_id + 1); + } + } + else + { + vfb->irq = rt_dm_dev_get_irq(dev, 0); + } + + return vfb->irq; +} + +static rt_err_t vop2fb_parse_display(struct vop2fb *vfb, struct rt_platform_device *pdev) +{ + struct rt_device *dev = &pdev->parent; + + vfb->display_w = 1920; + vfb->display_h = 1080; + vfb->vp_id = 0; + + rt_dm_dev_prop_read_u32(dev, "rockchip,fb-width", &vfb->display_w); + rt_dm_dev_prop_read_u32(dev, "rockchip,fb-height", &vfb->display_h); + rt_dm_dev_prop_read_u32(dev, "rockchip,active-vp", &vfb->vp_id); + + if (vfb->soc && vfb->vp_id >= vfb->soc->vp_count) + { + vfb->vp_id = 0; + } + + if (!vfb->display_w || !vfb->display_h) + { + return -RT_EINVAL; + } + + return RT_EOK; +} + +static rt_bool_t vop2fb_route_is_legacy_hdmi(struct rt_ofw_node *connector_np) +{ + if (!connector_np) + { + return RT_FALSE; + } + + return rt_ofw_node_is_compatible(connector_np, "rockchip,rk3568-dw-hdmi") || + rt_ofw_node_is_compatible(connector_np, "rockchip,rk3528-dw-hdmi"); +} + +#if DBG_LVL >= DBG_LOG +static const char *vop2fb_output_name(enum vop2fb_output_if output_if) +{ + switch (output_if) + { + case VOP2FB_OUTPUT_HDMI: + return "hdmi"; + case VOP2FB_OUTPUT_EDP: + return "edp"; + case VOP2FB_OUTPUT_MIPI0: + return "mipi0"; + case VOP2FB_OUTPUT_MIPI1: + return "mipi1"; + case VOP2FB_OUTPUT_LVDS: + return "lvds"; + case VOP2FB_OUTPUT_RGB: + return "rgb"; + default: + return "none"; + } +} +#endif /* DBG_LVL >= DBG_LOG */ + +static enum vop2fb_output_if vop2fb_output_from_connector(struct rt_ofw_node *connector_np) +{ + rt_uint64_t addr; + + if (!connector_np) + { + return VOP2FB_OUTPUT_NONE; + } + + if (vop2fb_route_is_legacy_hdmi(connector_np)) + { + return VOP2FB_OUTPUT_HDMI; + } + + if (rt_ofw_node_is_compatible(connector_np, "rockchip,rk3568-edp")) + { + return VOP2FB_OUTPUT_EDP; + } + + if (rt_ofw_node_is_compatible(connector_np, "rockchip,rk3568-lvds")) + { + return VOP2FB_OUTPUT_LVDS; + } + + if (rt_ofw_node_is_compatible(connector_np, "rockchip,rk3568-rgb")) + { + return VOP2FB_OUTPUT_RGB; + } + + if (rt_ofw_node_is_compatible(connector_np, "rockchip,rk3568-mipi-dsi")) + { + if (!rt_ofw_get_address(connector_np, 0, &addr, RT_NULL) && + addr == 0xfe070000ULL) + { + return VOP2FB_OUTPUT_MIPI1; + } + + return VOP2FB_OUTPUT_MIPI0; + } + + return VOP2FB_OUTPUT_NONE; +} + +static rt_err_t vop2fb_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + rt_bool_t irq_ready = RT_FALSE; + rt_uint32_t vp_id; + char ipc_name[RT_NAME_MAX]; + struct rt_device *dev = &pdev->parent; + struct vop2fb *vfb = rt_calloc(1, sizeof(*vfb)); + + if (!vfb) + { + return -RT_ENOMEM; + } + + vfb->dev = dev; + vfb->soc = vop2fb_soc_from_id(pdev->id); + + if (!vfb->soc) + { + err = -RT_ENOSYS; + goto _fail; + } + + if ((err = vop2fb_parse_display(vfb, pdev))) + { + goto _fail; + } + + vfb->regs = rt_ofw_iomap(dev->ofw_node, 0); + + if (!vfb->regs) + { + err = -RT_EIO; + goto _fail; + } + + vfb->regsbak = rt_calloc(vfb->soc->regbak_words, sizeof(rt_uint32_t)); + + if (!vfb->regsbak) + { + err = -RT_ENOMEM; + goto _fail_unmap; + } + + vfb->clks = rt_clk_get_array(dev); + + if (rt_is_err(vfb->clks)) + { + err = rt_ptr_err(vfb->clks); + goto _fail_regsbak; + } + + vfb->irq = vop2fb_request_irq(vfb, dev); + rt_spin_lock_init(&vfb->reg_lock); + + vfb->parent.ops = &vop2fb_ops; + vfb->parent.parent.ofw_node = dev->ofw_node; + + if ((err = vop2fb_clk_enable(vfb))) + { + goto _fail_clks; + } + + vfb->powered = RT_TRUE; + vop2fb_regsbak_sync(vfb); + vop2fb_rk3568_irqs_quiesce(vfb); + + vop2fb_axi_init_all(vfb); + vop2fb_overlay_init(vfb); + vop2fb_parse_port_planes(vfb, dev->ofw_node, vfb->vp_id); + + vfb->overlay_count = rt_min_t(rt_size_t, vfb->soc->overlay_count, VOP2FB_OVERLAY_MAX); + pdev->parent.user_data = vfb; + + for (vp_id = 0; vp_id < vfb->soc->vp_count && + vp_id < VOP2FB_VP_MAX; ++vp_id) + { + struct vop2fb_vp_state *state = &vfb->vp[vp_id]; + + state->vfb = vfb; + state->vp_id = vp_id; + + if (vfb->irq < 0) + { + continue; + } + + rt_snprintf(ipc_name, sizeof(ipc_name), "vop-vs%u", vp_id); + if ((err = rt_sem_init(&state->vsync_sem, ipc_name, 0, + RT_IPC_FLAG_FIFO))) + { + goto _fail_clk; + } + + rt_snprintf(ipc_name, sizeof(ipc_name), "vop-vl%u", vp_id); + if ((err = rt_mutex_init(&state->vsync_lock, ipc_name, + RT_IPC_FLAG_PRIO))) + { + rt_sem_detach(&state->vsync_sem); + goto _fail_clk; + } + + state->ipc_ready = RT_TRUE; + } + + /* + * Publish the CRTC only after every resource needed by a route exists. + * Otherwise a plane allocation failure leaves a global display entity + * pointing at the vfb object freed by the probe error path. + */ + if ((err = rockchip_display_register_crtc(dev->ofw_node, &vop2fb_crtc_ops, vfb))) + { + goto _fail_clk; + } + + /* + * Keep this last, matching Linux. A level interrupt may run as soon as + * GIC is unmasked, so all objects touched by the handler must be ready. + */ + if (vfb->irq >= 0) + { + rt_hw_interrupt_install(vfb->irq, vop2fb_isr, vfb, "vop2"); + rt_hw_interrupt_umask(vfb->irq); + irq_ready = RT_TRUE; + } + + LOG_I("VOP2 %s: max %ux%u, primary=%s, %u overlays, cursor=%s, per-VP fb on route complete", + vfb->soc->version, vfb->display_w, vfb->display_h, + vfb->soc->primary->name, (unsigned)vfb->overlay_count, + vfb->soc->cursor->name); + + return RT_EOK; + +_fail_clk: + (void)vop2fb_cleanup_planes(vfb); + if (irq_ready) + { + rt_hw_interrupt_mask(vfb->irq); + } + for (vp_id = 0; vp_id < vfb->soc->vp_count && + vp_id < VOP2FB_VP_MAX; ++vp_id) + { + if (vfb->vp[vp_id].ipc_ready) + { + rt_sem_detach(&vfb->vp[vp_id].vsync_sem); + rt_mutex_detach(&vfb->vp[vp_id].vsync_lock); + vfb->vp[vp_id].ipc_ready = RT_FALSE; + } + } + vop2fb_rk3568_irqs_quiesce(vfb); + vop2fb_clk_disable(vfb); +_fail_clks: + if (!rt_is_err_or_null(vfb->clks)) + { + rt_clk_array_put(vfb->clks); + } +_fail_regsbak: + rt_free(vfb->regsbak); +_fail_unmap: + if (vfb->regs) + { + rt_iounmap(vfb->regs); + } +_fail: + pdev->parent.user_data = RT_NULL; + rt_free(vfb); + + return err; +} + +static rt_err_t vop2fb_remove(struct rt_platform_device *pdev) +{ + rt_err_t err; + rt_uint32_t vp_id; + struct vop2fb *vfb = pdev->parent.user_data; + + if (!vfb) + { + return RT_EOK; + } + + err = vop2fb_cleanup_planes(vfb); + if (err) + { + return err; + } + + if (vfb->irq >= 0) + { + rt_hw_interrupt_mask(vfb->irq); + } + + for (vp_id = 0; vp_id < vfb->soc->vp_count && + vp_id < VOP2FB_VP_MAX; ++vp_id) + { + if (vfb->vp[vp_id].ipc_ready) + { + rt_sem_detach(&vfb->vp[vp_id].vsync_sem); + rt_mutex_detach(&vfb->vp[vp_id].vsync_lock); + vfb->vp[vp_id].ipc_ready = RT_FALSE; + } + } + + vop2fb_rk3568_irqs_quiesce(vfb); + + for (vp_id = 0; vp_id < vfb->soc->vp_count && + vp_id < VOP2FB_VP_MAX; ++vp_id) + { + vop2fb_vp_clk_disable(vfb, vp_id); + } + vop2fb_clk_disable(vfb); + + if (!rt_is_err_or_null(vfb->clks)) + { + rt_clk_array_put(vfb->clks); + } + + rt_iounmap(vfb->regs); + rt_free(vfb->regsbak); + rt_free(vfb); + + pdev->parent.user_data = RT_NULL; + + return RT_EOK; +} + +static const struct rt_ofw_node_id vop2_ofw_ids[] = +{ + { .compatible = "rockchip,rk3568-vop" }, + { .compatible = "rockchip,rk3588-vop" }, + { .compatible = "rockchip,rk3528-vop" }, + { .compatible = "rockchip,rk3562-vop" }, + { .compatible = "rockchip,rk3576-vop" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver vop2_driver = +{ + .name = "vop2-framebuffer", + .ids = vop2_ofw_ids, + + .probe = vop2fb_probe, + .remove = vop2fb_remove, +}; +RT_PLATFORM_DRIVER_EXPORT(vop2_driver); diff --git a/bsp/rockchip/dm/graphic/framebuffer/fb-vop2.h b/bsp/rockchip/dm/graphic/framebuffer/fb-vop2.h new file mode 100644 index 000000000000..10bc6eb3de7b --- /dev/null +++ b/bsp/rockchip/dm/graphic/framebuffer/fb-vop2.h @@ -0,0 +1,300 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-09-23 GuEe-GUI first version + */ + +#ifndef __FB_VOP2_H__ +#define __FB_VOP2_H__ + +#include "rockchip-display.h" + +#define VOP2FB_CURSOR_W 64 +#define VOP2FB_CURSOR_H 64 + +#define VOP2FB_OVERLAY_MAX 6 +#define VOP2FB_VP_MAX 4 + +/* System */ +#define VOP2_REG_CFG_DONE 0x000 +#define VOP2_CFG_DONE_EN RT_BIT(15) + +#define VOP2_EN_MASK 1 + +/* Cluster layer (RK3568 layout) */ +#define VOP2_CLUSTER0_BASE 0x1000 +#define VOP2_CLUSTER_STRIDE 0x200 + +#define VOP2_CLUSTER_WIN0_CTRL0 0x00 +#define VOP2_CLUSTER_WIN0_CTRL2 0x08 +#define VOP2_CLUSTER_WIN0_YRGB_MST 0x10 +#define VOP2_CLUSTER_WIN0_VIR 0x18 +#define VOP2_CLUSTER_WIN0_ACT_INFO 0x20 +#define VOP2_CLUSTER_WIN0_DSP_INFO 0x24 +#define VOP2_CLUSTER_WIN0_DSP_ST 0x28 +#define VOP2_CLUSTER_CTRL 0x100 +#define VOP2_CLUSTER_EN_SHIFT 0 + +#define VOP2_CLUSTER_AXI_ID_SHIFT 13 +#define VOP2_CLUSTER_AXI_YRGB_ID_SHIFT 0 +#define VOP2_CLUSTER_AXI_UV_ID_SHIFT 5 +#define VOP2_CLUSTER_AXI_YRGB_ID_MASK 0x1f +#define VOP2_CLUSTER_AXI_UV_ID_MASK 0x1f +#define VOP2_CLUSTER_AXI_ID_MASK 0x1 + +/* Esmart / Smart shared region layout */ +#define VOP2_ESMART0_BASE 0x1800 +#define VOP2_SMART0_BASE 0x1C00 +#define VOP2_ESMART_STRIDE 0x200 +#define VOP2_SMART_STRIDE 0x200 + +#define VOP2_ESMART_CTRL0 0x00 +#define VOP2_ESMART_AXI_CTRL 0x08 +#define VOP2_ESMART_CTRL1 0x04 +#define VOP2_ESMART_AXI_ID_SHIFT 1 +#define VOP2_ESMART_AXI_YRGB_ID_SHIFT 0 +#define VOP2_ESMART_AXI_UV_ID_SHIFT 12 +#define VOP2_ESMART_AXI_ID_MASK 0x1 +#define VOP2_ESMART_AXI_YRGB_ID_MASK 0x1f +#define VOP2_ESMART_AXI_UV_ID_MASK 0x1f +#define VOP2_RGB2YUV_EN_SHIFT 1 +#define VOP2_CSC_MODE_SHIFT 2 +#define VOP2_CSC_MODE_MASK 0x3 + +#define VOP2_REGION0_CTRL 0x10 +#define VOP2_REGION0_YRGB_MST 0x14 +#define VOP2_REGION0_CBR_MST 0x18 +#define VOP2_REGION0_VIR 0x1c +#define VOP2_REGION0_ACT_INFO 0x20 +#define VOP2_REGION0_DSP_INFO 0x24 +#define VOP2_REGION0_DSP_ST 0x28 +#define VOP2_REGION0_SCL_CTRL 0x30 +#define VOP2_REGION0_SCL_FACTOR_YRGB 0x34 +#define VOP2_REGION0_SCL_FACTOR_CBR 0x38 +#define VOP2_REGION0_SCL_OFFSET 0x3c +#define VOP2_YMIRROR_EN_SHIFT 31 + +#define VOP2_WIN_EN_SHIFT 0 +#define VOP2_WIN_FORMAT_MASK 0x1f +#define VOP2_WIN_FORMAT_SHIFT 1 +#define VOP2_REGION0_DITHER_UP_EN_SHIFT 12 +#define VOP2_REGION0_RB_SWAP_SHIFT 14 +#define VOP2_YRGB_GT2_SHIFT 8 +#define VOP2_YRGB_GT4_SHIFT 9 + +enum vop2fb_soc +{ + VOP2FB_SOC_RK3568 = 0, + VOP2FB_SOC_RK3588, + VOP2FB_SOC_RK3528, + VOP2FB_SOC_RK3562, + VOP2FB_SOC_RK3576, +}; + +enum vop2fb_layer_type +{ + VOP2FB_LAYER_CLUSTER = 0, + VOP2FB_LAYER_ESMART, + VOP2FB_LAYER_SMART, +}; + +enum vop2fb_hw_format +{ + VOP2FB_FMT_ARGB8888 = 0, + VOP2FB_FMT_RGB888, + VOP2FB_FMT_RGB565, +}; + +enum vop2fb_output_if +{ + VOP2FB_OUTPUT_NONE = 0, + VOP2FB_OUTPUT_HDMI, + VOP2FB_OUTPUT_EDP, + VOP2FB_OUTPUT_MIPI0, + VOP2FB_OUTPUT_MIPI1, + VOP2FB_OUTPUT_LVDS, + VOP2FB_OUTPUT_RGB, +}; + +struct vop2fb_win_desc +{ + const char *name; + enum vop2fb_layer_type type; + rt_uint32_t base_offset; + rt_uint8_t layer_sel_id; + rt_uint8_t win_sel_port_offset; + rt_uint8_t z_order; + rt_uint8_t axi_id; + rt_uint8_t axi_yrgb_id; + rt_uint8_t axi_uv_id; + rt_int8_t plane_id; + rt_uint32_t mix_alpha_reg; +}; + +struct vop2fb_soc_data +{ + enum vop2fb_soc soc; + const char *version; + rt_size_t reg_size; + rt_size_t regbak_words; + const struct vop2fb_win_desc *primary; + const struct vop2fb_win_desc *cursor; + const struct vop2fb_win_desc *overlays; + rt_size_t overlay_count; + const struct vop2fb_win_desc *const *route_windows; + rt_size_t route_window_count; + rt_bool_t axi_config; + rt_bool_t irq_by_vp; + rt_uint32_t vp_count; +}; + +struct vop2fb; + +struct vop2fb_plane_priv +{ + struct vop2fb *vfb; + const struct vop2fb_win_desc *desc; + rt_ubase_t dma_handle; + rt_ubase_t dma_flags; + rt_uint32_t pan_offset; + rt_uint32_t vp_id; + rt_bool_t enabled; +}; + +struct vop2fb_vp_state +{ + struct display_timing timing; + enum vop2fb_output_if output_if; + const struct vop2fb_win_desc *scanout; + struct vop2fb *vfb; + struct rt_graphic_device auxiliary; + struct rt_graphic_device *graphic; + struct rt_graphic_plane *primary; + rt_atomic_t vsync; + struct rt_semaphore vsync_sem; + struct rt_mutex vsync_lock; + rt_uint32_t vp_id; + rt_bool_t mode_valid; + rt_bool_t enabled; + rt_bool_t dclk_enabled; + rt_bool_t ipc_ready; + rt_bool_t registered; +}; + +struct vop2fb +{ + struct rt_graphic_device parent; + struct rt_device *dev; + + const struct vop2fb_soc_data *soc; + + void *regs; + rt_uint32_t *regsbak; + + rt_uint32_t display_w; + rt_uint32_t display_h; + rt_uint32_t vp_id; + + rt_uint32_t hw_format; + enum vop2fb_output_if output_if; + + struct display_timing output_tim; + rt_bool_t output_tim_valid; + struct vop2fb_vp_state vp[VOP2FB_VP_MAX]; + rt_uint32_t configured_vp_mask; + rt_uint32_t active_vp_mask; + + rt_bool_t clk_enabled; + struct rt_clk_array *clks; + struct rt_spinlock reg_lock; + + int irq; + rt_uint32_t post_buf_empty_count[VOP2FB_VP_MAX]; + rt_uint32_t axi_bus_error_count[2]; + + struct rt_graphic_plane *primary; + struct rt_graphic_plane *cursor; + struct rt_graphic_plane *overlays[VOP2FB_OVERLAY_MAX]; + rt_size_t overlay_count; + + rt_bool_t registered; + rt_bool_t powered; +}; + +rt_uint32_t vop2fb_mode_to_hw(rt_uint32_t mode); +rt_uint32_t vop2fb_hw_to_bpp(rt_uint32_t hw_fmt); + +rt_inline void vop2fb_reg_write(struct vop2fb *vfb, rt_uint32_t offset, rt_uint32_t v) +{ + rt_uint32_t idx = offset >> 2; + + HWREG32((rt_uint8_t *)vfb->regs + offset) = v; + + if (vfb->regsbak && idx < vfb->soc->regbak_words) + { + vfb->regsbak[idx] = v; + } +} + +rt_inline void vop2fb_mask_write(struct vop2fb *vfb, rt_uint32_t offset, + rt_uint32_t mask, rt_uint32_t shift, rt_uint32_t v) +{ + rt_uint32_t idx = offset >> 2; + rt_uint32_t cached, newv; + + if (!mask || !vfb->regsbak || idx >= vfb->soc->regbak_words) + { + return; + } + + cached = vfb->regsbak[idx]; + newv = (cached & ~(mask << shift)) | ((v & mask) << shift); + vop2fb_reg_write(vfb, offset, newv); +} + +rt_inline rt_uint32_t vop2fb_cfg_done_pending(struct vop2fb *vfb) +{ + /* + * RK3568 VP done bits have no hiword write mask. Preserve any update + * that another VP has queued but has not latched at frame start yet. + */ + if (vfb && vfb->regs && vfb->soc && + vfb->soc->soc == VOP2FB_SOC_RK3568) + { + return HWREG32((rt_uint8_t *)vfb->regs + VOP2_REG_CFG_DONE) & 0x7; + } + + return 0; +} + +rt_inline rt_uint32_t vop2fb_cfg_done_vp_val(struct vop2fb *vfb, rt_uint32_t vp) +{ + if (vfb && vfb->soc && vfb->soc->soc == VOP2FB_SOC_RK3568) + { + return VOP2_CFG_DONE_EN | RT_BIT(vp) | vop2fb_cfg_done_pending(vfb); + } + + return VOP2_CFG_DONE_EN | RT_BIT(vp) | (RT_BIT(vp) << 16); +} + +rt_inline rt_uint32_t vop2fb_cfg_done_val(struct vop2fb *vfb) +{ + return vop2fb_cfg_done_vp_val(vfb, vfb->vp_id); +} + +rt_inline rt_uint32_t vop2fb_cfg_done_mask_val(struct vop2fb *vfb, + rt_uint32_t vp_mask) +{ + if (vfb && vfb->soc && vfb->soc->soc == VOP2FB_SOC_RK3568) + { + return VOP2_CFG_DONE_EN | vp_mask | vop2fb_cfg_done_pending(vfb); + } + + return VOP2_CFG_DONE_EN | vp_mask | (vp_mask << 16); +} + +#endif /* __FB_VOP2_H__ */ diff --git a/bsp/rockchip/dm/graphic/framebuffer/fb-vopl.c b/bsp/rockchip/dm/graphic/framebuffer/fb-vopl.c new file mode 100644 index 000000000000..4ddcc2caf962 --- /dev/null +++ b/bsp/rockchip/dm/graphic/framebuffer/fb-vopl.c @@ -0,0 +1,641 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-09-23 GuEe-GUI first version + */ + +#include "fb-vopl.h" + +#include + +#define DBG_TAG "fb.vopl" +#define DBG_LVL DBG_INFO +#include + +#define EBC_CONFIG_DONE 0x0050 +#define EBC_WIN_MST2 0x0058 +#define EBC_WIN2_CTRL 0x006c +#define EBC_VOP_SYS_CTRL 0x0100 +#define EBC_VOP_DSP_CTRL0 0x0104 +#define EBC_VOP_DSP_CTRL1 0x0108 +#define EBC_DSP_HTOTAL_HS_END 0x0110 +#define EBC_DSP_HACT_ST_END 0x0114 +#define EBC_DSP_VTOTAL_VS_END 0x0118 +#define EBC_DSP_VACT_ST_END 0x011c +#define EBC_VOP_WIN_VIR 0x0150 +#define EBC_VOP_WIN_DSP_INFO 0x0158 +#define EBC_VOP_WIN_DSP_ST 0x015c + +#define VOPLFB_OUT_MODE_P888 0 + +struct voplfb_plane_priv +{ + rt_ubase_t dma_handle; + rt_uint32_t pan_offset; + rt_bool_t enabled; +}; + +static rt_uint32_t voplfb_modes[] = +{ + RTGRAPHIC_PIXEL_FORMAT_ARGB888, + RTGRAPHIC_PIXEL_FORMAT_RGB888, + RTGRAPHIC_PIXEL_FORMAT_RGB565, +}; + +rt_uint32_t voplfb_mode_to_hw(rt_uint32_t mode) +{ + switch (mode) + { + case RTGRAPHIC_PIXEL_FORMAT_ARGB888: + case RTGRAPHIC_PIXEL_FORMAT_ABGR888: + return VOPLFB_FMT_ARGB8888; + case RTGRAPHIC_PIXEL_FORMAT_RGB888: + case RTGRAPHIC_PIXEL_FORMAT_BGR888: + return VOPLFB_FMT_RGB888; + case RTGRAPHIC_PIXEL_FORMAT_RGB565: + case RTGRAPHIC_PIXEL_FORMAT_BGR565: + return VOPLFB_FMT_RGB565; + default: + return VOPLFB_FMT_ARGB8888; + } +} + +rt_uint32_t voplfb_hw_to_bpp(rt_uint32_t hw_fmt) +{ + switch (hw_fmt) + { + case VOPLFB_FMT_RGB565: + return 16; + case VOPLFB_FMT_RGB888: + return 24; + default: + return 32; + } +} + +static struct voplfb *voplfb_from_plane(struct rt_graphic_plane *plane) +{ + return rt_container_of(plane->graphic, struct voplfb, parent); +} + +static struct voplfb_plane_priv *voplfb_plane_priv(struct rt_graphic_plane *plane) +{ + return (struct voplfb_plane_priv *)plane->priv; +} + +rt_inline void voplfb_reg_write(struct voplfb *vfb, rt_uint32_t offset, rt_uint32_t v) +{ + HWREG32((rt_uint8_t *)vfb->regs + offset) = v; +} + +rt_inline void voplfb_mask_write(struct voplfb *vfb, rt_uint32_t offset, + rt_uint32_t mask, rt_uint32_t shift, rt_uint32_t v) +{ + rt_uint32_t cached = HWREG32((rt_uint8_t *)vfb->regs + offset); + rt_uint32_t newv = (cached & ~(mask << shift)) | ((v & mask) << shift); + + voplfb_reg_write(vfb, offset, newv); +} + +static void voplfb_cfg_done(struct voplfb *vfb) +{ + voplfb_reg_write(vfb, EBC_CONFIG_DONE, 1); +} + +static rt_uint32_t voplfb_xvir(rt_uint32_t width, rt_uint32_t bpp) +{ + return RT_ALIGN(width * bpp, 32) >> 5; +} + +static rt_err_t voplfb_output_mode_set(struct voplfb *vfb, const struct display_timing *tim) +{ + rt_uint32_t hact_st, hact_end, vact_st, vact_end; + + if (!vfb || !tim) + { + return -RT_EINVAL; + } + + hact_st = tim->hfront_porch + tim->hsync_len; + hact_end = hact_st + tim->hactive; + vact_st = tim->vfront_porch + tim->vsync_len; + vact_end = vact_st + tim->vactive; + + voplfb_reg_write(vfb, EBC_DSP_HTOTAL_HS_END, (tim->htotal << 16) | tim->hsync_len); + voplfb_reg_write(vfb, EBC_DSP_HACT_ST_END, (hact_st << 16) | hact_end); + voplfb_reg_write(vfb, EBC_DSP_VTOTAL_VS_END, (tim->vtotal << 16) | tim->vsync_len); + voplfb_reg_write(vfb, EBC_DSP_VACT_ST_END, (vact_st << 16) | vact_end); + + voplfb_mask_write(vfb, EBC_VOP_DSP_CTRL1, 0xf, 16, VOPLFB_OUT_MODE_P888); + voplfb_mask_write(vfb, EBC_VOP_DSP_CTRL0, 1, 15, 0); + voplfb_mask_write(vfb, EBC_VOP_DSP_CTRL0, 1, 31, 1); + voplfb_mask_write(vfb, EBC_VOP_SYS_CTRL, 1, 0, 1); + voplfb_mask_write(vfb, EBC_VOP_SYS_CTRL, 1, 8, 1); + + vfb->display_w = tim->hactive; + vfb->display_h = tim->vactive; + + return RT_EOK; +} + +static rt_err_t voplfb_output_enable(struct voplfb *vfb, rt_bool_t enable) +{ + voplfb_mask_write(vfb, EBC_VOP_DSP_CTRL0, 1, 15, enable ? 0 : 1); + voplfb_cfg_done(vfb); + + return RT_EOK; +} + +static rt_err_t voplfb_plane_commit(struct voplfb *vfb, struct rt_graphic_plane *plane, + rt_bool_t enable) +{ + struct voplfb_plane_priv *priv = voplfb_plane_priv(plane); + rt_ubase_t dma; + rt_uint32_t xvir, act_info, dsp_info, dsp_st; + + if (!priv || !plane) + { + return -RT_EINVAL; + } + + if (!enable || !plane->framebuffer) + { + voplfb_mask_write(vfb, EBC_WIN2_CTRL, 1, 0, 0); + voplfb_cfg_done(vfb); + priv->enabled = RT_FALSE; + return RT_EOK; + } + + dma = priv->dma_handle + priv->pan_offset; + xvir = voplfb_xvir(plane->width, plane->bits_per_pixel); + act_info = ((plane->height - 1) << 16) | ((plane->width - 1) & 0xffff); + dsp_info = act_info; + dsp_st = (plane->y << 16) | (plane->x & 0xffff); + + voplfb_mask_write(vfb, EBC_VOP_SYS_CTRL, 0x3, 4, voplfb_mode_to_hw(plane->mode)); + voplfb_reg_write(vfb, EBC_VOP_WIN_VIR, xvir); + voplfb_reg_write(vfb, EBC_WIN_MST2, (rt_uint32_t)dma); + voplfb_reg_write(vfb, EBC_VOP_WIN_DSP_INFO, dsp_info); + voplfb_reg_write(vfb, EBC_VOP_WIN_DSP_ST, dsp_st); + voplfb_mask_write(vfb, EBC_WIN2_CTRL, 1, 0, 1); + voplfb_cfg_done(vfb); + + priv->enabled = RT_TRUE; + + return RT_EOK; +} + +static void voplfb_plane_free_fb(struct rt_graphic_plane *plane) +{ + struct voplfb *vfb = voplfb_from_plane(plane); + struct voplfb_plane_priv *priv = voplfb_plane_priv(plane); + struct rt_device *dev = &vfb->parent.parent; + + if (plane->framebuffer) + { + rt_dma_free_coherent(dev, plane->framebuffer_len, + plane->framebuffer, priv->dma_handle); + plane->framebuffer = RT_NULL; + plane->framebuffer_len = 0; + plane->screen_len = 0; + priv->dma_handle = 0; + priv->pan_offset = 0; + } +} + +static rt_err_t voplfb_plane_update(struct rt_graphic_plane *plane, + struct rt_device_rect_info *rect) +{ + struct voplfb *vfb = voplfb_from_plane(plane); + struct voplfb_plane_priv *priv = voplfb_plane_priv(plane); + + RT_UNUSED(rect); + + if (priv) + { + priv->enabled = RT_TRUE; + } + + return voplfb_plane_commit(vfb, plane, RT_TRUE); +} + +static rt_err_t voplfb_plane_fb_remap(struct rt_graphic_plane *plane, + rt_uint32_t mode, struct rt_device_rect_info *rect) +{ + rt_err_t err; + struct voplfb *vfb = voplfb_from_plane(plane); + struct voplfb_plane_priv *priv = voplfb_plane_priv(plane); + struct rt_device *dev = &vfb->parent.parent; + rt_uint32_t bpp = rt_graphic_mode_bpp(mode); + rt_size_t screen_len, fb_len; + void *fb; + + if (!rect->width || !rect->height || !bpp) + { + return -RT_EINVAL; + } + + voplfb_plane_free_fb(plane); + + plane->line_length = RT_ALIGN(rect->width * bpp, 32) / 8; + plane->bits_per_pixel = bpp; + screen_len = plane->line_length * rect->height; + fb_len = screen_len * 2; + + fb = rt_dma_alloc_coherent(dev, fb_len, &priv->dma_handle); + + if (!fb) + { + return -RT_ENOMEM; + } + + rt_memset(fb, 0, fb_len); + + plane->framebuffer = fb; + plane->screen_len = screen_len; + plane->framebuffer_len = fb_len; + plane->width = rect->width; + plane->height = rect->height; + plane->mode = mode; + priv->pan_offset = 0; + + if (vfb->powered) + { + err = voplfb_plane_commit(vfb, plane, RT_TRUE); + } + else + { + err = RT_EOK; + } + + return err; +} + +static rt_err_t voplfb_plane_fb_pan_display(struct rt_graphic_plane *plane, + struct rt_device_rect_info *rect) +{ + struct voplfb *vfb = voplfb_from_plane(plane); + struct voplfb_plane_priv *priv = voplfb_plane_priv(plane); + + if (rect->width != plane->width || rect->height != plane->height) + { + return voplfb_plane_fb_remap(plane, plane->mode, rect); + } + + if (plane->framebuffer_len <= plane->screen_len) + { + plane->x = rect->x; + plane->y = rect->y; + return RT_EOK; + } + + priv->pan_offset = rect->y * plane->line_length + rect->x * (plane->bits_per_pixel / 8); + + if (priv->pan_offset + plane->screen_len > plane->framebuffer_len) + { + priv->pan_offset = 0; + return -RT_EINVAL; + } + + plane->x = rect->x; + plane->y = rect->y; + + return voplfb_plane_commit(vfb, plane, RT_TRUE); +} + +static rt_err_t voplfb_plane_fb_cleanup(struct rt_graphic_plane *plane) +{ + struct voplfb *vfb = voplfb_from_plane(plane); + struct voplfb_plane_priv *priv = voplfb_plane_priv(plane); + + if (priv && priv->enabled) + { + voplfb_plane_commit(vfb, plane, RT_FALSE); + } + + voplfb_plane_free_fb(plane); + + return RT_EOK; +} + +static const struct rt_graphic_plane_ops voplfb_primary_ops = +{ + .update = voplfb_plane_update, + .fb_remap = voplfb_plane_fb_remap, + .fb_pan_display = voplfb_plane_fb_pan_display, + .fb_cleanup = voplfb_plane_fb_cleanup, +}; + +static rt_err_t voplfb_clk_enable(struct voplfb *vfb) +{ + if (!vfb->clk_enabled && !rt_is_err_or_null(vfb->clks)) + { + rt_clk_array_prepare_enable(vfb->clks); + vfb->clk_enabled = RT_TRUE; + } + + return RT_EOK; +} + +static void voplfb_clk_disable(struct voplfb *vfb) +{ + if (vfb->clk_enabled && !rt_is_err_or_null(vfb->clks)) + { + rt_clk_array_disable_unprepare(vfb->clks); + vfb->clk_enabled = RT_FALSE; + } +} + +static rt_err_t voplfb_dpms_switch(struct rt_graphic_device *gdev, rt_uint32_t dpms) +{ + struct voplfb *vfb = rt_container_of(gdev, struct voplfb, parent); + + switch (dpms) + { + case RT_GRAPHIC_DPMS_ON: + voplfb_clk_enable(vfb); + vfb->powered = RT_TRUE; + + if (vfb->primary && vfb->primary->framebuffer) + { + voplfb_plane_commit(vfb, vfb->primary, RT_TRUE); + } + + rt_graphic_device_update_auto(gdev, RT_GRAPHIC_UPDATE_MS); + break; + + case RT_GRAPHIC_DPMS_STANDBY: + case RT_GRAPHIC_DPMS_SUSPEND: + rt_graphic_device_update_auto(gdev, 0); + + if (vfb->primary) + { + voplfb_plane_commit(vfb, vfb->primary, RT_FALSE); + } + break; + + case RT_GRAPHIC_DPMS_OFF: + rt_graphic_device_update_auto(gdev, 0); + + if (vfb->primary) + { + voplfb_plane_commit(vfb, vfb->primary, RT_FALSE); + } + + voplfb_clk_disable(vfb); + vfb->powered = RT_FALSE; + break; + + default: + return -RT_EINVAL; + } + + gdev->dpms = dpms; + + return RT_EOK; +} + +static rt_err_t voplfb_wait_vsync(struct rt_graphic_device *gdev) +{ + struct voplfb *vfb = rt_container_of(gdev, struct voplfb, parent); + + if (vfb->irq >= 0) + { + rt_atomic_store(&vfb->vsync, 0); + + if (rt_sem_take(&vfb->vsync_sem, rt_tick_from_millisecond(100)) == RT_EOK) + { + return RT_EOK; + } + } + + rt_thread_mdelay(16); + + return RT_EOK; +} + +static void voplfb_isr(int irq, void *param) +{ + struct voplfb *vfb = param; + + RT_UNUSED(irq); + + if (rt_atomic_load(&vfb->vsync) == 0) + { + rt_atomic_store(&vfb->vsync, 1); + rt_sem_release(&vfb->vsync_sem); + } +} + +static const struct rt_graphic_device_ops voplfb_ops = +{ + .dpms_switch = voplfb_dpms_switch, + .wait_vsync = voplfb_wait_vsync, +}; + +static rt_err_t voplfb_crtc_mode_set(void *priv, const struct display_route *route, + const struct display_timing *tim) +{ + struct voplfb *vfb = priv; + + RT_UNUSED(route); + + if (!vfb) + { + return -RT_EINVAL; + } + + vfb->output_tim = *tim; + vfb->output_tim_valid = RT_TRUE; + + return voplfb_output_mode_set(vfb, tim); +} + +static rt_err_t voplfb_crtc_enable(void *priv, rt_uint32_t vp_id, rt_bool_t enable) +{ + struct voplfb *vfb = priv; + + RT_UNUSED(vp_id); + + return voplfb_output_enable(vfb, enable); +} + +static const struct rockchip_crtc_ops voplfb_crtc_ops = +{ + .mode_set = voplfb_crtc_mode_set, + .enable = voplfb_crtc_enable, +}; + +static void voplfb_plane_init_fb_state(struct rt_graphic_plane *plane, rt_uint32_t mode) +{ + rt_uint32_t bpp = rt_graphic_mode_bpp(mode); + + plane->mode = mode; + plane->bits_per_pixel = bpp; + plane->line_length = RT_ALIGN(plane->width * bpp, 32) / 8; + plane->screen_len = plane->line_length * plane->height; + plane->framebuffer = RT_NULL; + plane->framebuffer_len = 0; +} + +static rt_err_t voplfb_plane_init(struct voplfb *vfb, struct rt_graphic_plane *plane, + rt_uint32_t width, rt_uint32_t height) +{ + struct voplfb_plane_priv *priv = voplfb_plane_priv(plane); + + priv->enabled = RT_FALSE; + priv->pan_offset = 0; + plane->z = 1; + plane->alpha = 0xff; + plane->x = 0; + plane->y = 0; + plane->width = width; + plane->height = height; + + voplfb_plane_init_fb_state(plane, RTGRAPHIC_PIXEL_FORMAT_ARGB888); + + return RT_EOK; +} + +static rt_err_t voplfb_planes_create(struct voplfb *vfb, rt_uint32_t width, rt_uint32_t height) +{ + rt_err_t err; + struct rt_graphic_plane *plane; + + plane = rt_graphic_device_alloc_plane(&vfb->parent, sizeof(struct voplfb_plane_priv), + &voplfb_primary_ops, voplfb_modes, RT_ARRAY_SIZE(voplfb_modes), + RT_GRAPHIC_PLANE_TYPE_PRIMARY); + + if (!plane) + { + return -RT_ENOMEM; + } + + if ((err = rt_graphic_device_add_plane(&vfb->parent, plane))) + { + rt_graphic_device_free_plane(plane); + return err; + } + + vfb->primary = plane; + + return voplfb_plane_init(vfb, plane, width, height); +} + +static rt_err_t voplfb_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + struct rt_device *dev = &pdev->parent; + struct rt_ofw_node *np = dev->ofw_node; + struct voplfb *vfb = rt_calloc(1, sizeof(*vfb)); + + if (!vfb) + { + return -RT_ENOMEM; + } + + vfb->display_w = 1920; + vfb->display_h = 1080; + rt_dm_dev_prop_read_u32(dev, "rockchip,fb-width", &vfb->display_w); + rt_dm_dev_prop_read_u32(dev, "rockchip,fb-height", &vfb->display_h); + + if (!vfb->display_w || !vfb->display_h) + { + err = -RT_EINVAL; + goto _fail; + } + + vfb->regs = rt_ofw_iomap(np, 0); + + if (!vfb->regs) + { + err = -RT_EIO; + goto _fail; + } + + vfb->clks = rt_clk_get_array(dev); + + if (rt_is_err(vfb->clks)) + { + err = rt_ptr_err(vfb->clks); + goto _fail_unmap; + } + + vfb->irq = rt_dm_dev_get_irq(dev, 0); + + if (vfb->irq >= 0) + { + rt_sem_init(&vfb->vsync_sem, "vopl-vsync", 0, RT_IPC_FLAG_FIFO); + rt_hw_interrupt_install(vfb->irq, voplfb_isr, vfb, "vopl"); + rt_hw_interrupt_umask(vfb->irq); + } + + vfb->parent.ops = &voplfb_ops; + + if ((err = voplfb_clk_enable(vfb))) + { + goto _fail_irq; + } + + vfb->powered = RT_TRUE; + + rockchip_display_register_crtc(np, &voplfb_crtc_ops, vfb); + + if ((err = voplfb_planes_create(vfb, vfb->display_w, vfb->display_h))) + { + goto _fail_clk; + } + + rt_graphic_device_simple_edid(&vfb->parent, vfb->display_w, vfb->display_h, 60); + + if ((err = rt_graphic_device_register(&vfb->parent))) + { + goto _fail_clk; + } + + voplfb_dpms_switch(&vfb->parent, RT_GRAPHIC_DPMS_ON); + + pdev->parent.user_data = vfb; + + LOG_I("VOPL rk3576: %ux%u", vfb->display_w, vfb->display_h); + + return RT_EOK; + +_fail_clk: + voplfb_clk_disable(vfb); +_fail_irq: + if (vfb->irq >= 0) + { + rt_hw_interrupt_mask(vfb->irq); + rt_sem_detach(&vfb->vsync_sem); + } + + if (!rt_is_err_or_null(vfb->clks)) + { + rt_clk_array_put(vfb->clks); + } +_fail_unmap: + rt_iounmap(vfb->regs); +_fail: + rt_free(vfb); + + return err; +} + +static const struct rt_ofw_node_id voplfb_ids[] = +{ + { .compatible = "rockchip,rk3576-vop-lit" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver voplfb_driver = +{ + .name = "vopl-framebuffer", + .ids = voplfb_ids, + .probe = voplfb_probe, +}; +RT_PLATFORM_DRIVER_EXPORT(voplfb_driver); diff --git a/bsp/rockchip/dm/graphic/framebuffer/fb-vopl.h b/bsp/rockchip/dm/graphic/framebuffer/fb-vopl.h new file mode 100644 index 000000000000..661523c4146c --- /dev/null +++ b/bsp/rockchip/dm/graphic/framebuffer/fb-vopl.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-09-23 GuEe-GUI first version + */ + +#ifndef __FB_VOPL_H__ +#define __FB_VOPL_H__ + +#include "rockchip-display.h" + +enum voplfb_hw_format +{ + VOPLFB_FMT_ARGB8888 = 0, + VOPLFB_FMT_RGB888, + VOPLFB_FMT_RGB565, +}; + +struct voplfb +{ + struct rt_graphic_device parent; + + void *regs; + rt_uint32_t display_w; + rt_uint32_t display_h; + + struct display_timing output_tim; + rt_bool_t output_tim_valid; + + rt_bool_t clk_enabled; + struct rt_clk_array *clks; + + int irq; + rt_atomic_t vsync; + struct rt_semaphore vsync_sem; + + struct rt_graphic_plane *primary; + + rt_bool_t powered; +}; + +rt_uint32_t voplfb_mode_to_hw(rt_uint32_t mode); +rt_uint32_t voplfb_hw_to_bpp(rt_uint32_t hw_fmt); + +#endif /* __FB_VOPL_H__ */ diff --git a/bsp/rockchip/dm/graphic/framebuffer/hdmi-rockchip.c b/bsp/rockchip/dm/graphic/framebuffer/hdmi-rockchip.c new file mode 100644 index 000000000000..020d95eb5ad4 --- /dev/null +++ b/bsp/rockchip/dm/graphic/framebuffer/hdmi-rockchip.c @@ -0,0 +1,1090 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-09-23 GuEe-GUI first version + */ + +#include "rockchip-display.h" +#include "rockchip-hdmi.h" +#include "dw-hdmi-regs.h" + +#define DBG_TAG "hdmi.rk" +#define DBG_LVL DBG_INFO +#include + +#define RK3568_GRF_VO_CON1 0x0364 +#define RK3568_HDMI_SDAIN_MSK ((1U << 15) | (1U << (15 + 16))) +#define RK3568_HDMI_SCLIN_MSK ((1U << 14) | (1U << (14 + 16))) +#define RK_HDMI_PHY_I2C_TIMEOUT_US 20000 + +struct rk_hdmi_phy_config +{ + rt_uint32_t mpixelclock; + rt_uint16_t sym_ctr; + rt_uint16_t term; + rt_uint16_t vlev_ctr; +}; + +struct rk_hdmi_mpll_config +{ + rt_uint32_t mpixelclock; + rt_uint16_t cpce; + rt_uint16_t gmp; + rt_uint16_t curr; +}; + +struct rk_hdmi_phy_write +{ + rt_uint16_t data; + rt_uint8_t addr; +}; + +struct rk_hdmi +{ + void *regs; + struct rt_clk_array *clks; + struct rt_syscon *grf; + rt_uint32_t reg_io_width; + struct display_timing mode; + rt_bool_t clks_enabled; + rt_bool_t prepared; + rt_bool_t enabled; + rt_bool_t sink_is_hdmi; + rt_bool_t audio_configured; + rt_bool_t audio_enabled; + rt_uint32_t audio_n; +}; + +#if DBG_LVL >= DBG_LOG +static rt_ubase_t rk_hdmi_clk_rate(struct rk_hdmi *hdmi, const char *name) +{ + if (!hdmi || !hdmi->clks || !name) + { + return 0; + } + + for (rt_size_t i = 0; i < hdmi->clks->count; i++) + { + struct rt_clk *clk = hdmi->clks->clks[i]; + + if (!rt_is_err_or_null(clk) && clk->con_id && !rt_strcmp(clk->con_id, name)) + { + return rt_clk_get_rate(clk); + } + } + + return 0; +} +#endif /* DBG_LVL >= DBG_LOG */ + +static const struct rk_hdmi_phy_config rockchip_phy_config[] = +{ + { 74250000, 0x8009, 0x0004, 0x0272 }, + { 165000000, 0x802b, 0x0004, 0x0209 }, + { 297000000, 0x8039, 0x0005, 0x028d }, + { 594000000, 0x8039, 0x0000, 0x019d }, + { ~0u, 0x0000, 0x0000, 0x0000 }, +}; + +static const struct rk_hdmi_mpll_config rockchip_mpll_cfg[] = +{ + { 30666000, 0x00b3, 0x0000, 0x0000 }, + { 36800000, 0x00b3, 0x0000, 0x0000 }, + { 46000000, 0x00b3, 0x0000, 0x0000 }, + { 61333000, 0x0072, 0x0001, 0x0000 }, + { 73600000, 0x0072, 0x0001, 0x0000 }, + { 92000000, 0x0072, 0x0001, 0x0000 }, + { 122666000, 0x0051, 0x0002, 0x0000 }, + { 147200000, 0x0051, 0x0002, 0x0000 }, + { 184000000, 0x0051, 0x0002, 0x0000 }, + { 226666000, 0x0040, 0x0003, 0x0000 }, + { 272000000, 0x0040, 0x0003, 0x0000 }, + { 340000000, 0x0040, 0x0003, 0x0000 }, + { 600000000, 0x1a40, 0x0003, 0x0000 }, + { ~0u, 0x0051, 0x0003, 0x0000 }, +}; + +static const rt_uint16_t rk_hdmi_csc_coeff_default[3][4] = +{ + { 0x2000, 0x0000, 0x0000, 0x0000 }, + { 0x0000, 0x2000, 0x0000, 0x0000 }, + { 0x0000, 0x0000, 0x2000, 0x0000 }, +}; + +rt_inline void rk_hdmi_write(struct rk_hdmi *hdmi, rt_uint32_t reg, rt_uint8_t val) +{ + if (hdmi->reg_io_width == 1) + { + HWREG8((rt_uint8_t *)hdmi->regs + reg) = val; + } + else + { + HWREG32((rt_uint8_t *)hdmi->regs + (reg << 2)) = val; + } +} + +rt_inline rt_uint8_t rk_hdmi_read(struct rk_hdmi *hdmi, rt_uint32_t reg) +{ + if (hdmi->reg_io_width == 1) + { + return HWREG8((rt_uint8_t *)hdmi->regs + reg); + } + + return (rt_uint8_t)HWREG32((rt_uint8_t *)hdmi->regs + (reg << 2)); +} + +static void rk_hdmi_mod(struct rk_hdmi *hdmi, rt_uint32_t reg, rt_uint8_t mask, rt_uint8_t data) +{ + rt_uint8_t val = rk_hdmi_read(hdmi, reg) & ~mask; + + val |= data & mask; + rk_hdmi_write(hdmi, reg, val); +} + +static struct rk_hdmi *rk_hdmi_from_np(struct rt_ofw_node *np) +{ + if (!np) + { + return RT_NULL; + } + + return rt_ofw_data(np); +} + +static rt_uint32_t rk_hdmi_audio_n(rt_uint32_t samplerate) +{ + switch (samplerate) + { + case 32000: + return 4096; + case 44100: + return 6272; + case 48000: + return 6144; + case 88200: + return 12544; + case 96000: + return 12288; + case 176400: + return 25088; + case 192000: + return 24576; + default: + return 0; + } +} + +static void rk_hdmi_audio_set_n(struct rk_hdmi *hdmi, rt_uint32_t n) +{ + /* I2S uses the controller's automatic CTS generator. */ + rk_hdmi_mod(hdmi, HDMI_AUD_CTS3, + HDMI_AUD_CTS3_N_SHIFT_MASK | HDMI_AUD_CTS3_CTS_MANUAL, 0); + rk_hdmi_write(hdmi, HDMI_AUD_CTS2, 0); + rk_hdmi_write(hdmi, HDMI_AUD_CTS1, 0); + rk_hdmi_write(hdmi, HDMI_AUD_N3, (n >> 16) & 0x0f); + rk_hdmi_write(hdmi, HDMI_AUD_N2, n >> 8); + rk_hdmi_write(hdmi, HDMI_AUD_N1, n); +} + +rt_err_t rk_hdmi_audio_enable(struct rt_ofw_node *np, rt_bool_t enable) +{ + rt_uint8_t clkdis; + struct rk_hdmi *hdmi = rk_hdmi_from_np(np); + + if (!hdmi) + { + return -RT_ENOSYS; + } + + if (enable && (!hdmi->enabled || !hdmi->sink_is_hdmi || + !hdmi->audio_configured)) + { + return -RT_EINVAL; + } + + hdmi->audio_enabled = enable; + clkdis = rk_hdmi_read(hdmi, HDMI_MC_CLKDIS); + + if (enable) + { + rk_hdmi_audio_set_n(hdmi, hdmi->audio_n); + clkdis &= ~HDMI_MC_CLKDIS_AUDCLK_DISABLE; + } + else + { + rk_hdmi_audio_set_n(hdmi, 0); + clkdis |= HDMI_MC_CLKDIS_AUDCLK_DISABLE; + } + + rk_hdmi_write(hdmi, HDMI_MC_CLKDIS, clkdis); + + return RT_EOK; +} + +rt_err_t rk_hdmi_audio_configure(struct rt_ofw_node *np, + rt_uint32_t samplerate, rt_uint8_t channels, rt_uint8_t samplebits) +{ + rt_uint8_t conf0, conf1; + struct rk_hdmi *hdmi = rk_hdmi_from_np(np); + rt_uint32_t n = rk_hdmi_audio_n(samplerate); + + if (!hdmi) + { + return -RT_ENOSYS; + } + + if (!hdmi->enabled || !hdmi->sink_is_hdmi) + { + return -RT_EBUSY; + } + + if (!n || channels != 2 || (samplebits != 16 && samplebits != 24 && samplebits != 32)) + { + return -RT_EINVAL; + } + + rk_hdmi_audio_enable(np, RT_FALSE); + + /* Reset the I2S FIFO before changing its input format. */ + rk_hdmi_write(hdmi, HDMI_AUD_CONF0, HDMI_AUD_CONF0_SW_RESET); + rk_hdmi_write(hdmi, HDMI_MC_SWRSTZ, (rt_uint8_t)~HDMI_MC_SWRSTZ_I2SSWRST_REQ); + + conf0 = HDMI_AUD_CONF0_I2S_SELECT | HDMI_AUD_CONF0_I2S_EN0; + conf1 = HDMI_AUD_CONF1_MODE_I2S | + (samplebits == 16 ? HDMI_AUD_CONF1_WIDTH_16 : HDMI_AUD_CONF1_WIDTH_24); + + rk_hdmi_write(hdmi, HDMI_AUD_INPUTCLKFS, HDMI_AUD_INPUTCLKFS_64FS); + rk_hdmi_write(hdmi, HDMI_AUD_CONF0, conf0); + rk_hdmi_write(hdmi, HDMI_AUD_CONF1, conf1); + rk_hdmi_write(hdmi, HDMI_AUD_CONF2, + rk_hdmi_read(hdmi, HDMI_DESIGN_ID) >= 0x21 ? HDMI_AUD_CONF2_INSERT_PCUV : 0); + + /* Stereo PCM uses layout 0 and channel allocation 0. */ + rk_hdmi_mod(hdmi, HDMI_FC_AUDSCONF, + HDMI_FC_AUDSCONF_AUD_PACKET_LAYOUT_MASK, + HDMI_FC_AUDSCONF_AUD_PACKET_LAYOUT_LAYOUT0); + rk_hdmi_mod(hdmi, HDMI_FC_AUDICONF0, + HDMI_FC_AUDICONF0_CC_MASK, (channels - 1) << HDMI_FC_AUDICONF0_CC_OFFSET); + rk_hdmi_write(hdmi, HDMI_FC_AUDICONF1, 0); + rk_hdmi_write(hdmi, HDMI_FC_AUDICONF2, 0); + rk_hdmi_write(hdmi, HDMI_FC_AUDICONF3, 0); + + /* IEC60958 consumer PCM: sample frequency and 16-bit word length. */ + rk_hdmi_write(hdmi, HDMI_FC_AUDSCHNLS7, + samplerate == 48000 ? 0x02 : samplerate == 44100 ? 0x00 : 0x03); + rk_hdmi_write(hdmi, HDMI_FC_AUDSCHNLS8, samplebits == 16 ? 0x02 : 0x0b); + + hdmi->audio_n = n; + hdmi->audio_configured = RT_TRUE; + rk_hdmi_write(hdmi, HDMI_AUD_CONF0, conf0 | HDMI_AUD_CONF0_SW_RESET); + rk_hdmi_write(hdmi, HDMI_MC_SWRSTZ, (rt_uint8_t)~HDMI_MC_SWRSTZ_I2SSWRST_REQ); + + LOG_D("audio %u Hz, %u ch, %u bit, N=%u", + samplerate, channels, samplebits, n); + + return RT_EOK; +} + +static void rk_hdmi_phy_test_clear(struct rk_hdmi *hdmi, rt_uint8_t enable) +{ + rk_hdmi_mod(hdmi, HDMI_PHY_TST0, HDMI_PHY_TST0_TSTCLR_MASK, + enable << HDMI_PHY_TST0_TSTCLR_OFFSET); +} + +static rt_err_t rk_hdmi_phy_wait_i2c_done(struct rk_hdmi *hdmi, + rt_uint32_t timeout_us) +{ + rt_uint32_t step_us = 100; + rt_uint32_t waited = 0; + + while (waited < timeout_us) + { + rt_uint8_t val = rk_hdmi_read(hdmi, HDMI_IH_I2CMPHY_STAT0); + + if (val & (HDMI_IH_I2CMPHY_STAT0_DONE | + HDMI_IH_I2CMPHY_STAT0_ERROR)) + { + rk_hdmi_write(hdmi, HDMI_IH_I2CMPHY_STAT0, val); + + return (val & HDMI_IH_I2CMPHY_STAT0_ERROR) ? + -RT_EIO : RT_EOK; + } + + rt_hw_us_delay(step_us); + waited += step_us; + } + + return -RT_ETIMEOUT; +} + +static rt_err_t rk_hdmi_phy_i2c_write(struct rk_hdmi *hdmi, + rt_uint16_t data, rt_uint8_t addr) +{ + rk_hdmi_write(hdmi, HDMI_IH_I2CMPHY_STAT0, 0xff); + rk_hdmi_write(hdmi, HDMI_PHY_I2CM_ADDRESS_ADDR, addr); + rk_hdmi_write(hdmi, HDMI_PHY_I2CM_DATAO_1_ADDR, (rt_uint8_t)(data >> 8)); + rk_hdmi_write(hdmi, HDMI_PHY_I2CM_DATAO_0_ADDR, (rt_uint8_t)data); + rk_hdmi_write(hdmi, HDMI_PHY_I2CM_OPERATION_ADDR, HDMI_PHY_I2CM_OPERATION_ADDR_WRITE); + return rk_hdmi_phy_wait_i2c_done(hdmi, RK_HDMI_PHY_I2C_TIMEOUT_US); +} + +static void rk_hdmi_phy_enable_svsret(struct rk_hdmi *hdmi, rt_uint8_t enable) +{ + rk_hdmi_mod(hdmi, HDMI_PHY_CONF0, HDMI_PHY_CONF0_SVSRET_MASK, + enable << HDMI_PHY_CONF0_SVSRET_OFFSET); +} + +static void rk_hdmi_phy_gen2_pddq(struct rk_hdmi *hdmi, rt_uint8_t enable) +{ + rk_hdmi_mod(hdmi, HDMI_PHY_CONF0, HDMI_PHY_CONF0_GEN2_PDDQ_MASK, + enable << HDMI_PHY_CONF0_GEN2_PDDQ_OFFSET); +} + +static void rk_hdmi_phy_gen2_txpwron(struct rk_hdmi *hdmi, rt_uint8_t enable) +{ + rk_hdmi_mod(hdmi, HDMI_PHY_CONF0, HDMI_PHY_CONF0_GEN2_TXPWRON_MASK, + enable << HDMI_PHY_CONF0_GEN2_TXPWRON_OFFSET); +} + +static void rk_hdmi_phy_power_off(struct rk_hdmi *hdmi) +{ + rt_uint32_t waited_us = 0; + + rk_hdmi_phy_gen2_txpwron(hdmi, 0); + + while (waited_us < 5000) + { + if (!(rk_hdmi_read(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_TX_PHY_LOCK)) + { + break; + } + + rt_hw_us_delay(100); + waited_us += 100; + } + + rk_hdmi_phy_gen2_pddq(hdmi, 1); +} + +static void rk_hdmi_phy_sel_data_en_pol(struct rk_hdmi *hdmi, rt_uint8_t enable) +{ + rk_hdmi_mod(hdmi, HDMI_PHY_CONF0, HDMI_PHY_CONF0_SELDATAENPOL_MASK, + enable << HDMI_PHY_CONF0_SELDATAENPOL_OFFSET); +} + +static void rk_hdmi_phy_sel_interface_control(struct rk_hdmi *hdmi, rt_uint8_t enable) +{ + rk_hdmi_mod(hdmi, HDMI_PHY_CONF0, HDMI_PHY_CONF0_SELDIPIF_MASK, + enable << HDMI_PHY_CONF0_SELDIPIF_OFFSET); +} + +static rt_err_t rk_hdmi_phy_configure(struct rk_hdmi *hdmi, rt_uint32_t mpixelclock) +{ + rt_err_t err; + const struct rk_hdmi_mpll_config *mpll_cfg = rockchip_mpll_cfg; + const struct rk_hdmi_phy_config *phy_cfg = rockchip_phy_config; + struct rk_hdmi_phy_write writes[8]; + rt_size_t i; + rt_uint32_t waited_us = 0; + + while (mpll_cfg->mpixelclock != ~0u && mpixelclock > mpll_cfg->mpixelclock) + { + mpll_cfg++; + } + + while (phy_cfg->mpixelclock != ~0u && mpixelclock > phy_cfg->mpixelclock) + { + phy_cfg++; + } + + if (mpll_cfg->mpixelclock == ~0u || phy_cfg->mpixelclock == ~0u) + { + return -RT_EINVAL; + } + + LOG_D("phy cfg: mpixel=%u mpll(cpce=0x%04x gmp=0x%04x curr=0x%04x) phy(sym=0x%04x term=0x%04x vlev=0x%04x)", + mpixelclock, + mpll_cfg->cpce, mpll_cfg->gmp, mpll_cfg->curr, + phy_cfg->sym_ctr, phy_cfg->term, phy_cfg->vlev_ctr); + + rk_hdmi_phy_power_off(hdmi); + rk_hdmi_phy_enable_svsret(hdmi, 1); + + rk_hdmi_write(hdmi, HDMI_MC_PHYRSTZ, HDMI_MC_PHYRSTZ_PHYRSTZ); + rk_hdmi_write(hdmi, HDMI_MC_PHYRSTZ, 0); + rk_hdmi_write(hdmi, HDMI_MC_HEACPHY_RST, HDMI_MC_HEACPHY_RST_ASSERT); + + rk_hdmi_phy_test_clear(hdmi, 1); + rk_hdmi_write(hdmi, HDMI_PHY_I2CM_SLAVE_ADDR, HDMI_PHY_I2CM_SLAVE_ADDR_PHY_GEN2); + rk_hdmi_phy_test_clear(hdmi, 0); + + writes[0] = (struct rk_hdmi_phy_write) + { mpll_cfg->cpce, HDMI_3D_TX_PHY_CPCE_CTRL }; + writes[1] = (struct rk_hdmi_phy_write) + { mpll_cfg->gmp, HDMI_3D_TX_PHY_GMPCTRL }; + writes[2] = (struct rk_hdmi_phy_write) + { mpll_cfg->curr, HDMI_3D_TX_PHY_CURRCTRL }; + writes[3] = (struct rk_hdmi_phy_write) + { 0x0000, HDMI_3D_TX_PHY_PLLPHBYCTRL }; + writes[4] = (struct rk_hdmi_phy_write) + { HDMI_3D_TX_PHY_MSM_CTRL_CKO_SEL_FB_CLK, HDMI_3D_TX_PHY_MSM_CTRL }; + writes[5] = (struct rk_hdmi_phy_write) + { phy_cfg->term, HDMI_3D_TX_PHY_TXTERM }; + writes[6] = (struct rk_hdmi_phy_write) + { phy_cfg->sym_ctr, HDMI_3D_TX_PHY_CKSYMTXCTRL }; + writes[7] = (struct rk_hdmi_phy_write) + { phy_cfg->vlev_ctr, HDMI_3D_TX_PHY_VLEVCTRL }; + + for (i = 0; i < RT_ARRAY_SIZE(writes); ++i) + { + err = rk_hdmi_phy_i2c_write(hdmi, writes[i].data, writes[i].addr); + if (err) + { + LOG_W("PHY I2C write reg=0x%02x failed: %s", + writes[i].addr, rt_strerror(err)); + rk_hdmi_phy_power_off(hdmi); + return err; + } + } + + rk_hdmi_phy_gen2_txpwron(hdmi, 1); + rk_hdmi_phy_gen2_pddq(hdmi, 0); + + while (waited_us < 5000) + { + rt_uint8_t stat0 = rk_hdmi_read(hdmi, HDMI_PHY_STAT0); + + if (stat0 & HDMI_PHY_TX_PHY_LOCK) + { + return RT_EOK; + } + + rt_hw_us_delay(100); + waited_us += 100; + } + + LOG_W("PHY pll lock timeout, stat0=0x%02x", rk_hdmi_read(hdmi, HDMI_PHY_STAT0)); + rk_hdmi_phy_power_off(hdmi); + + return -RT_ETIMEOUT; +} + +static rt_err_t rk_hdmi_phy_init(struct rk_hdmi *hdmi) +{ + if (!hdmi->mode.pixelclock) + { + return -RT_EINVAL; + } + + rk_hdmi_phy_sel_data_en_pol(hdmi, 1); + rk_hdmi_phy_sel_interface_control(hdmi, 0); + + return rk_hdmi_phy_configure(hdmi, + (rt_uint32_t)hdmi->mode.pixelclock); +} + +static void rk_hdmi_video_sample(struct rk_hdmi *hdmi) +{ + rt_uint8_t val = HDMI_TX_INVID0_INTERNAL_DE_GENERATOR_DISABLE | + (1 << HDMI_TX_INVID0_VIDEO_MAPPING_OFFSET); + + rk_hdmi_write(hdmi, HDMI_TX_INVID0, val); + + val = HDMI_TX_INSTUFFING_BDBDATA_STUFFING_ENABLE | + HDMI_TX_INSTUFFING_RCRDATA_STUFFING_ENABLE | + HDMI_TX_INSTUFFING_GYDATA_STUFFING_ENABLE; + + rk_hdmi_write(hdmi, HDMI_TX_INSTUFFING, val); + rk_hdmi_write(hdmi, HDMI_TX_GYDATA0, 0x00); + rk_hdmi_write(hdmi, HDMI_TX_GYDATA1, 0x00); + rk_hdmi_write(hdmi, HDMI_TX_RCRDATA0, 0x00); + rk_hdmi_write(hdmi, HDMI_TX_RCRDATA1, 0x00); + rk_hdmi_write(hdmi, HDMI_TX_BCBDATA0, 0x00); + rk_hdmi_write(hdmi, HDMI_TX_BCBDATA1, 0x00); +} + +static void rk_hdmi_video_packetize(struct rk_hdmi *hdmi) +{ + rt_uint8_t val; + + /* + * Keep the 8-bit RGB888 HDMI path aligned with the Synopsys/U-Boot + * configuration: bypass the packetizer datapath, no YCC422 remap, and + * leave the default phase cleared. + */ + val = ((0 << HDMI_VP_PR_CD_COLOR_DEPTH_OFFSET) & HDMI_VP_PR_CD_COLOR_DEPTH_MASK) | + ((0 << HDMI_VP_PR_CD_DESIRED_PR_FACTOR_OFFSET) & HDMI_VP_PR_CD_DESIRED_PR_FACTOR_MASK); + rk_hdmi_write(hdmi, HDMI_VP_PR_CD, val); + + rk_hdmi_mod(hdmi, HDMI_VP_STUFF, HDMI_VP_STUFF_PR_STUFFING_MASK, + HDMI_VP_STUFF_PR_STUFFING_STUFFING_MODE); + + val = HDMI_VP_CONF_PR_EN_DISABLE | + HDMI_VP_CONF_BYPASS_SELECT_VID_PACKETIZER; + rk_hdmi_mod(hdmi, HDMI_VP_CONF, + HDMI_VP_CONF_PR_EN_MASK | HDMI_VP_CONF_BYPASS_SELECT_MASK, val); + + rk_hdmi_mod(hdmi, HDMI_VP_STUFF, HDMI_VP_STUFF_IDEFAULT_PHASE_MASK, 0); + + rk_hdmi_write(hdmi, HDMI_VP_REMAP, 0); + + val = HDMI_VP_CONF_BYPASS_EN_ENABLE | + HDMI_VP_CONF_PP_EN_DISABLE | + HDMI_VP_CONF_YCC422_EN_DISABLE; + rk_hdmi_mod(hdmi, HDMI_VP_CONF, + HDMI_VP_CONF_BYPASS_EN_MASK | + HDMI_VP_CONF_PP_EN_ENMASK | + HDMI_VP_CONF_YCC422_EN_MASK, val); + + rk_hdmi_mod(hdmi, HDMI_VP_STUFF, + HDMI_VP_STUFF_PP_STUFFING_MASK | HDMI_VP_STUFF_YCC422_STUFFING_MASK, + HDMI_VP_STUFF_PP_STUFFING_STUFFING_MODE | + HDMI_VP_STUFF_YCC422_STUFFING_STUFFING_MODE); + + rk_hdmi_mod(hdmi, HDMI_VP_CONF, HDMI_VP_CONF_OUTPUT_SELECTOR_MASK, + HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS); +} + +static void rk_hdmi_video_csc(struct rk_hdmi *hdmi) +{ + rt_size_t i; + + if (!hdmi) + { + return; + } + + rk_hdmi_write(hdmi, HDMI_CSC_CFG, + HDMI_CSC_CFG_INTMODE_DISABLE | HDMI_CSC_CFG_DECMODE_DISABLE); + rk_hdmi_mod(hdmi, HDMI_CSC_SCALE, + HDMI_CSC_SCALE_CSC_COLORDE_PTH_MASK | + HDMI_CSC_SCALE_CSCSCALE_MASK, + HDMI_CSC_SCALE_CSC_COLORDE_PTH_24BPP | 0x01); + + for (i = 0; i < 4; i++) + { + rt_uint16_t coeff_a = rk_hdmi_csc_coeff_default[0][i]; + rt_uint16_t coeff_b = rk_hdmi_csc_coeff_default[1][i]; + rt_uint16_t coeff_c = rk_hdmi_csc_coeff_default[2][i]; + + rk_hdmi_write(hdmi, HDMI_CSC_COEF_A1_LSB + i * 2, coeff_a & 0xff); + rk_hdmi_write(hdmi, HDMI_CSC_COEF_A1_MSB + i * 2, coeff_a >> 8); + rk_hdmi_write(hdmi, HDMI_CSC_COEF_B1_LSB + i * 2, coeff_b & 0xff); + rk_hdmi_write(hdmi, HDMI_CSC_COEF_B1_MSB + i * 2, coeff_b >> 8); + rk_hdmi_write(hdmi, HDMI_CSC_COEF_C1_LSB + i * 2, coeff_c & 0xff); + rk_hdmi_write(hdmi, HDMI_CSC_COEF_C1_MSB + i * 2, coeff_c >> 8); + } +} + +static void rk_hdmi_config_input_polarity(struct rk_hdmi *hdmi, + const struct display_timing *tim) +{ + rt_uint8_t pol = HDMI_A_VIDPOLCFG_DATAENPOL_ACTIVE_HIGH; + + if (!hdmi || !tim) + { + return; + } + + pol |= (tim->flags & DISPLAY_TIMING_F_PVSYNC) ? + HDMI_A_VIDPOLCFG_VSYNCPOL_ACTIVE_HIGH : + HDMI_A_VIDPOLCFG_VSYNCPOL_ACTIVE_LOW; + pol |= (tim->flags & DISPLAY_TIMING_F_PHSYNC) ? + HDMI_A_VIDPOLCFG_HSYNCPOL_ACTIVE_HIGH : + HDMI_A_VIDPOLCFG_HSYNCPOL_ACTIVE_LOW; + + rk_hdmi_mod(hdmi, HDMI_A_VIDPOLCFG, + HDMI_A_VIDPOLCFG_VSYNCPOL_MASK | + HDMI_A_VIDPOLCFG_HSYNCPOL_MASK | + HDMI_A_VIDPOLCFG_DATAENPOL_MASK, + pol); +} + +#if DBG_LVL >= DBG_LOG +static void rk_hdmi_dump_regs(struct rk_hdmi *hdmi, const char *tag) +{ + if (!hdmi) + { + return; + } + + LOG_D("%s: PHY_STAT0=0x%02x PHY_CONF0=0x%02x MC_CLKDIS=0x%02x MC_FLOWCTRL=0x%02x", + tag, + rk_hdmi_read(hdmi, HDMI_PHY_STAT0), + rk_hdmi_read(hdmi, HDMI_PHY_CONF0), + rk_hdmi_read(hdmi, HDMI_MC_CLKDIS), + rk_hdmi_read(hdmi, HDMI_MC_FLOWCTRL)); + LOG_D("%s: FC_INVIDCONF=0x%02x A_HDCPCFG0=0x%02x TX_INVID0=0x%02x", + tag, + rk_hdmi_read(hdmi, HDMI_FC_INVIDCONF), + rk_hdmi_read(hdmi, HDMI_A_HDCPCFG0), + rk_hdmi_read(hdmi, HDMI_TX_INVID0)); + LOG_D("%s: A_VIDPOLCFG=0x%02x CONFIG2_ID=0x%02x", + tag, + rk_hdmi_read(hdmi, HDMI_A_VIDPOLCFG), + rk_hdmi_read(hdmi, HDMI_CONFIG2_ID)); + LOG_D("%s: CSC_CFG=0x%02x CSC_SCALE=0x%02x", + tag, + rk_hdmi_read(hdmi, HDMI_CSC_CFG), + rk_hdmi_read(hdmi, HDMI_CSC_SCALE)); + LOG_D("%s: VP_CONF=0x%02x VP_PR_CD=0x%02x VP_STUFF=0x%02x VP_REMAP=0x%02x", + tag, + rk_hdmi_read(hdmi, HDMI_VP_CONF), + rk_hdmi_read(hdmi, HDMI_VP_PR_CD), + rk_hdmi_read(hdmi, HDMI_VP_STUFF), + rk_hdmi_read(hdmi, HDMI_VP_REMAP)); +} +#endif /* DBG_LVL >= DBG_LOG */ + +static void rk_hdmi_av_composer(struct rk_hdmi *hdmi, const struct display_timing *tim) +{ + rt_uint32_t hblank = tim->hsync_len + tim->hfront_porch + tim->hback_porch; + rt_uint32_t vblank = tim->vsync_len + tim->vfront_porch + tim->vback_porch; + rt_uint8_t inv = HDMI_FC_INVIDCONF_HDCP_KEEPOUT_ACTIVE | + HDMI_FC_INVIDCONF_DE_IN_POLARITY_ACTIVE_HIGH | + HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC_ACTIVE_LOW | + HDMI_FC_INVIDCONF_IN_I_P_PROGRESSIVE; + + inv |= hdmi->sink_is_hdmi ? + HDMI_FC_INVIDCONF_DVI_MODEZ_HDMI_MODE : + HDMI_FC_INVIDCONF_DVI_MODEZ_DVI_MODE; + + if (tim->flags & DISPLAY_TIMING_F_PHSYNC) + { + inv |= HDMI_FC_INVIDCONF_HSYNC_IN_POLARITY_ACTIVE_HIGH; + } + else + { + inv |= HDMI_FC_INVIDCONF_HSYNC_IN_POLARITY_ACTIVE_LOW; + } + + if (tim->flags & DISPLAY_TIMING_F_PVSYNC) + { + inv |= HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_ACTIVE_HIGH; + } + else + { + inv |= HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_ACTIVE_LOW; + } + + rk_hdmi_write(hdmi, HDMI_FC_INVIDCONF, inv); + rk_hdmi_write(hdmi, HDMI_FC_INHACTV1, tim->hactive >> 8); + rk_hdmi_write(hdmi, HDMI_FC_INHACTV0, tim->hactive); + rk_hdmi_write(hdmi, HDMI_FC_INVACTV1, tim->vactive >> 8); + rk_hdmi_write(hdmi, HDMI_FC_INVACTV0, tim->vactive); + rk_hdmi_write(hdmi, HDMI_FC_INHBLANK1, hblank >> 8); + rk_hdmi_write(hdmi, HDMI_FC_INHBLANK0, hblank); + rk_hdmi_write(hdmi, HDMI_FC_INVBLANK, vblank); + rk_hdmi_write(hdmi, HDMI_FC_HSYNCINDELAY1, tim->hfront_porch >> 8); + rk_hdmi_write(hdmi, HDMI_FC_HSYNCINDELAY0, tim->hfront_porch); + rk_hdmi_write(hdmi, HDMI_FC_VSYNCINDELAY, tim->vfront_porch); + rk_hdmi_write(hdmi, HDMI_FC_HSYNCINWIDTH1, tim->hsync_len >> 8); + rk_hdmi_write(hdmi, HDMI_FC_HSYNCINWIDTH0, tim->hsync_len); + rk_hdmi_write(hdmi, HDMI_FC_VSYNCINWIDTH, tim->vsync_len); +} + +static void rk_hdmi_enable_video_path(struct rk_hdmi *hdmi) +{ + rt_uint8_t clkdis = 0x7f; + + rk_hdmi_write(hdmi, HDMI_FC_CTRLDUR, 12); + rk_hdmi_write(hdmi, HDMI_FC_EXCTRLDUR, 32); + rk_hdmi_write(hdmi, HDMI_FC_EXCTRLSPAC, 1); + rk_hdmi_write(hdmi, HDMI_FC_CH0PREAM, 0x0b); + rk_hdmi_write(hdmi, HDMI_FC_CH1PREAM, 0x16); + rk_hdmi_write(hdmi, HDMI_FC_CH2PREAM, 0x21); + rk_hdmi_write(hdmi, HDMI_MC_FLOWCTRL, HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_BYPASS); + + clkdis &= ~HDMI_MC_CLKDIS_PIXELCLK_DISABLE; + rk_hdmi_write(hdmi, HDMI_MC_CLKDIS, clkdis); + + clkdis &= ~HDMI_MC_CLKDIS_TMDSCLK_DISABLE; + + if (hdmi->audio_enabled) + { + clkdis &= ~HDMI_MC_CLKDIS_AUDCLK_DISABLE; + } + + rk_hdmi_write(hdmi, HDMI_MC_CLKDIS, clkdis); +} + +static void rk_hdmi_clear_overflow(struct rk_hdmi *hdmi) +{ + rt_uint8_t val; + int count; + + rk_hdmi_write(hdmi, HDMI_MC_SWRSTZ, (rt_uint8_t)~HDMI_MC_SWRSTZ_TMDSSWRST_REQ); + + val = rk_hdmi_read(hdmi, HDMI_FC_INVIDCONF); + + for (count = 0; count < 4; count++) + { + rk_hdmi_write(hdmi, HDMI_FC_INVIDCONF, val); + } +} + +static void rk_hdmi_stabilize_link(struct rk_hdmi *hdmi) +{ + /* + * Match the Rockchip Linux DW-HDMI setup sequence. Holding the frame + * composer test video briefly gives the sink a continuous TMDS stream + * while it acquires the newly programmed mode. + */ + rk_hdmi_write(hdmi, HDMI_FC_DBGTMDS0, 0); + rk_hdmi_write(hdmi, HDMI_FC_DBGTMDS1, 0); + rk_hdmi_write(hdmi, HDMI_FC_DBGTMDS2, 0); + rk_hdmi_write(hdmi, HDMI_FC_DBGFORCE, HDMI_FC_DBGFORCE_FORCEVIDEO); + rt_thread_mdelay(50); + rk_hdmi_write(hdmi, HDMI_FC_DBGFORCE, 0); +} + +static void rk_hdmi_core_init(struct rk_hdmi *hdmi) +{ + rt_uint8_t ih_mute = HDMI_IH_MUTE_MUTE_WAKEUP_INTERRUPT | + HDMI_IH_MUTE_MUTE_ALL_INTERRUPT; + + rk_hdmi_write(hdmi, HDMI_IH_MUTE, ih_mute); + rk_hdmi_write(hdmi, HDMI_I2CM_INT, (rt_uint8_t)~HDMI_I2CM_INT_DONE_MASK); + rk_hdmi_write(hdmi, HDMI_I2CM_CTLINT, + (rt_uint8_t)~(HDMI_I2CM_CTLINT_NAC_MASK | HDMI_I2CM_CTLINT_ARB_MASK)); + rk_hdmi_write(hdmi, HDMI_IH_MUTE_FC_STAT2, + HDMI_IH_MUTE_FC_STAT2_OVERFLOW_MASK); +} + +static void rk_hdmi_phy_irq_init(struct rk_hdmi *hdmi) +{ + rk_hdmi_write(hdmi, HDMI_PHY_I2CM_INT_ADDR, HDMI_PHY_I2CM_INT_ADDR_DONE_POL); + rk_hdmi_write(hdmi, HDMI_PHY_I2CM_CTLINT_ADDR, + HDMI_PHY_I2CM_CTLINT_ADDR_NAC_POL | HDMI_PHY_I2CM_CTLINT_ADDR_ARBITRATION_POL); + rk_hdmi_write(hdmi, HDMI_PHY_MASK0, (rt_uint8_t)~HDMI_PHY_HPD); + rk_hdmi_write(hdmi, HDMI_IH_PHY_STAT0, HDMI_IH_PHY_STAT0_HPD); +} + +static rt_err_t rk_hdmi_clks_enable(struct rk_hdmi *hdmi) +{ + rt_err_t err; + + if (hdmi->clks_enabled) + { + return RT_EOK; + } + + err = rt_clk_array_prepare_enable(hdmi->clks); + if (!err) + { + hdmi->clks_enabled = RT_TRUE; + } + + return err; +} + +static void rk_hdmi_clks_disable(struct rk_hdmi *hdmi) +{ + if (!hdmi->clks_enabled) + { + return; + } + + rt_clk_array_disable_unprepare(hdmi->clks); + hdmi->clks_enabled = RT_FALSE; +} + +static rt_err_t rk_hdmi_detect(void *priv, rt_bool_t *connected) +{ + struct rk_hdmi *hdmi = priv; + rt_bool_t enabled_for_detect = RT_FALSE; + rt_uint32_t sample; + rt_err_t err; + + if (!hdmi || !connected) + { + return -RT_EINVAL; + } + + if (!hdmi->clks_enabled) + { + err = rk_hdmi_clks_enable(hdmi); + if (err) + { + return err; + } + enabled_for_detect = RT_TRUE; + + /* The HPD synchronizer is not reliable on the first bus-clock cycle. */ + rt_hw_us_delay(1000); + } + + *connected = RT_FALSE; + for (sample = 0; sample < 3; ++sample) + { + if (rk_hdmi_read(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_HPD) + { + *connected = RT_TRUE; + break; + } + + rt_hw_us_delay(1000); + } + + /* + * Keep a connected HDMI clock chain alive until prepare() takes ownership. + * Cycling the shared VO/HPLL clocks between HPD detection and mode setup can + * leave the HDMI-only path gated, while a later MIPI setup happens to bring + * that shared chain back. A disconnected probe may release its clocks. + */ + if (enabled_for_detect && !*connected) + { + rk_hdmi_clks_disable(hdmi); + } + + return RT_EOK; +} + +static rt_err_t rk_hdmi_prepare(void *priv, rt_uint32_t vp_id, const struct display_timing *tim) +{ + struct rk_hdmi *hdmi = priv; + rt_err_t err; + + RT_UNUSED(vp_id); + RT_UNUSED(tim); + + if (!hdmi) + { + return -RT_EINVAL; + } + + if (hdmi->prepared) + { + return RT_EOK; + } + + err = rk_hdmi_clks_enable(hdmi); + if (err) + { + return err; + } + + if (hdmi->grf) + { + rt_syscon_write(hdmi->grf, RK3568_GRF_VO_CON1, + RK3568_HDMI_SDAIN_MSK | RK3568_HDMI_SCLIN_MSK); + } + + rk_hdmi_core_init(hdmi); + rk_hdmi_phy_irq_init(hdmi); + hdmi->prepared = RT_TRUE; + + LOG_D("prepared, HPD=%d", !!(rk_hdmi_read(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_HPD)); + + return RT_EOK; +} + +static rt_err_t rk_hdmi_mode_set(void *priv, const struct display_timing *tim) +{ + struct rk_hdmi *hdmi = priv; + + if (!hdmi || !tim) + { + return -RT_EINVAL; + } + + hdmi->mode = *tim; + + if (!hdmi->mode.htotal || !hdmi->mode.vtotal) + { + display_timing_derive(&hdmi->mode); + } + + if (!hdmi->mode.pixelclock && hdmi->mode.htotal && hdmi->mode.vtotal) + { + hdmi->mode.pixelclock = (rt_uint64_t)hdmi->mode.htotal * hdmi->mode.vtotal * 60; + } + + LOG_D("mode %ux%u htotal=%u vtotal=%u pclk=%u", + hdmi->mode.hactive, hdmi->mode.vactive, + hdmi->mode.htotal, hdmi->mode.vtotal, + (rt_uint32_t)hdmi->mode.pixelclock); + + return RT_EOK; +} + +static rt_err_t rk_hdmi_enable(void *priv, rt_bool_t enable) +{ + struct rk_hdmi *hdmi = priv; + rt_err_t err; + + if (!hdmi) + { + return -RT_EINVAL; + } + + if (!enable) + { + if (!hdmi->clks_enabled) + { + hdmi->enabled = RT_FALSE; + return RT_EOK; + } + + rk_hdmi_write(hdmi, HDMI_MC_CLKDIS, 0x7f); + rk_hdmi_phy_power_off(hdmi); + hdmi->enabled = RT_FALSE; + return RT_EOK; + } + + if (hdmi->enabled) + { + return RT_EOK; + } + + if (!hdmi->prepared) + { + err = rk_hdmi_prepare(priv, 0, &hdmi->mode); + if (err) + { + return err; + } + } + + if (!hdmi->mode.hactive || !hdmi->mode.vactive || !hdmi->mode.pixelclock) + { + return -RT_EINVAL; + } + +#if DBG_LVL >= DBG_LOG + LOG_D("enable clocks: pixel=%u ref=%lu", + (rt_uint32_t)hdmi->mode.pixelclock, rk_hdmi_clk_rate(hdmi, "ref")); +#endif + + rk_hdmi_av_composer(hdmi, &hdmi->mode); + rk_hdmi_config_input_polarity(hdmi, &hdmi->mode); + rk_hdmi_mod(hdmi, HDMI_A_HDCPCFG0, + HDMI_A_HDCPCFG0_HDMIDVI_MASK, + hdmi->sink_is_hdmi ? HDMI_A_HDCPCFG0_HDMIDVI_HDMI : + HDMI_A_HDCPCFG0_HDMIDVI_DVI); + rk_hdmi_mod(hdmi, HDMI_A_HDCPCFG0, + HDMI_A_HDCPCFG0_AVMUTE_MASK, HDMI_A_HDCPCFG0_AVMUTE_DISABLE); + + rk_hdmi_enable_video_path(hdmi); + rk_hdmi_video_packetize(hdmi); + rk_hdmi_video_csc(hdmi); + rk_hdmi_video_sample(hdmi); + + err = rk_hdmi_phy_init(hdmi); + if (err) + { + rk_hdmi_write(hdmi, HDMI_MC_CLKDIS, 0x7f); + return err; + } + + rk_hdmi_clear_overflow(hdmi); + rk_hdmi_stabilize_link(hdmi); + hdmi->enabled = RT_TRUE; + +#if DBG_LVL >= DBG_LOG + rk_hdmi_dump_regs(hdmi, "post-enable"); +#endif + + LOG_D("enabled, mode=%s HPD=%d stat0=0x%02x", + hdmi->sink_is_hdmi ? "hdmi" : "dvi", + !!(rk_hdmi_read(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_HPD), + rk_hdmi_read(hdmi, HDMI_PHY_STAT0)); + + return RT_EOK; +} + +static rt_err_t rk_hdmi_disable(void *priv) +{ + struct rk_hdmi *hdmi = priv; + + if (!hdmi) + { + return -RT_EINVAL; + } + + rk_hdmi_enable(priv, RT_FALSE); + rk_hdmi_clks_disable(hdmi); + hdmi->prepared = RT_FALSE; + + return RT_EOK; +} + +static const struct rockchip_connector_ops rk_hdmi_connector_ops = +{ + .detect = rk_hdmi_detect, + .prepare = rk_hdmi_prepare, + .mode_set = rk_hdmi_mode_set, + .enable = rk_hdmi_enable, + .disable = rk_hdmi_disable, +}; + +static rt_err_t rk_hdmi_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + struct rt_device *dev = &pdev->parent; + struct rt_ofw_node *np = dev->ofw_node; + struct rk_hdmi *hdmi = rt_calloc(1, sizeof(*hdmi)); + + if (!hdmi) + { + return -RT_ENOMEM; + } + + hdmi->regs = rt_ofw_iomap(np, 0); + if (!hdmi->regs) + { + rt_free(hdmi); + return -RT_EIO; + } + + hdmi->clks = rt_clk_get_array(dev); + if (rt_is_err(hdmi->clks)) + { + rt_iounmap(hdmi->regs); + rt_free(hdmi); + return rt_ptr_err(hdmi->clks); + } + + hdmi->reg_io_width = 4; + rt_dm_dev_prop_read_u32(dev, "reg-io-width", &hdmi->reg_io_width); + hdmi->sink_is_hdmi = RT_TRUE; + hdmi->grf = rt_syscon_find_by_ofw_phandle(np, "rockchip,grf"); + + err = rockchip_display_register_connector(np, &rk_hdmi_connector_ops, hdmi); + if (err) + { + rt_clk_array_put(hdmi->clks); + rt_iounmap(hdmi->regs); + rt_free(hdmi); + return err; + } + + pdev->parent.user_data = hdmi; + rt_dm_dev_bind_fwdata(dev, RT_NULL, hdmi); + + LOG_D("HDMI %s: reg-io-width=%u", rt_ofw_node_full_name(np), hdmi->reg_io_width); + + return RT_EOK; +} + +static const struct rt_ofw_node_id rk_hdmi_ids[] = +{ + { .compatible = "rockchip,rk3568-dw-hdmi" }, + { .compatible = "rockchip,rk3528-dw-hdmi" }, + { .compatible = "rockchip,rk3399-dw-hdmi" }, + { .compatible = "rockchip,rk3288-dw-hdmi" }, + { .compatible = "rockchip,rk3328-dw-hdmi" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver rk_hdmi_driver = +{ + .name = "dw-hdmi-rockchip", + .ids = rk_hdmi_ids, + .probe = rk_hdmi_probe, +}; +RT_PLATFORM_DRIVER_EXPORT(rk_hdmi_driver); diff --git a/bsp/rockchip/dm/graphic/framebuffer/panel-simple.c b/bsp/rockchip/dm/graphic/framebuffer/panel-simple.c new file mode 100644 index 000000000000..dac20887dcc9 --- /dev/null +++ b/bsp/rockchip/dm/graphic/framebuffer/panel-simple.c @@ -0,0 +1,428 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-09-23 GuEe-GUI first version + */ + +#include "rockchip-display.h" + +#define DBG_TAG "panel.simple" +#define DBG_LVL DBG_INFO +#include + +rt_packed(struct panel_cmd_header +{ + rt_uint8_t data_type; + rt_uint8_t delay; + rt_uint8_t payload_length; +}); + +struct panel_cmd_desc +{ + struct panel_cmd_header header; + rt_uint8_t *payload; +}; + +struct panel_cmd_seq +{ + struct panel_cmd_desc *cmds; + rt_uint8_t *blob; + rt_uint32_t cmd_cnt; +}; + +struct panel_simple +{ + struct rt_device parent; + struct display_timing timing; + rt_base_t reset_pin; + rt_uint8_t reset_active; + rt_base_t enable_pin; + rt_uint8_t enable_active; + rt_uint32_t reset_delay_ms; + rt_uint32_t prepare_delay_ms; + rt_uint32_t enable_delay_ms; + rt_uint32_t init_delay_ms; + struct panel_cmd_seq init_seq; + struct rt_regulator *supply; + rt_bool_t prepared; + rt_bool_t enabled; +#ifdef RT_GRAPHIC_BACKLIGHT + struct rt_backlight_device *backlight; + rt_uint32_t brightness; +#endif +}; + +static rt_err_t panel_simple_get_timing(void *priv, struct display_timing *tim) +{ + struct panel_simple *panel = priv; + + if (!panel || !tim) + { + return -RT_EINVAL; + } + + *tim = panel->timing; + + return RT_EOK; +} + +static void panel_simple_pulse_reset(struct panel_simple *panel) +{ + if (panel->reset_pin < 0) + { + return; + } + + rt_pin_mode(panel->reset_pin, PIN_MODE_OUTPUT); + rt_pin_write(panel->reset_pin, panel->reset_active); + rt_thread_mdelay(panel->reset_delay_ms); + rt_pin_write(panel->reset_pin, !panel->reset_active); + rt_thread_mdelay(panel->reset_delay_ms); +} + +static rt_err_t panel_simple_parse_cmd_seq(struct rt_ofw_node *np, const char *prop, + struct panel_cmd_seq *seq) +{ + const rt_uint8_t *data; + rt_ssize_t len; + const rt_uint8_t *d; + rt_size_t remain, i, cnt; + struct panel_cmd_header *header; + + if (!np || !prop || !seq) + { + return -RT_EINVAL; + } + + data = rt_ofw_prop_read_raw(np, prop, &len); + + if (!data || len <= 0) + { + return -RT_ENOENT; + } + + seq->blob = rt_malloc(len); + + if (!seq->blob) + { + return -RT_ENOMEM; + } + + rt_memcpy(seq->blob, data, len); + d = seq->blob; + remain = len; + cnt = 0; + + while (remain) + { + if (remain < sizeof(*header)) + { + rt_free(seq->blob); + seq->blob = RT_NULL; + return -RT_EINVAL; + } + + header = (struct panel_cmd_header *)d; + d += sizeof(*header); + remain -= sizeof(*header); + + if (header->payload_length > remain) + { + rt_free(seq->blob); + seq->blob = RT_NULL; + return -RT_EINVAL; + } + + d += header->payload_length; + remain -= header->payload_length; + ++cnt; + } + + seq->cmds = rt_calloc(cnt, sizeof(*seq->cmds)); + + if (!seq->cmds) + { + rt_free(seq->blob); + seq->blob = RT_NULL; + return -RT_ENOMEM; + } + + seq->cmd_cnt = cnt; + d = seq->blob; + remain = len; + + for (i = 0; i < cnt; ++i) + { + header = (struct panel_cmd_header *)d; + d += sizeof(*header); + remain -= sizeof(*header); + seq->cmds[i].header = *header; + seq->cmds[i].payload = (rt_uint8_t *)d; + d += header->payload_length; + remain -= header->payload_length; + } + + return RT_EOK; +} + +static rt_err_t panel_simple_run_init(void *priv, + const struct rockchip_connector_ops *conn_ops, void *conn_priv) +{ + struct panel_simple *panel = priv; + rt_uint32_t i; + rt_err_t err = RT_EOK; + + if (!panel || !conn_ops || !conn_ops->transfer || !panel->init_seq.cmd_cnt) + { + return RT_EOK; + } + + if (panel->init_delay_ms) + { + rt_thread_mdelay(panel->init_delay_ms); + } + + for (i = 0; i < panel->init_seq.cmd_cnt; ++i) + { + struct panel_cmd_desc *cmd = &panel->init_seq.cmds[i]; + + err = conn_ops->transfer(conn_priv, cmd->header.data_type, cmd->header.delay, + cmd->payload, cmd->header.payload_length); + + if (err) + { + LOG_W("panel init cmd %u failed: %d", i, err); + break; + } + } + + if (!err) + { + LOG_D("sent %u panel init command(s)", panel->init_seq.cmd_cnt); + } + + return err; +} + +static rt_err_t panel_simple_prepare(void *priv) +{ + struct panel_simple *panel = priv; + rt_err_t err; + + if (!panel || panel->prepared) + { + return RT_EOK; + } + + if (panel->supply) + { + err = rt_regulator_enable(panel->supply); + + if (err) + { + LOG_W("panel power enable failed: %d", err); + return err; + } + } + + if (panel->prepare_delay_ms) + { + rt_thread_mdelay(panel->prepare_delay_ms); + } + + panel_simple_pulse_reset(panel); + panel->prepared = RT_TRUE; + + return RT_EOK; +} + +static rt_err_t panel_simple_enable(void *priv) +{ + struct panel_simple *panel = priv; + + if (!panel) + { + return -RT_EINVAL; + } + + if (panel->enable_pin >= 0) + { + rt_pin_mode(panel->enable_pin, PIN_MODE_OUTPUT); + rt_pin_write(panel->enable_pin, panel->enable_active); + } + + if (panel->enable_delay_ms) + { + rt_thread_mdelay(panel->enable_delay_ms); + } + +#ifdef RT_GRAPHIC_BACKLIGHT + if (panel->backlight) + { + rt_backlight_set_power(panel->backlight, RT_BACKLIGHT_POWER_NORMAL); + rt_backlight_set_brightness(panel->backlight, panel->brightness); + } +#endif + + panel->enabled = RT_TRUE; + + return RT_EOK; +} + +static rt_err_t panel_simple_disable(void *priv) +{ + struct panel_simple *panel = priv; + + if (!panel) + { + return -RT_EINVAL; + } + +#ifdef RT_GRAPHIC_BACKLIGHT + if (panel->backlight) + { + rt_backlight_set_power(panel->backlight, RT_BACKLIGHT_POWER_POWERDOWN); + } +#endif + + if (panel->enable_pin >= 0) + { + rt_pin_write(panel->enable_pin, !panel->enable_active); + } + + if (panel->supply) + { + rt_regulator_disable(panel->supply); + } + + panel->enabled = RT_FALSE; + panel->prepared = RT_FALSE; + + return RT_EOK; +} + +static const struct rockchip_panel_ops panel_simple_ops = +{ + .get_timing = panel_simple_get_timing, + .prepare = panel_simple_prepare, + .run_init = panel_simple_run_init, + .enable = panel_simple_enable, + .disable = panel_simple_disable, +}; + +static rt_err_t panel_simple_probe(struct rt_platform_device *pdev) +{ + struct rt_device *dev = &pdev->parent; + struct rt_ofw_node *np = dev->ofw_node; + struct panel_simple *panel = rt_calloc(1, sizeof(*panel)); + rt_err_t err; + + if (!panel) + { + return -RT_ENOMEM; + } + + panel->reset_pin = -1; + panel->enable_pin = -1; + panel->reset_delay_ms = 20; + panel->prepare_delay_ms = 0; + panel->enable_delay_ms = 0; +#ifdef RT_GRAPHIC_BACKLIGHT + panel->brightness = 255; +#endif + + if ((err = display_timing_parse(np, &panel->timing))) + { + LOG_W("%s: no timing, use 1920x1080", np->name); + panel->timing.hactive = 1920; + panel->timing.vactive = 1080; + panel->timing.hfront_porch = 40; + panel->timing.hback_porch = 40; + panel->timing.hsync_len = 10; + panel->timing.vfront_porch = 20; + panel->timing.vback_porch = 20; + panel->timing.vsync_len = 4; + display_timing_derive(&panel->timing); + } + + rt_dm_dev_prop_read_u32(dev, "reset-delay-ms", &panel->reset_delay_ms); + rt_dm_dev_prop_read_u32(dev, "prepare-delay-ms", &panel->prepare_delay_ms); + rt_dm_dev_prop_read_u32(dev, "enable-delay-ms", &panel->enable_delay_ms); + rt_dm_dev_prop_read_u32(dev, "init-delay-ms", &panel->init_delay_ms); + + err = panel_simple_parse_cmd_seq(np, "panel-init-sequence", &panel->init_seq); + if (err && err != -RT_ENOENT) + { + LOG_E("%s: invalid panel-init-sequence: %s", + rt_ofw_node_full_name(np), rt_strerror(err)); + rt_free(panel); + return err; + } + + panel->reset_pin = rt_pin_get_named_pin(dev, "reset", 0, RT_NULL, &panel->reset_active); + if (panel->reset_pin < 0 && panel->reset_pin != PIN_NONE) + { + panel->reset_pin = -1; + } + + panel->enable_pin = rt_pin_get_named_pin(dev, "enable", 0, RT_NULL, &panel->enable_active); + if (panel->enable_pin < 0 && panel->enable_pin != PIN_NONE) + { + panel->enable_pin = -1; + } + + panel->supply = rt_regulator_get(dev, "power"); + if (rt_is_err(panel->supply)) + { + panel->supply = RT_NULL; + } + +#ifdef RT_GRAPHIC_BACKLIGHT + { + struct rt_ofw_node *bl_np = rt_ofw_parse_phandle(np, "backlight", 0); + + if (bl_np) + { + panel->backlight = rt_ofw_data(bl_np); + + if (panel->backlight) + { + rt_device_open(&panel->backlight->parent, RT_DEVICE_OFLAG_RDWR); + panel->brightness = panel->backlight->props.max_brightness ? + panel->backlight->props.max_brightness : 255; + } + + rt_ofw_node_put(bl_np); + } + } +#endif /* RT_GRAPHIC_BACKLIGHT */ + + rockchip_display_register_panel(np, &panel_simple_ops, panel); + + pdev->parent.user_data = panel; + + LOG_D("panel %s: %ux%u, init-cmds=%u", rt_ofw_node_full_name(np), + panel->timing.hactive, panel->timing.vactive, panel->init_seq.cmd_cnt); + + return RT_EOK; +} + +static const struct rt_ofw_node_id panel_simple_ids[] = +{ + { .compatible = "simple-panel" }, + { .compatible = "simple-panel-dsi" }, + { .compatible = "rockchip,panel-simple" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver panel_simple_driver = +{ + .name = "panel-simple", + .ids = panel_simple_ids, + .probe = panel_simple_probe, +}; +RT_PLATFORM_DRIVER_EXPORT(panel_simple_driver); diff --git a/bsp/rockchip/dm/graphic/framebuffer/rockchip-display.h b/bsp/rockchip/dm/graphic/framebuffer/rockchip-display.h new file mode 100644 index 000000000000..c78728dfd006 --- /dev/null +++ b/bsp/rockchip/dm/graphic/framebuffer/rockchip-display.h @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-09-23 GuEe-GUI first version + */ + +#ifndef __ROCKCHIP_DISPLAY_H__ +#define __ROCKCHIP_DISPLAY_H__ + +#include +#include +#include + +#include + +#define DISPLAY_TIMING_F_PHSYNC RT_BIT(0) +#define DISPLAY_TIMING_F_PVSYNC RT_BIT(1) +#define DISPLAY_TIMING_F_PIXDATA_NEGEDGE RT_BIT(2) + +struct 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_uint64_t pixelclock; + rt_uint32_t flags; + rt_uint32_t htotal; + rt_uint32_t vtotal; +}; + +struct display_route +{ + struct rt_ofw_node *route_np; + struct rt_ofw_node *vop_np; + struct rt_ofw_node *vp_port_np; + struct rt_ofw_node *connector_np; + struct rt_ofw_node *panel_np; + rt_uint32_t vp_id; +}; + +struct rockchip_crtc_ops +{ + rt_err_t (*mode_set)(void *priv, const struct display_route *route, + const struct display_timing *tim); + rt_err_t (*enable)(void *priv, rt_uint32_t vp_id, rt_bool_t enable); + rt_err_t (*complete)(void *priv, rt_uint32_t vp_id); +}; + +struct rockchip_connector_ops +{ + rt_err_t (*detect)(void *priv, rt_bool_t *connected); + rt_err_t (*prepare)(void *priv, rt_uint32_t vp_id, const struct display_timing *tim); + rt_err_t (*mode_set)(void *priv, const struct display_timing *tim); + rt_err_t (*transfer)(void *priv, rt_uint8_t data_type, rt_uint8_t delay_ms, + const rt_uint8_t *payload, rt_size_t len); + rt_err_t (*enable)(void *priv, rt_bool_t enable); + rt_err_t (*disable)(void *priv); +}; + +struct rockchip_panel_ops +{ + rt_err_t (*get_timing)(void *priv, struct display_timing *tim); + rt_err_t (*prepare)(void *priv); + rt_err_t (*run_init)(void *priv, const struct rockchip_connector_ops *conn_ops, void *conn_priv); + rt_err_t (*enable)(void *priv); + rt_err_t (*disable)(void *priv); +}; + +rt_err_t display_timing_parse(struct rt_ofw_node *np, struct display_timing *tim); +void display_timing_derive(struct display_timing *tim); + +rt_err_t display_route_resolve(struct rt_ofw_node *route_np, struct display_route *route); +rt_err_t display_route_get_vp_id(struct rt_ofw_node *vp_port_np, rt_uint32_t *vp_id); + +rt_err_t rockchip_display_register_crtc(struct rt_ofw_node *np, + const struct rockchip_crtc_ops *ops, void *priv); +rt_err_t rockchip_display_register_connector(struct rt_ofw_node *np, + const struct rockchip_connector_ops *ops, void *priv); +rt_err_t rockchip_display_register_panel(struct rt_ofw_node *np, + const struct rockchip_panel_ops *ops, void *priv); + +rt_err_t rockchip_display_route_enable(struct rt_ofw_node *route_np); + +#endif /* __ROCKCHIP_DISPLAY_H__ */ diff --git a/bsp/rockchip/dm/graphic/logo/Kconfig b/bsp/rockchip/dm/graphic/logo/Kconfig new file mode 100755 index 000000000000..9b67c60e6f6d --- /dev/null +++ b/bsp/rockchip/dm/graphic/logo/Kconfig @@ -0,0 +1,5 @@ +config RT_GRAPHIC_LOGO_RADXA_CLUT224 + bool "Standard 224-color Radxa logo" + +config RT_GRAPHIC_LOGO_ROCKCHIP_CLUT224 + bool "Standard 224-color Rockchip logo" diff --git a/bsp/rockchip/dm/graphic/logo/Kconfig.path b/bsp/rockchip/dm/graphic/logo/Kconfig.path new file mode 100755 index 000000000000..96a474512923 --- /dev/null +++ b/bsp/rockchip/dm/graphic/logo/Kconfig.path @@ -0,0 +1,10 @@ +if RT_GRAPHIC_LOGO_RADXA_CLUT224 + config RT_GRAPHIC_LOGO_RADXA_CLUT224_PATH + string + default "../dm/graphic/logo/logo-radxa-clut224.ppm" +endif +if RT_GRAPHIC_LOGO_ROCKCHIP_CLUT224 + config RT_GRAPHIC_LOGO_ROCKCHIP_CLUT224_PATH + string + default "../dm/graphic/logo/logo-rockchip-clut224.ppm" +endif diff --git a/bsp/rockchip/dm/graphic/logo/logo-radxa-clut224.ppm b/bsp/rockchip/dm/graphic/logo/logo-radxa-clut224.ppm new file mode 100755 index 000000000000..a8c1426afa9a --- /dev/null +++ b/bsp/rockchip/dm/graphic/logo/logo-radxa-clut224.ppm @@ -0,0 +1,5139 @@ +P3 +379 107 +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 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 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 49 49 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 +66 66 66 51 51 51 28 28 28 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 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 186 186 186 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 251 251 251 207 207 207 149 149 149 69 69 69 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 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 186 186 186 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 218 218 218 +91 91 91 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 186 186 186 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 170 170 170 9 9 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 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 186 186 186 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 179 179 179 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 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 186 186 186 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 111 111 111 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 186 186 186 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 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 12 12 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 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 186 186 186 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 86 86 86 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 186 186 186 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 160 160 160 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 186 186 186 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 221 221 221 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 186 186 186 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 251 251 251 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 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 186 186 186 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 31 31 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 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 186 186 186 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 186 186 186 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 186 186 186 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 186 186 186 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 186 186 186 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 186 186 186 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 186 186 186 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 186 186 186 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 186 186 186 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 186 186 186 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 186 186 186 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 186 186 186 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 186 186 186 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 186 186 186 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 186 186 186 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 186 186 186 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 186 186 186 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 186 186 186 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 186 186 186 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 186 186 186 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 186 186 186 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 186 186 186 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 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 48 48 48 80 80 80 91 91 91 102 102 102 +102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 99 99 99 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 85 85 85 85 85 85 85 85 85 +80 80 80 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 64 64 64 31 31 31 +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 26 26 26 53 53 53 +71 71 71 91 91 91 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 +102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 +102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 +102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 +102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 100 100 100 83 83 83 +68 68 68 44 44 44 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 +2 2 2 31 31 31 48 48 48 62 62 62 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 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 23 23 23 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 186 186 186 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 18 28 6 +32 50 11 32 50 11 32 50 11 32 50 11 32 50 11 32 50 11 32 50 11 32 50 11 +32 50 11 32 50 11 32 50 11 32 50 11 32 50 11 32 50 11 32 50 11 32 50 11 +32 50 11 32 50 11 32 50 11 32 50 11 32 50 11 32 50 11 32 50 11 32 50 11 +32 50 11 32 50 11 32 50 11 32 50 11 32 50 11 32 50 11 32 50 11 32 50 11 +32 50 11 32 50 11 32 50 11 32 50 11 32 50 11 32 50 11 32 50 11 32 50 11 +32 50 11 32 50 11 32 50 11 32 50 11 32 50 11 32 50 11 32 50 11 32 50 11 +32 50 11 32 50 11 32 50 11 32 50 11 32 50 11 32 50 11 32 50 11 32 50 11 +32 50 11 32 50 11 32 50 11 32 50 11 32 50 11 27 42 9 4 6 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 1 1 1 40 40 40 68 68 68 +91 91 91 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 +102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 +102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 +102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 +102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 97 97 97 76 76 76 53 53 53 +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 +18 18 18 116 116 116 198 198 198 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 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +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 197 197 197 113 113 113 14 14 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 61 61 61 157 157 157 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 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 244 244 244 191 191 191 107 107 107 12 12 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 40 40 40 128 128 128 193 193 193 +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 255 255 255 255 255 255 86 86 86 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 186 186 186 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 16 25 5 93 145 31 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 113 176 37 48 76 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 48 48 48 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 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +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 179 179 179 86 86 86 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 5 5 5 126 126 126 +243 243 243 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 235 235 235 85 85 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 40 40 40 191 191 191 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 111 111 111 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 59 59 59 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 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 86 86 86 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 186 186 186 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 9 13 3 105 165 35 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 116 181 38 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 119 185 39 113 176 37 117 183 39 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +44 69 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 25 25 25 163 163 163 253 253 253 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 204 204 204 62 62 62 0 0 0 0 0 0 0 0 0 +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 184 184 184 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 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 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 +61 61 61 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 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 +9 9 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 11 11 11 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 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 83 83 83 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 186 186 186 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 59 92 19 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 120 188 40 64 100 21 +13 21 4 0 0 0 15 23 5 74 116 25 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 100 156 33 53 83 17 +19 30 6 1 2 0 0 0 0 1 1 0 20 32 7 64 100 21 114 178 38 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +110 171 36 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 +49 49 49 223 223 223 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 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 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 5 5 5 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 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 85 85 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 56 56 56 +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 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +163 163 163 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +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 211 211 211 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 83 83 83 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 186 186 186 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 88 138 29 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 117 183 39 37 58 12 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 53 83 17 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 112 175 37 44 69 15 0 1 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 15 23 5 93 145 31 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 20 32 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 68 68 68 +247 247 247 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 140 140 140 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 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 12 12 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 9 9 9 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 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 97 97 97 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 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 18 18 +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 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 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 186 186 186 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 94 147 31 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 115 179 38 31 48 10 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 74 116 25 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 105 165 35 16 25 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 3 4 1 +79 123 26 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 27 42 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 40 40 40 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 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 107 107 107 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 38 38 38 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 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 107 107 107 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 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 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 218 218 218 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 2 2 2 181 181 181 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 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 186 186 186 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 94 147 31 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 113 176 37 27 42 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 7 11 2 108 169 36 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 119 185 39 27 42 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 +1 1 0 74 116 25 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 27 42 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 5 5 5 218 218 218 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 251 251 251 +48 48 48 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 140 140 140 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 1 1 1 218 218 218 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 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 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 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 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 186 186 186 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 94 147 31 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 112 174 37 20 32 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 39 61 13 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 53 83 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 1 1 0 71 111 23 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 27 42 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 111 111 111 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +191 191 191 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 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 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 253 253 253 +12 12 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 56 56 56 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 151 151 151 0 0 0 0 0 0 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 232 232 232 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 76 76 76 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 186 186 186 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 94 147 31 121 189 40 121 189 40 121 189 40 +121 189 40 113 177 37 23 36 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 84 130 28 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 84 130 28 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 1 0 74 116 25 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 27 42 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 4 4 4 233 233 233 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 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 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 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +56 56 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 109 109 109 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 211 211 211 0 0 0 0 0 0 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 95 95 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 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 186 186 186 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 94 147 31 121 189 40 121 189 40 121 189 40 +115 180 38 27 42 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 13 21 4 +114 178 38 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +105 165 35 9 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 1 2 0 84 130 28 121 189 40 121 189 40 121 189 40 +121 189 40 27 42 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 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 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 140 140 140 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 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +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 160 160 160 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 253 253 253 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 200 200 200 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 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 186 186 186 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 94 147 31 121 189 40 121 189 40 120 188 40 +37 58 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 +50 78 16 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 119 186 39 +28 44 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 3 4 1 88 138 29 121 189 40 121 189 40 +121 189 40 27 42 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 136 136 136 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 218 218 218 0 0 0 +0 0 0 0 0 0 101 101 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 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +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 0 0 0 0 0 0 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 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 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 36 36 36 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 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 186 186 186 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 94 147 31 121 189 40 121 189 40 65 103 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 +1 1 0 94 147 31 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 55 87 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 7 11 2 103 161 34 121 189 40 +121 189 40 27 42 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 173 173 173 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 253 253 253 4 4 4 +0 0 0 0 0 0 113 113 113 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +136 136 136 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 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 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 38 38 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 100 100 100 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 69 69 69 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 186 186 186 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 94 147 31 121 189 40 112 175 37 5 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 20 32 7 119 185 39 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 84 132 28 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 27 42 9 121 189 40 +121 189 40 27 42 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 197 197 197 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 25 25 25 +0 0 0 0 0 0 116 116 116 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +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 204 204 204 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 49 49 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 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 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 66 66 66 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 186 186 186 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 94 147 31 121 189 40 71 111 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 62 97 20 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 108 168 36 9 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 0 0 0 108 169 36 +121 189 40 27 42 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 211 211 211 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 43 43 43 +0 0 0 0 0 0 116 116 116 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 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 +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 +100 100 100 0 0 0 0 0 0 0 0 0 0 0 0 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 136 136 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 +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 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 +235 235 235 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +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 193 193 193 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 64 64 64 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 186 186 186 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 94 147 31 121 189 40 44 69 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 4 6 1 103 161 34 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 119 186 39 28 44 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 100 156 33 +121 189 40 27 42 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 140 140 140 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 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 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 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 44 44 44 +0 0 0 0 0 0 116 116 116 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 130 130 130 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 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 255 255 255 255 255 255 +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 218 218 218 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 244 244 244 +207 207 207 179 179 179 157 157 157 147 147 147 136 136 136 136 136 136 147 147 147 154 154 154 +166 166 166 170 170 170 186 186 186 193 193 193 223 223 223 251 251 251 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 64 64 64 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 186 186 186 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 94 147 31 121 189 40 34 54 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 29 46 10 121 188 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 57 90 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 11 17 4 118 185 39 +121 189 40 27 42 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 202 202 202 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 44 44 44 +0 0 0 0 0 0 116 116 116 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 130 130 130 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 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 255 255 255 255 255 255 +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 233 233 233 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 251 251 251 179 179 179 102 102 102 38 38 38 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 4 4 4 46 46 46 107 107 107 +186 186 186 252 252 252 255 255 255 255 255 255 62 62 62 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 186 186 186 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 94 147 31 121 189 40 37 58 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 74 115 24 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 86 135 29 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 76 118 25 121 189 40 +121 189 40 27 42 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 202 202 202 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 44 44 44 +0 0 0 0 0 0 116 116 116 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 130 130 130 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 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 255 255 255 255 255 255 +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 233 233 233 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 253 253 253 147 147 147 25 25 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 40 40 40 183 183 183 255 255 255 61 61 61 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 186 186 186 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 94 147 31 121 189 40 53 83 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 9 13 3 110 172 36 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 109 170 36 9 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 0 0 0 0 1 0 64 100 21 121 189 40 121 189 40 +121 189 40 27 42 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 202 202 202 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 44 44 44 +0 0 0 0 0 0 116 116 116 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 130 130 130 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 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 255 255 255 255 255 255 +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 233 233 233 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +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 69 69 69 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 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 133 133 133 59 59 59 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 186 186 186 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 94 147 31 121 189 40 84 130 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 42 65 13 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 120 187 40 29 46 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 13 21 4 86 135 29 121 189 40 121 189 40 121 189 40 +121 189 40 27 42 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 202 202 202 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 44 44 44 +0 0 0 0 0 0 116 116 116 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 130 130 130 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 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 255 255 255 255 255 255 +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 233 233 233 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 +49 49 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 8 8 8 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 186 186 186 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 94 147 31 121 189 40 118 184 39 9 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 84 132 28 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 59 92 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 1 0 48 76 16 114 178 38 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 27 42 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 202 202 202 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 44 44 44 +0 0 0 0 0 0 116 116 116 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 130 130 130 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 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 255 255 255 255 255 255 +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 233 233 233 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 186 186 186 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 94 147 31 121 189 40 121 189 40 64 100 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 15 23 5 115 180 38 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +88 138 29 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 +19 30 6 93 145 31 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 27 42 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 202 202 202 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 44 44 44 +0 0 0 0 0 0 116 116 116 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 130 130 130 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 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 255 255 255 255 255 255 +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 233 233 233 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 23 23 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 186 186 186 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 94 147 31 121 189 40 121 189 40 118 184 39 +23 36 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 53 83 17 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 110 172 36 +11 17 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 2 4 1 57 90 19 +117 183 39 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 27 42 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 202 202 202 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 44 44 44 +0 0 0 0 0 0 116 116 116 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 130 130 130 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 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 255 255 255 255 255 255 +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 233 233 233 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 186 186 186 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 94 147 31 121 189 40 121 189 40 121 189 40 +107 167 35 19 30 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 1 2 0 +95 149 32 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 120 188 40 32 50 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 25 39 8 98 153 32 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 27 42 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 202 202 202 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 44 44 44 +0 0 0 0 0 0 116 116 116 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 130 130 130 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 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 255 255 255 255 255 255 +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 233 233 233 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 186 186 186 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 94 147 31 121 189 40 121 189 40 121 189 40 +121 189 40 115 180 38 42 65 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 +23 36 8 119 186 39 121 189 40 121 189 40 121 189 40 121 189 40 108 169 36 5 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 5 7 2 65 103 21 120 187 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 27 42 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 202 202 202 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 44 44 44 +0 0 0 0 0 0 116 116 116 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 130 130 130 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +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 52 52 52 80 80 80 93 93 93 102 102 102 102 102 102 102 102 102 102 102 102 +102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 +102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 +102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 +102 102 102 102 102 102 18 18 18 0 0 0 0 0 0 0 0 0 0 0 0 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 255 255 255 255 255 255 +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 233 233 233 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 186 186 186 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 94 147 31 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 76 118 25 5 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 65 103 21 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 65 103 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 29 46 10 103 161 34 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 27 42 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 +25 25 25 64 64 64 97 97 97 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 +102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 +102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 +102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 +102 102 102 18 18 18 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 202 202 202 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 44 44 44 +0 0 0 0 0 0 116 116 116 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 130 130 130 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 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 25 25 116 116 116 202 202 202 +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 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 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 +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 255 255 255 255 255 255 +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 233 233 233 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 186 186 186 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 94 147 31 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 98 153 32 18 28 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 4 6 1 105 164 35 121 189 40 121 189 40 121 189 40 121 189 40 120 187 40 +25 39 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 +7 11 2 74 115 24 121 188 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 27 42 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 5 5 5 83 83 83 168 168 168 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 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 202 202 202 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 44 44 44 +0 0 0 0 0 0 116 116 116 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 130 130 130 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 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 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 +255 255 255 255 255 255 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 +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 255 255 255 255 255 255 +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 233 233 233 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 186 186 186 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 94 147 31 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 114 178 38 42 65 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 31 48 10 121 188 40 121 189 40 121 189 40 121 189 40 121 189 40 +100 156 33 2 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 37 58 12 +108 168 36 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 27 42 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 5 5 5 104 104 104 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 42 42 42 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 202 202 202 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 44 44 44 +0 0 0 0 0 0 116 116 116 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 130 130 130 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 43 43 43 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 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 +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 255 255 255 255 255 255 +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 233 233 233 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 243 243 243 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 186 186 186 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 94 147 31 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 74 115 24 +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 76 118 25 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 57 90 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 11 17 4 82 128 27 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 27 42 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 36 36 36 207 207 207 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 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 202 202 202 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 44 44 44 +0 0 0 0 0 0 116 116 116 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 130 130 130 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 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 44 44 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 255 255 255 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 +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 255 255 255 255 255 255 +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 233 233 233 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 244 244 244 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 186 186 186 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 94 147 31 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +97 151 32 16 25 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 9 14 3 112 174 37 121 189 40 121 189 40 121 189 40 +121 189 40 118 184 39 20 32 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 39 61 13 112 175 37 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 27 42 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 +59 59 59 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 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 202 202 202 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 44 44 44 +0 0 0 0 0 0 116 116 116 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 130 130 130 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +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 18 18 221 221 221 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 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 +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 255 255 255 255 255 255 +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 233 233 233 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 245 245 245 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 186 186 186 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 94 147 31 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 112 175 37 37 58 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 31 48 10 108 168 36 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 93 145 31 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 16 25 5 91 142 30 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 27 42 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 36 36 36 +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 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 202 202 202 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 44 44 44 +0 0 0 0 0 0 116 116 116 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 130 130 130 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +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 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 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 +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 255 255 255 255 255 255 +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 233 233 233 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 186 186 186 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 94 147 31 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 188 40 69 108 23 2 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 7 11 2 69 108 23 120 188 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 50 78 16 0 0 0 0 0 0 0 0 0 0 0 0 +1 1 0 48 76 16 115 180 38 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 27 42 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 184 184 184 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 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 202 202 202 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 44 44 44 +0 0 0 0 0 0 116 116 116 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 130 130 130 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 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 +253 253 253 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 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 +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 255 255 255 255 255 255 +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 233 233 233 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 186 186 186 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 94 147 31 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 95 149 32 15 23 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 +34 54 11 107 167 35 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 114 178 38 13 21 4 0 0 0 0 0 0 20 32 7 +95 149 32 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 27 42 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 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 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 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 202 202 202 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 44 44 44 +0 0 0 0 0 0 116 116 116 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 130 130 130 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 145 145 145 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 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 +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 255 255 255 255 255 255 +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 233 233 233 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 250 250 250 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 186 186 186 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 94 147 31 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 112 174 37 34 54 11 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 13 3 74 115 24 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 86 135 29 2 4 1 55 87 18 118 185 39 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 27 42 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 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 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 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 202 202 202 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 44 44 44 +0 0 0 0 0 0 116 116 116 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 130 130 130 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 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 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 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 +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 255 255 255 255 255 255 +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 233 233 233 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 250 250 250 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 186 186 186 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 94 147 31 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 120 188 40 62 97 20 +1 2 0 0 0 0 0 0 0 0 0 0 0 0 0 39 61 13 110 171 36 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 109 170 36 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 27 42 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 11 11 11 248 248 248 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 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 202 202 202 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 44 44 44 +0 0 0 0 0 0 116 116 116 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 130 130 130 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 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 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 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 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 +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 255 255 255 255 255 255 +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 233 233 233 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 251 251 251 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 186 186 186 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 94 147 31 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +91 142 30 12 19 4 0 0 0 9 15 3 76 118 25 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 27 42 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 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 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 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 202 202 202 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 44 44 44 +0 0 0 0 0 0 116 116 116 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 130 130 130 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 118 118 118 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 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 +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 255 255 255 255 255 255 +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 233 233 233 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 253 253 253 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 186 186 186 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 94 147 31 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 109 170 36 57 90 19 112 175 37 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 88 138 29 69 108 23 121 188 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 27 42 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 118 118 118 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 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 202 202 202 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 44 44 44 +0 0 0 0 0 0 116 116 116 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 130 130 130 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 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 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 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 +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 255 255 255 255 255 255 +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 233 233 233 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 186 186 186 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 94 147 31 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +114 178 38 48 76 16 0 1 0 0 0 0 37 58 12 112 175 37 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 27 42 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 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 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 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 202 202 202 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 44 44 44 +0 0 0 0 0 0 116 116 116 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 130 130 130 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 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 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 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 +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 255 255 255 255 255 255 +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 233 233 233 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 186 186 186 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 94 147 31 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 120 187 40 +112 174 37 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 84 132 28 +13 21 4 0 0 0 0 0 0 0 0 0 0 0 0 15 23 5 95 149 32 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 27 42 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 184 184 184 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 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 202 202 202 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 44 44 44 +0 0 0 0 0 0 116 116 116 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 130 130 130 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 186 186 186 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +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 191 191 191 147 147 147 128 128 128 117 117 117 102 102 102 88 88 88 85 85 85 +85 85 85 85 85 85 101 101 101 109 109 109 133 133 133 160 160 160 197 197 197 247 247 247 +255 255 255 255 255 255 48 48 48 0 0 0 0 0 0 0 0 0 0 0 0 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 255 255 255 255 255 255 +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 233 233 233 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 186 186 186 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 94 147 31 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 100 156 33 27 42 9 +23 36 8 119 186 39 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 113 177 37 48 76 16 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 3 1 64 100 21 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 27 42 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 193 193 193 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 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 215 215 215 200 200 200 186 186 186 171 171 171 168 168 168 170 170 170 +170 170 170 186 186 186 194 194 194 221 221 221 247 247 247 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 202 202 202 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 44 44 44 +0 0 0 0 0 0 116 116 116 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 130 130 130 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 186 186 186 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 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 93 93 93 28 28 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 7 7 7 +64 64 64 166 166 166 43 43 43 0 0 0 0 0 0 0 0 0 0 0 0 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 255 255 255 255 255 255 +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 233 233 233 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 186 186 186 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 94 147 31 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 119 185 39 64 100 21 3 4 1 0 0 0 +0 0 0 65 103 21 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 84 132 28 13 21 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 +37 58 12 113 177 37 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 27 42 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 193 193 193 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 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 184 184 184 116 116 116 68 68 68 +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 28 28 28 86 86 86 151 151 151 +241 241 241 42 42 42 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 202 202 202 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 44 44 44 +0 0 0 0 0 0 116 116 116 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 130 130 130 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 186 186 186 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 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 160 160 160 25 25 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 +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 255 255 255 255 255 255 +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 233 233 233 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 186 186 186 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 94 147 31 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 94 147 31 20 32 7 0 0 0 0 0 0 0 0 0 +0 0 0 5 7 2 103 161 34 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 112 174 37 44 69 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 18 28 6 98 153 32 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 27 42 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 193 193 193 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 245 245 245 123 123 123 26 26 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 +12 12 12 10 10 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 202 202 202 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 44 44 44 +0 0 0 0 0 0 116 116 116 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 130 130 130 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 186 186 186 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 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 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 +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 255 255 255 255 255 255 +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 233 233 233 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 186 186 186 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 94 147 31 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 115 180 38 53 83 17 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 32 50 11 121 188 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 79 123 26 9 14 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 6 1 74 115 24 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 27 42 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 193 193 193 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 204 204 204 36 36 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 0 0 0 0 0 0 0 0 0 0 0 0 202 202 202 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 44 44 44 +0 0 0 0 0 0 116 116 116 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 130 130 130 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 186 186 186 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 91 91 91 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 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 255 255 255 255 255 255 +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 233 233 233 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 5 5 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 186 186 186 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 94 147 31 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +86 135 29 15 23 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 74 116 25 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 69 108 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 44 69 15 116 181 38 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 27 42 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 193 193 193 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +223 223 223 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 202 202 202 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 44 44 44 +0 0 0 0 0 0 116 116 116 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 130 130 130 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 186 186 186 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +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 +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 255 255 255 255 255 255 +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 233 233 233 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 5 5 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 186 186 186 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 94 147 31 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 113 177 37 48 76 16 +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 7 11 2 108 169 36 121 189 40 121 189 40 121 189 40 +121 189 40 120 188 40 28 44 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 19 30 6 100 156 33 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 27 42 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 193 193 193 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +107 107 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 202 202 202 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 44 44 44 +0 0 0 0 0 0 116 116 116 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 130 130 130 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 186 186 186 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +171 171 171 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 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 255 255 255 255 255 255 +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 233 233 233 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 186 186 186 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 94 147 31 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 84 132 28 12 19 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 39 61 13 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 100 156 33 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 4 6 1 74 115 24 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 27 42 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 193 193 193 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +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 202 202 202 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 44 44 44 +0 0 0 0 0 0 116 116 116 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 130 130 130 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 186 186 186 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +170 170 170 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 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 255 255 255 255 255 255 +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 233 233 233 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 186 186 186 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 94 147 31 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 109 170 36 39 61 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 82 128 27 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 57 90 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 +44 69 15 116 181 38 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 27 42 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 193 193 193 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +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 202 202 202 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 44 44 44 +0 0 0 0 0 0 116 116 116 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 130 130 130 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 186 186 186 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +170 170 170 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 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 255 255 255 255 255 255 +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 233 233 233 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 186 186 186 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 94 147 31 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 188 40 76 118 25 9 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 11 17 4 113 176 37 121 189 40 +121 189 40 121 189 40 121 189 40 118 184 39 19 30 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 20 32 7 100 156 33 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 27 42 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 193 193 193 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +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 202 202 202 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 44 44 44 +0 0 0 0 0 0 116 116 116 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 130 130 130 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 186 186 186 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +170 170 170 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 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 255 255 255 255 255 255 +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 233 233 233 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 186 186 186 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 94 147 31 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +103 161 34 29 46 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 50 78 16 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 91 142 30 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 7 11 2 82 128 27 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 27 42 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 193 193 193 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +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 202 202 202 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 44 44 44 +0 0 0 0 0 0 116 116 116 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 130 130 130 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 186 186 186 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +171 171 171 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 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 255 255 255 255 255 255 +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 233 233 233 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 14 14 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 191 191 191 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 94 147 31 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 119 186 39 64 100 21 +4 6 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 1 1 0 91 142 30 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 47 73 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 55 87 18 121 189 40 121 189 40 121 189 40 +121 189 40 27 42 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 193 193 193 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +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 202 202 202 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 44 44 44 +0 0 0 0 0 0 116 116 116 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 130 130 130 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 186 186 186 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +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 +207 207 207 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +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 233 233 233 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 221 221 221 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 94 147 31 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 97 151 32 23 36 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 59 92 19 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 113 176 37 11 17 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 71 111 23 121 189 40 121 189 40 +121 189 40 27 42 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 193 193 193 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +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 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 44 44 44 +0 0 0 0 0 0 116 116 116 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 130 130 130 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 186 186 186 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +235 235 235 7 7 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 12 12 12 +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 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 233 233 233 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 126 126 126 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 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 44 44 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 94 147 31 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 117 183 39 55 87 18 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 29 46 10 120 187 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 79 123 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 7 11 2 109 170 36 121 189 40 +121 189 40 27 42 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 193 193 193 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +101 101 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 18 18 18 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 255 255 255 +255 255 255 255 255 255 44 44 44 +0 0 0 0 0 0 116 116 116 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 130 130 130 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 186 186 186 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 107 107 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 128 128 128 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +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 233 233 233 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 +38 38 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 +4 4 4 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 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 94 147 31 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 93 145 31 19 30 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 9 15 3 109 170 36 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 37 58 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 57 90 19 121 189 40 +121 189 40 27 42 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 193 193 193 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +200 200 200 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 136 136 136 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 44 44 44 +0 0 0 0 0 0 116 116 116 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 130 130 130 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 186 186 186 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 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 66 66 66 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 100 100 100 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 +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 233 233 233 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +221 221 221 36 36 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 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 18 18 18 +188 188 188 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 94 147 31 121 189 40 121 189 40 121 189 40 +115 179 38 48 76 16 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 1 1 0 88 138 29 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 107 167 35 +5 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 13 21 4 121 189 40 +121 189 40 27 42 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 193 193 193 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 131 131 131 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 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 104 104 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 255 255 255 255 255 255 +255 255 255 255 255 255 44 44 44 +0 0 0 0 0 0 116 116 116 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 130 130 130 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 186 186 186 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 251 251 251 131 131 131 7 7 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 49 49 49 170 170 170 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +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 233 233 233 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 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 119 119 119 12 12 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 18 18 18 126 126 126 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 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 94 147 31 121 189 40 121 189 40 105 165 35 +18 28 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 57 90 19 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +68 106 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 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 165 35 +121 189 40 27 42 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 193 193 193 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 166 166 166 18 18 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 53 53 53 173 173 173 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 44 44 44 +0 0 0 0 0 0 116 116 116 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 130 130 130 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 186 186 186 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 235 235 235 145 145 145 49 49 49 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 +5 5 5 60 60 60 126 126 126 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 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +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 233 233 233 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 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 157 157 157 77 77 77 16 16 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 3 3 3 52 52 52 117 117 117 183 183 183 245 245 245 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 94 147 31 121 189 40 116 181 38 19 30 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 28 44 9 119 186 39 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +120 187 40 25 39 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 91 142 30 +121 189 40 27 42 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 193 193 193 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 243 243 243 154 154 154 56 56 56 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 5 5 5 +61 61 61 128 128 128 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 44 44 44 +0 0 0 0 0 0 116 116 116 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 130 130 130 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 186 186 186 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 244 244 244 +198 198 198 149 149 149 118 118 118 102 102 102 88 88 88 74 74 74 68 68 68 68 68 68 +77 77 77 85 85 85 95 95 95 102 102 102 119 119 119 151 151 151 184 184 184 215 215 215 +247 247 247 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +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 233 233 233 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 218 218 218 +176 176 176 140 140 140 116 116 116 95 95 95 83 83 83 68 68 68 68 68 68 68 68 68 +71 71 71 85 85 85 91 91 91 102 102 102 109 109 109 126 126 126 157 157 157 188 188 188 +221 221 221 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 255 255 255 255 255 255 255 255 255 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 94 147 31 121 189 40 68 106 22 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +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 15 3 108 168 36 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 98 153 32 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 86 135 29 +121 189 40 27 42 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 193 193 193 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 200 200 200 +151 151 151 118 118 118 102 102 102 88 88 88 74 74 74 68 68 68 68 68 68 77 77 77 +85 85 85 97 97 97 102 102 102 119 119 119 154 154 154 184 184 184 215 215 215 248 248 248 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 44 44 44 +0 0 0 0 0 0 116 116 116 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 130 130 130 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 186 186 186 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +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 227 227 227 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 49 49 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 94 147 31 121 189 40 39 61 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 1 0 +84 132 28 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 55 87 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 95 149 32 +121 189 40 27 42 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 193 193 193 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 44 44 44 +0 0 0 0 0 0 111 111 111 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 130 130 130 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 179 179 179 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 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 211 211 211 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 31 31 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 94 147 31 121 189 40 48 76 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 55 87 18 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 117 183 39 16 25 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 5 7 2 118 184 39 +121 189 40 27 42 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 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 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 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 102 102 102 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 130 130 130 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 166 166 166 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 26 26 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 197 197 197 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 14 14 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 94 147 31 121 189 40 86 135 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 27 42 9 119 185 39 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 88 138 29 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 48 76 16 121 189 40 +121 189 40 27 42 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 160 160 160 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 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 0 0 0 83 83 83 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 130 130 130 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 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 151 151 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 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 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 168 168 168 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 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 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 94 147 31 121 189 40 121 189 40 48 76 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 9 13 3 105 165 35 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 44 69 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 9 14 3 109 170 36 121 189 40 +121 189 40 27 42 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 131 131 131 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 235 235 235 0 0 0 +0 0 0 0 0 0 46 46 46 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 130 130 130 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 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 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 223 223 223 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 116 116 116 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 184 184 184 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 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 147 31 121 189 40 121 189 40 120 187 40 +39 61 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 1 0 84 130 28 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 112 175 37 9 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 1 2 0 84 132 28 121 189 40 121 189 40 +121 189 40 27 42 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 62 62 62 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 166 166 166 0 0 0 +0 0 0 0 0 0 5 5 5 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 255 255 255 130 130 130 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 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 86 86 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 171 171 171 0 0 0 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 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 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 126 126 126 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 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 147 31 121 189 40 121 189 40 121 189 40 +117 183 39 29 46 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 53 83 17 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 79 123 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 1 0 74 115 24 121 189 40 121 189 40 121 189 40 +121 189 40 27 42 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 4 4 4 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 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 89 89 89 0 0 0 +0 0 0 0 0 0 0 0 0 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 130 130 130 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 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 36 36 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 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 5 5 5 227 227 227 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 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 94 147 31 121 189 40 121 189 40 121 189 40 +121 189 40 114 178 38 23 36 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 25 39 8 118 185 39 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 32 50 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 68 106 22 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 27 42 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 128 128 128 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +223 223 223 7 7 7 0 0 0 +0 0 0 0 0 0 0 0 0 91 91 91 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 130 130 130 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 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 223 223 223 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 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 12 12 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 126 126 126 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 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 94 147 31 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 112 174 37 23 36 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 9 13 3 105 164 35 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 105 165 35 5 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 64 100 21 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 27 42 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 12 12 12 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 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +91 91 91 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 5 5 5 221 221 221 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 130 130 130 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 116 116 116 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 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 23 23 23 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 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 253 253 253 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 94 147 31 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 113 177 37 27 42 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 79 123 26 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 65 103 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 1 0 65 103 21 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 27 42 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 76 76 76 +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 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 173 173 173 +2 2 2 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 69 69 69 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 130 130 130 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 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 +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 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +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 7 7 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 91 91 91 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 136 136 136 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 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 145 31 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 114 178 38 29 46 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 1 0 62 97 20 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 119 186 39 +27 42 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 2 0 +74 116 25 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 25 39 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 +117 117 117 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 14 14 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 116 116 116 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 130 130 130 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +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 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 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 221 221 221 +38 38 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 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 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 160 160 160 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 79 123 26 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 118 185 39 50 78 16 0 1 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 13 21 4 +84 130 28 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +108 169 36 16 25 5 0 0 0 0 0 0 0 0 0 0 0 0 4 6 1 82 128 27 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 188 40 11 17 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 118 118 118 253 253 253 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 197 197 197 23 23 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 97 97 97 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 130 130 130 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 83 83 83 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 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 25 25 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 +83 83 83 235 235 235 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 245 245 245 +111 111 111 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 34 54 11 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 93 145 31 +39 61 13 9 14 3 0 0 0 0 0 0 9 13 3 37 58 12 76 118 25 117 183 39 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 112 174 37 47 73 15 5 8 2 2 4 1 31 48 10 97 151 32 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +84 130 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 77 77 77 235 235 235 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 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 154 154 154 7 7 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 21 21 21 +149 149 149 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 130 130 130 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 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 145 145 145 233 233 233 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 207 207 207 95 95 95 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 14 14 14 126 126 126 223 223 223 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 232 232 232 126 126 126 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 69 108 23 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 115 179 38 115 180 38 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 188 40 118 184 39 121 189 40 121 189 40 121 189 40 +121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 121 189 40 107 167 35 +13 21 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 14 14 14 136 136 136 243 243 243 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 191 191 191 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 8 8 8 76 76 76 131 131 131 171 171 171 191 191 191 204 204 204 204 204 204 +204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 104 104 104 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 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 5 5 64 64 64 111 111 111 154 154 154 +179 179 179 188 188 188 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 +204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 +204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 +204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 +204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 +204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 186 186 186 +166 166 166 147 147 147 93 93 93 25 25 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 36 36 36 93 93 93 145 145 145 168 168 168 +184 184 184 202 202 202 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 +204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 +204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 +204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 +204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 +204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 +191 191 191 173 173 173 154 154 154 104 104 104 46 46 46 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 39 61 13 86 135 29 +103 161 34 105 164 35 105 164 35 105 164 35 105 164 35 105 164 35 105 164 35 105 164 35 +105 164 35 105 164 35 105 164 35 105 164 35 105 164 35 105 164 35 105 164 35 105 164 35 +105 164 35 105 164 35 105 164 35 105 164 35 105 164 35 105 164 35 105 164 35 105 164 35 +105 164 35 105 164 35 105 164 35 105 164 35 105 164 35 105 164 35 105 164 35 105 164 35 +105 164 35 105 164 35 105 164 35 105 164 35 105 164 35 105 164 35 105 164 35 105 164 35 +105 164 35 105 164 35 105 164 35 105 164 35 105 164 35 105 164 35 105 164 35 105 164 35 +105 164 35 105 164 35 105 164 35 105 164 35 105 164 35 105 164 35 105 164 35 105 164 35 +105 164 35 105 164 35 105 164 35 105 164 35 105 164 35 97 151 32 64 100 21 9 14 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 8 8 8 74 74 74 140 140 140 +173 173 173 196 196 196 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 +204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 +204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 +204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 +204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 +204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 181 181 181 160 160 160 +104 104 104 28 28 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 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 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/rockchip/dm/graphic/logo/logo-rockchip-clut224.ppm b/bsp/rockchip/dm/graphic/logo/logo-rockchip-clut224.ppm new file mode 100755 index 000000000000..b410e1c98bac --- /dev/null +++ b/bsp/rockchip/dm/graphic/logo/logo-rockchip-clut224.ppm @@ -0,0 +1,2181 @@ +P3 +261 66 +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 10 8 3 19 20 20 45 40 27 45 40 27 36 33 21 +24 18 12 15 14 10 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 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 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 41 41 42 108 107 102 159 161 155 205 199 177 205 199 177 223 208 120 +191 137 46 127 102 34 65 56 29 10 8 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 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 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 74 184 189 184 238 241 232 230 229 205 230 229 205 223 208 120 223 208 120 +224 192 64 224 186 50 203 179 47 127 102 34 24 18 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 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 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 +84 84 74 230 229 205 249 247 238 230 229 205 223 208 120 223 208 120 223 208 120 223 208 120 +224 192 64 224 192 64 224 192 64 224 186 50 127 102 34 15 14 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 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 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 74 73 60 +210 206 194 238 241 232 202 199 165 223 208 120 223 208 120 223 208 120 218 195 86 224 186 50 +224 186 50 224 192 64 224 192 64 224 192 64 224 186 50 127 102 34 5 5 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 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 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 18 12 140 128 111 +202 199 165 223 208 120 223 208 120 223 208 120 223 208 120 224 192 64 224 164 58 224 186 50 +224 192 64 224 192 64 224 192 64 224 192 64 224 192 64 203 179 47 65 56 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 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 45 40 27 218 195 86 +223 208 120 223 208 120 223 208 120 218 195 86 224 164 58 224 164 58 224 164 58 224 192 64 +224 192 64 224 192 64 224 192 64 224 192 64 224 192 64 224 186 50 127 102 34 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 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 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 3 127 102 34 224 164 58 +223 208 120 223 208 120 224 164 58 224 164 58 224 164 58 224 164 58 224 192 64 224 192 64 +224 192 64 224 192 64 224 192 64 224 192 64 224 192 64 224 192 64 191 137 46 36 33 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 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 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 8 3 127 102 34 224 164 58 +224 164 58 224 164 58 224 164 58 224 164 58 224 164 58 224 192 64 224 192 64 224 192 64 +224 192 64 224 192 64 224 192 64 224 192 64 224 192 64 224 192 64 203 179 47 65 56 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 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 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 8 3 191 137 46 224 164 58 +224 164 58 224 164 58 224 164 58 224 164 58 224 192 64 224 192 64 224 192 64 224 192 64 +224 192 64 224 192 64 224 192 64 224 192 64 224 192 64 224 192 64 203 179 47 65 56 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 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 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 8 3 191 137 46 224 164 58 +224 164 58 224 164 58 224 164 58 224 164 58 224 192 64 224 192 64 224 192 64 224 192 64 +224 192 64 224 192 64 224 192 64 224 192 64 224 192 64 226 209 55 203 179 47 65 56 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 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 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 8 3 127 102 34 224 164 58 +224 164 58 224 164 58 224 164 58 224 192 64 224 192 64 224 192 64 224 192 64 224 192 64 +224 192 64 224 192 64 224 192 64 224 192 64 224 192 64 226 209 55 203 179 47 45 40 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 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 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 65 56 29 224 164 58 +224 164 58 224 164 58 224 192 64 224 192 64 224 192 64 224 192 64 224 192 64 224 192 64 +224 192 64 224 192 64 224 192 64 224 192 64 226 209 55 226 209 55 191 137 46 15 14 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 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 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 33 21 191 137 46 +224 164 58 224 164 58 224 192 64 224 192 64 224 192 64 224 192 64 224 192 64 224 192 64 +224 192 64 224 192 64 224 192 64 226 209 55 226 209 55 211 208 52 127 102 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 0 0 0 +0 0 0 0 0 0 0 0 0 24 24 26 107 108 115 119 119 131 119 119 131 119 119 131 +119 119 131 119 119 131 119 119 131 119 119 131 119 119 131 119 119 131 119 119 131 119 119 127 +61 61 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 28 29 33 119 119 122 119 119 131 119 119 131 119 119 131 119 119 131 +119 119 131 119 119 131 119 119 131 119 119 131 119 119 131 119 119 131 107 108 115 42 42 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 4 4 3 127 102 34 +224 164 58 224 192 64 224 192 64 224 192 64 224 192 64 224 192 64 224 192 64 224 192 64 +224 192 64 224 192 64 226 209 55 226 209 55 226 209 55 203 179 47 24 18 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 1 69 69 72 238 239 238 246 246 248 246 246 248 246 246 248 +246 246 248 246 246 248 246 246 248 246 246 248 246 246 248 246 246 248 246 246 248 226 226 227 +85 86 89 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 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 95 97 246 246 245 246 246 248 246 246 248 246 246 248 246 246 248 +246 246 248 246 246 248 246 246 248 246 246 248 246 246 248 246 246 248 208 208 212 52 54 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 24 18 12 +127 102 34 224 186 50 224 192 64 224 192 64 224 192 64 224 192 64 224 192 64 224 192 64 +224 192 64 224 192 64 226 209 55 226 209 55 211 208 52 65 56 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 14 13 15 37 37 44 42 42 47 42 42 47 42 42 47 42 42 47 +42 42 47 42 42 47 42 42 47 42 42 47 42 42 47 42 42 47 42 42 47 42 42 47 +42 42 47 42 42 47 42 42 47 42 42 47 42 42 47 42 42 47 42 42 47 42 42 47 +42 42 47 42 42 47 42 42 47 42 42 47 42 42 47 42 42 47 42 42 47 42 42 47 +19 20 20 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 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 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 119 118 116 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 209 209 208 +52 54 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 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 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 154 156 155 255 255 255 255 255 255 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 190 191 189 8 8 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 +24 18 12 127 102 34 203 179 47 224 192 64 224 192 64 224 192 64 224 192 64 224 192 64 +224 192 64 226 209 55 226 209 55 203 179 47 65 56 29 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 79 79 80 182 182 190 199 199 207 199 199 207 199 199 207 199 199 207 +199 199 207 199 199 207 199 199 207 199 199 207 199 199 207 199 199 207 199 199 207 199 199 207 +199 199 207 199 199 207 199 199 207 199 199 207 199 199 207 199 199 207 199 199 207 199 199 207 +199 199 207 199 199 207 199 199 207 199 199 207 199 199 207 199 199 207 199 199 207 197 197 199 +162 163 162 137 136 139 94 95 97 46 47 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 8 8 9 178 178 177 255 255 255 255 255 255 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 183 183 184 +17 17 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 1 1 1 212 214 214 255 255 255 255 255 255 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 137 136 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 24 18 12 127 102 34 191 137 46 224 186 50 226 209 55 224 186 50 226 209 55 +226 209 55 203 179 47 127 102 34 45 40 27 4 4 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 2 2 4 145 145 147 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 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 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 234 236 235 209 209 208 140 140 141 35 36 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 13 13 13 230 230 228 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 250 250 250 149 151 148 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 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 28 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 249 249 249 69 71 69 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 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 3 36 33 21 65 56 29 127 102 34 127 102 34 127 102 34 +65 56 29 45 40 27 15 14 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 24 24 26 183 183 184 255 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 254 254 254 250 249 248 206 207 206 71 74 72 4 4 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 56 57 57 253 253 253 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 243 244 243 92 91 89 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 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 85 81 255 255 255 255 255 255 255 255 255 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 235 229 14 13 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 2 2 2 4 4 3 4 4 3 +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 60 60 62 215 216 214 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 216 219 216 53 54 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 119 118 116 255 255 255 255 255 255 255 255 255 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 237 38 40 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 153 153 148 255 255 255 255 255 255 255 255 255 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 184 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 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 92 91 89 238 239 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 255 255 255 255 255 255 178 178 177 +8 8 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 182 183 177 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 212 212 214 5 5 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 +11 11 15 193 194 193 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 113 113 112 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +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 12 137 136 139 253 253 253 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 236 235 +69 71 69 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 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 15 21 21 21 21 21 21 21 21 21 17 17 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 13 13 20 219 219 221 255 255 255 255 255 255 255 255 255 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 164 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +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 47 219 219 221 255 255 255 255 255 255 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 247 247 56 57 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 +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 28 183 183 184 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 +134 134 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 1 5 5 5 19 20 20 41 43 42 70 70 63 126 128 130 +175 176 177 182 182 190 197 197 199 215 216 214 215 216 214 215 216 214 200 201 199 182 182 190 +165 166 171 113 113 112 70 70 63 28 29 33 8 8 9 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 1 1 2 4 4 4 8 8 7 +15 16 17 21 21 21 21 21 21 24 24 26 24 24 26 37 37 44 43 43 52 43 43 52 +43 43 52 43 43 52 43 43 52 43 43 52 43 43 52 37 37 44 29 29 28 24 24 26 +11 11 12 60 60 62 234 233 233 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 92 91 89 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 29 29 28 70 70 63 74 73 60 +74 73 60 74 73 60 74 73 60 74 73 60 74 73 60 74 73 60 74 73 60 74 73 60 +74 73 60 74 73 60 74 73 60 52 54 51 10 10 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 1 1 2 4 4 4 6 6 7 +14 13 15 17 17 20 21 21 21 21 21 21 23 23 21 24 24 23 24 24 26 24 24 26 +24 24 26 24 24 23 24 24 23 21 21 21 21 21 21 21 21 21 21 21 21 8 8 9 +92 91 89 234 233 233 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 200 201 199 29 29 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 2 2 4 2 2 4 +1 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 1 2 2 4 +2 2 4 2 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 +5 5 5 2 2 2 0 0 0 0 0 0 0 0 0 13 13 13 21 21 21 21 21 21 +24 24 23 34 34 38 49 49 55 61 61 57 74 73 60 74 73 60 74 74 69 75 77 80 +107 108 115 137 136 139 137 143 137 137 143 137 137 143 137 137 136 139 135 135 131 119 119 127 +86 85 81 74 73 60 63 66 61 34 34 38 17 17 20 4 4 4 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 +46 47 47 231 230 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 253 253 253 +172 172 174 2 2 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 1 11 11 15 53 54 59 107 107 107 175 176 177 222 222 223 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 245 248 245 193 194 193 126 128 130 65 69 67 11 11 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 11 11 15 42 42 47 75 77 80 107 107 107 135 135 131 +165 166 171 183 183 184 190 191 189 201 204 208 205 205 208 212 212 214 212 214 214 223 223 225 +223 223 225 223 223 225 223 223 225 218 217 218 212 214 214 212 214 214 208 208 212 191 191 198 +75 77 80 113 113 112 242 242 243 255 255 255 255 255 255 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 49 49 55 0 0 0 +0 0 0 0 0 0 0 0 0 6 6 7 60 60 62 179 182 178 250 249 248 255 253 248 +255 253 248 255 253 248 255 253 248 255 253 248 255 253 248 255 253 248 255 253 248 255 253 248 +255 253 248 255 253 248 220 221 219 119 119 122 17 17 20 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 1 11 11 15 41 41 42 75 77 80 102 103 105 124 126 122 +152 152 156 172 172 174 190 191 189 190 191 189 193 194 193 200 201 199 201 204 208 201 204 208 +201 204 208 200 199 197 197 196 193 190 191 189 190 191 189 190 191 189 172 172 174 60 60 67 +140 140 141 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 147 146 143 13 13 13 0 0 0 0 0 0 +0 0 0 3 3 7 15 16 17 41 41 42 52 54 51 63 66 61 81 81 89 81 81 89 +71 71 77 56 57 57 41 41 42 11 11 15 0 0 1 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 2 2 0 29 29 28 56 57 57 56 57 57 69 69 72 81 81 89 +89 89 95 94 95 97 101 101 99 108 107 102 107 107 107 107 107 107 107 107 107 107 107 107 +113 113 112 41 43 42 0 0 0 0 0 0 0 0 0 137 143 137 190 191 189 190 191 189 +199 199 200 212 214 214 228 229 229 246 245 244 255 254 252 255 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 254 254 242 241 241 206 207 206 172 172 174 107 107 107 60 60 67 22 23 25 +1 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 +89 89 95 251 252 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 246 245 244 +216 219 216 212 212 214 215 216 214 224 224 221 231 230 231 249 250 247 255 254 252 255 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 +183 183 184 11 11 15 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 +46 47 47 134 134 139 205 205 208 245 248 245 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 250 250 250 218 217 218 137 136 139 19 20 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 10 10 9 75 77 80 148 147 154 197 197 199 228 229 229 250 250 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 212 214 214 +56 57 57 159 161 155 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 209 209 208 21 21 21 0 0 0 +0 0 0 0 0 0 4 4 4 85 86 89 205 205 208 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 254 252 212 214 214 79 79 80 8 8 9 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 12 12 12 85 86 89 148 147 154 193 194 193 226 226 227 248 247 247 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 220 221 219 65 69 67 +172 172 174 255 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 250 249 248 94 95 97 2 2 2 14 13 15 53 54 59 +92 91 89 134 134 139 161 162 166 191 191 198 209 209 208 220 221 219 231 230 231 233 233 234 +225 226 225 212 212 214 191 193 193 148 147 154 81 81 89 6 6 7 0 0 0 0 0 0 +0 0 0 0 0 0 10 10 9 119 119 122 212 212 214 215 216 214 224 224 226 231 230 231 +238 239 238 240 241 241 242 245 241 251 252 251 255 254 254 255 255 255 255 255 255 255 255 255 +248 247 247 46 47 47 0 0 0 0 0 0 15 16 17 231 235 229 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 250 250 250 219 219 221 161 162 166 +71 71 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 2 2 2 +148 147 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 162 163 162 +46 47 47 41 41 42 41 43 42 46 47 47 52 54 51 63 66 61 119 118 116 220 221 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 254 254 +178 178 177 5 5 7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 119 119 122 +212 214 214 244 244 245 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 245 175 176 177 +29 29 28 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 +63 66 61 172 172 174 226 226 227 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 255 255 255 255 255 255 255 255 255 254 254 254 183 183 184 +38 40 37 190 191 189 255 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 165 165 164 13 13 13 0 0 0 +0 0 0 0 0 0 113 113 112 226 226 227 255 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 +184 189 184 61 61 57 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 10 10 9 +81 83 81 183 183 184 231 230 231 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 255 255 255 255 255 255 255 255 255 197 196 193 52 54 51 +200 199 197 255 255 255 255 255 255 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 128 128 137 145 145 147 199 199 200 218 217 218 +233 233 234 248 248 248 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 251 251 251 228 229 229 165 165 164 24 24 26 0 0 0 +0 0 0 0 0 0 13 13 13 145 145 147 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +209 209 208 17 15 14 0 0 0 0 0 0 49 49 55 240 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 251 251 251 +224 224 226 119 118 116 3 3 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 4 4 4 +220 221 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 253 253 253 81 83 81 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 17 17 20 +183 183 184 253 253 253 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 +140 140 141 0 0 0 0 0 0 0 0 0 4 4 4 46 47 47 179 182 178 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 253 253 253 +184 189 184 41 41 42 1 1 1 0 0 0 0 0 0 4 4 3 24 24 23 162 163 162 +248 247 247 253 253 253 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 250 250 250 134 134 139 +65 69 67 219 219 221 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 253 253 253 102 103 105 2 3 4 2 2 2 +29 29 28 149 151 148 246 245 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 236 236 237 137 136 139 +24 24 23 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 60 60 62 190 191 189 +248 247 247 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 149 151 148 81 81 89 +236 236 237 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 253 253 253 251 251 251 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 253 253 253 200 201 199 46 47 47 +1 1 0 0 0 0 5 5 7 65 69 67 119 119 127 128 128 137 137 143 137 165 165 164 +234 233 233 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +124 126 122 6 6 7 0 0 0 0 0 0 107 107 107 248 247 247 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 243 244 243 137 136 139 14 13 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 34 34 38 +255 254 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 228 229 229 29 29 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 +60 60 67 236 236 237 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 243 +98 97 101 0 0 0 0 0 0 4 4 4 69 69 72 193 194 193 252 253 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 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +251 252 251 135 135 131 11 11 12 0 0 0 6 6 7 69 71 69 184 189 184 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 246 246 245 65 69 67 +102 103 105 242 242 243 255 255 255 255 255 255 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 236 235 65 69 67 2 2 2 56 57 57 +174 177 173 248 247 247 255 255 255 255 255 255 255 255 255 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 223 113 114 119 3 3 7 +0 0 0 0 0 0 0 0 0 0 0 0 17 17 20 94 95 97 230 230 228 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 81 83 81 119 118 116 +255 254 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 252 253 251 159 161 155 +21 21 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 69 71 69 +219 219 221 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 242 242 243 +76 76 75 1 1 0 0 0 0 0 0 0 154 156 155 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 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 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 236 235 101 101 99 5 5 5 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 94 95 97 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 175 176 177 19 20 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 +52 54 51 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 226 229 225 +35 36 34 0 0 0 0 0 0 60 60 67 201 204 208 251 252 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 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +220 221 219 86 85 81 6 6 7 4 4 4 76 76 75 209 209 208 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 252 252 252 +238 239 238 228 229 229 226 226 227 223 223 225 226 226 227 234 233 233 228 229 229 26 27 26 +137 136 139 255 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 200 199 197 41 43 42 76 76 75 193 194 193 +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 252 252 252 200 201 199 85 86 89 6 6 7 0 0 0 +0 0 0 0 0 0 0 0 0 19 20 20 121 125 125 228 229 229 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 254 252 242 245 241 238 240 239 242 245 241 +242 245 241 245 248 245 254 254 254 255 255 255 255 255 255 255 254 252 46 47 47 159 161 155 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 230 230 228 +69 71 69 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 107 107 107 +244 244 245 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 201 204 208 +42 42 47 0 0 0 0 0 0 14 13 15 184 189 184 254 254 254 255 255 255 255 255 255 +255 255 255 255 255 255 255 254 254 246 245 244 236 236 237 236 236 237 242 245 241 255 254 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 190 191 189 29 29 28 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 154 156 155 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 126 128 130 8 8 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 +60 60 62 240 240 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 159 161 155 +2 2 2 0 0 0 28 29 33 197 197 199 252 253 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 255 255 255 255 255 255 255 255 255 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 236 235 +101 101 99 8 8 7 0 0 0 49 49 55 209 209 208 253 253 253 255 255 255 255 255 255 +255 255 255 255 255 255 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 238 239 238 209 209 208 161 162 166 113 114 119 89 89 95 +76 76 75 60 60 67 60 60 67 60 60 67 60 60 67 69 69 72 69 71 69 29 29 28 +183 183 184 255 255 255 255 255 255 255 255 255 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 166 171 105 105 109 218 217 218 252 253 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 251 251 251 183 183 184 52 54 51 5 5 5 0 0 0 0 0 0 +0 0 0 0 0 0 12 12 12 137 136 139 237 236 235 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 243 244 243 197 197 199 137 143 137 98 97 101 86 85 81 84 84 74 84 84 74 +84 84 74 84 84 74 98 97 101 128 128 137 172 172 174 174 177 173 35 36 34 200 201 199 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 253 253 253 +137 136 139 10 10 9 0 0 0 0 0 0 0 0 0 0 0 0 15 16 17 152 152 156 +253 253 253 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 152 152 156 +15 16 17 0 0 0 0 0 0 41 43 42 206 207 206 255 254 254 246 245 244 215 216 214 +174 177 173 119 119 131 98 97 101 86 85 81 76 76 75 73 73 73 81 83 81 94 95 97 +128 128 137 199 199 207 246 245 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 247 248 247 86 85 81 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 15 16 17 212 212 214 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 235 229 71 74 72 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 12 +152 152 156 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 226 226 227 37 37 44 +0 0 0 19 20 20 172 172 174 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 251 251 251 216 219 216 +149 151 148 89 89 95 69 69 72 102 103 105 165 166 171 230 230 228 253 253 253 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 252 252 252 126 128 130 +0 0 0 0 0 0 15 16 17 209 209 208 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 254 254 254 250 249 248 +226 229 225 179 182 178 107 107 107 38 40 37 14 13 15 1 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 49 49 55 +222 222 223 255 255 255 255 255 255 255 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 252 222 224 222 234 236 235 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 254 254 238 239 238 135 135 131 19 20 20 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 2 3 4 113 114 119 245 248 245 255 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 254 254 234 236 235 184 189 184 +107 107 107 46 47 47 4 4 3 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 60 60 67 246 246 245 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 253 253 253 240 241 241 +224 224 223 193 194 193 191 193 193 220 221 219 248 248 248 255 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 +199 199 200 19 20 20 0 0 0 0 0 0 0 0 0 0 0 0 41 41 42 199 199 200 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 242 242 243 107 107 107 +0 0 0 0 0 0 0 0 0 49 49 55 124 126 122 79 79 80 42 42 47 14 13 15 +1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 1 1 8 8 7 65 69 67 165 166 171 238 239 238 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 165 165 164 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 63 66 61 226 226 227 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 193 194 193 41 41 42 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 15 16 17 102 103 105 +240 240 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 234 233 233 113 113 112 6 6 7 +6 6 7 107 107 107 234 236 235 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 251 251 251 178 178 177 61 61 57 +6 6 7 0 0 0 0 0 0 0 0 0 13 13 13 102 103 105 231 230 231 255 254 254 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 209 209 208 19 20 20 +0 0 0 6 6 7 135 135 131 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 234 233 233 154 156 155 +79 79 80 17 17 20 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 1 1 1 81 83 81 +250 250 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 253 253 253 +218 217 218 119 118 116 11 11 15 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 1 2 69 69 72 233 233 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 251 251 251 200 201 199 98 97 101 23 23 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 107 107 107 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 247 247 184 189 184 113 113 112 +60 60 62 26 27 26 26 27 26 65 69 67 172 172 174 248 248 248 255 255 255 255 255 255 +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 223 24 24 26 0 0 0 0 0 0 0 0 0 0 0 0 69 71 69 240 241 241 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 212 214 214 60 60 62 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 22 23 25 134 134 139 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 215 216 214 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 107 107 107 240 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 254 254 159 161 155 14 13 15 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 52 54 51 149 151 148 233 233 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 238 240 239 134 134 139 19 20 20 0 0 0 +41 41 42 193 194 193 255 255 255 255 255 255 255 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 187 191 189 42 42 47 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 10 9 154 156 155 253 252 251 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 250 249 248 94 95 97 0 0 0 +0 0 0 69 69 72 225 226 225 255 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 254 254 215 216 214 94 95 97 19 20 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 4 4 4 126 128 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 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 253 253 253 200 201 199 +79 79 80 10 10 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +34 34 38 190 191 189 253 253 253 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 243 244 243 165 165 164 56 57 57 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 161 162 166 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 237 236 235 137 136 139 38 40 37 4 4 3 +0 0 0 0 0 0 0 0 0 0 0 0 41 41 42 220 221 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 +226 226 227 24 24 26 0 0 0 0 0 0 0 0 0 5 5 5 119 119 122 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 254 254 184 189 184 17 17 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 21 21 21 215 216 214 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 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 241 241 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 6 7 154 156 155 252 252 253 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 243 244 243 119 118 116 2 2 2 1 1 1 +2 2 2 5 5 7 21 21 21 81 81 89 155 157 162 222 222 222 247 248 247 255 255 255 +255 255 255 255 255 255 255 255 255 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 245 244 147 146 143 19 19 25 0 0 0 5 5 5 +113 113 112 248 248 248 255 255 255 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 226 229 225 86 85 81 2 2 2 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 79 79 80 249 249 249 +255 255 255 255 255 255 255 255 255 255 255 255 255 254 254 183 183 184 29 29 28 0 0 0 +12 12 12 154 156 155 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 254 254 254 205 205 208 69 69 72 5 5 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 8 8 9 197 197 199 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 193 194 193 46 47 47 +4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 4 +119 118 116 243 244 243 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 162 163 162 29 29 28 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 220 221 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 254 254 254 234 233 233 107 107 107 17 15 14 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 172 172 174 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +218 217 218 24 24 23 0 0 0 0 0 0 0 0 0 13 13 13 178 178 177 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 248 248 248 137 136 139 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 126 128 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 253 248 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 38 40 37 191 193 193 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 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 239 238 174 177 173 153 153 148 161 162 166 +197 197 199 228 229 229 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 250 250 249 220 221 219 94 95 97 0 0 0 0 0 0 0 0 0 24 24 23 +205 205 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 250 250 250 154 156 155 5 5 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 24 24 23 246 246 245 +255 255 255 255 255 255 255 255 255 255 255 255 246 246 245 102 103 105 1 1 2 0 0 0 +75 77 80 228 229 229 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 206 207 206 52 54 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 21 21 21 246 245 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 +255 255 255 255 255 255 255 255 255 255 254 254 237 236 235 140 140 141 10 10 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 56 57 57 +208 208 212 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 197 197 199 19 20 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 41 41 42 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 234 236 235 98 97 101 2 2 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 165 165 164 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +205 205 208 21 21 21 0 0 0 0 0 0 0 0 0 34 34 38 245 248 245 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 238 239 238 65 69 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 53 54 59 252 253 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 253 248 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 69 71 69 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 254 254 254 +228 229 229 155 157 162 56 57 57 2 2 2 0 0 0 0 0 0 0 0 0 74 74 69 +255 254 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 236 236 237 85 86 89 0 0 0 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 20 246 246 245 +255 255 255 255 255 255 255 255 255 255 255 255 206 207 206 52 54 51 0 0 0 11 11 12 +137 136 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 246 245 244 81 83 81 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 69 71 69 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 253 253 253 219 219 221 113 113 112 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 6 6 7 119 118 116 +255 254 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 249 249 249 69 69 72 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 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 95 97 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 253 253 253 165 165 164 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 172 172 174 255 255 255 255 255 255 +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 191 189 17 17 20 0 0 0 0 0 0 0 0 0 92 91 89 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 215 216 214 12 12 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 38 40 37 238 239 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 242 245 241 +0 0 0 0 0 0 0 0 0 0 0 0 2 3 4 105 105 109 246 246 245 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 239 175 176 177 +81 81 89 22 23 25 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 149 151 148 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 216 219 216 22 23 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 35 36 34 248 247 247 +255 255 255 255 255 255 255 255 255 253 253 253 165 165 164 14 13 15 0 0 0 28 29 33 +199 199 207 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 179 182 178 2 2 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 126 128 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 255 255 255 +255 255 255 255 255 255 237 236 235 75 77 80 11 11 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 21 21 21 197 197 199 +255 255 255 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 212 11 11 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 149 151 148 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 250 249 248 56 57 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 3 3 7 197 197 199 255 255 255 255 255 255 +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 156 155 13 13 13 0 0 0 0 0 0 0 0 0 161 162 166 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 162 163 162 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 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 36 34 228 229 229 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 221 223 222 +0 0 0 0 0 0 0 0 0 0 0 0 15 16 17 149 151 148 255 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 231 235 229 153 153 148 76 76 75 22 23 25 +2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 212 214 214 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 175 176 177 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 69 71 69 248 248 248 +255 255 255 255 255 255 255 255 255 244 244 245 121 125 125 0 0 1 0 0 0 61 61 57 +248 247 247 255 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 94 95 97 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 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 193 194 193 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 243 244 243 98 97 101 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 53 54 59 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 153 153 148 5 5 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 8 8 7 200 199 197 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 191 191 198 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 34 34 38 222 222 223 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +121 125 125 6 6 7 0 0 0 0 0 0 13 13 20 220 221 219 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 254 254 94 95 97 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 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 41 42 250 249 248 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 200 199 197 +0 0 0 0 0 0 0 0 0 0 0 0 35 36 34 199 199 207 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 250 249 248 137 143 137 6 6 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 41 43 42 236 236 237 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 128 128 137 0 0 0 0 0 0 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 122 251 251 251 +255 255 255 255 255 255 255 255 255 228 229 229 69 69 72 0 0 0 0 0 0 121 125 125 +255 255 255 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 253 251 53 54 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 34 34 38 224 224 226 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 224 224 221 81 83 81 4 4 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 126 128 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 140 140 141 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 61 61 57 224 224 223 255 255 255 255 255 255 +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 89 89 95 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 81 83 81 234 236 235 255 255 255 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 251 +94 95 97 2 2 2 0 0 0 0 0 0 71 74 72 238 239 238 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 243 244 243 29 29 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 113 113 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 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 135 135 131 +0 0 0 0 0 0 0 0 0 0 0 0 60 60 62 240 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 242 241 241 250 250 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 254 254 254 200 201 199 46 47 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 85 86 89 242 242 243 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 92 91 89 0 0 0 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 3 178 178 177 254 254 254 +255 255 255 255 255 255 255 255 255 219 219 221 35 36 34 0 0 0 0 0 0 172 172 174 +255 255 255 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 250 247 49 49 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 76 76 75 234 233 233 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 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 253 251 184 189 184 41 41 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 183 183 184 255 255 255 +255 255 255 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 174 6 6 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 101 101 99 236 236 237 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +224 224 226 41 41 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 135 135 131 248 247 247 255 255 255 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 230 231 +65 69 67 0 0 0 0 0 0 0 0 0 126 128 130 248 247 247 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 197 197 199 15 16 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 17 17 20 212 212 214 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 251 252 251 85 86 89 +0 0 0 0 0 0 0 0 0 0 0 0 107 107 107 255 254 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 174 177 173 199 199 200 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 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 247 247 134 134 139 11 11 12 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 105 105 109 246 245 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 69 69 72 0 0 0 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 41 42 212 212 214 255 254 254 +255 255 255 255 255 255 255 255 255 206 207 206 8 8 7 0 0 0 0 0 0 208 208 212 +255 255 255 255 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 98 97 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 6 6 7 135 135 131 246 246 245 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 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 149 151 148 10 10 9 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 6 7 224 224 223 255 255 255 +255 255 255 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 233 233 26 27 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 8 8 12 148 147 154 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 +161 162 166 17 17 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 11 11 12 172 172 174 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 201 204 208 +46 47 47 0 0 0 0 0 0 8 8 12 172 172 174 253 253 253 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 140 140 141 8 8 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 5 5 5 119 119 122 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 222 222 222 41 41 42 +0 0 0 0 0 0 0 0 0 1 1 1 165 165 164 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 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 101 101 99 105 105 109 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 216 219 216 56 57 57 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 113 113 112 246 246 245 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 65 69 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 102 103 105 236 236 237 255 255 255 +255 255 255 255 255 255 255 255 255 172 172 174 0 0 0 0 0 0 0 0 0 225 226 225 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 206 207 206 11 11 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 4 4 4 34 34 38 135 135 131 231 230 231 254 254 254 255 255 255 +255 255 255 254 254 254 249 250 247 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 244 244 245 101 101 99 2 2 2 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 37 37 44 238 239 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 254 254 152 152 156 8 8 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 2 2 2 34 34 38 137 136 139 233 233 234 255 254 254 255 255 255 255 255 255 +251 252 251 231 235 229 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 253 252 251 +105 105 109 2 3 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 46 47 47 200 201 199 255 255 255 255 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 165 165 164 +21 21 21 0 0 0 0 0 0 41 43 42 206 207 206 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 253 252 251 92 91 89 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 8 8 9 102 103 105 230 230 228 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 254 254 254 162 163 162 19 20 20 +0 0 0 0 0 0 0 0 0 6 6 7 243 244 243 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 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 245 244 38 40 37 35 36 34 191 191 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 159 161 155 12 12 12 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 113 113 112 244 244 245 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 98 97 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 24 24 23 172 172 174 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 152 152 156 0 0 0 0 0 0 1 1 2 248 247 247 +255 255 255 255 255 255 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 161 162 166 34 34 38 4 4 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 +10 10 9 46 47 47 113 114 119 219 219 221 255 255 255 255 255 255 255 255 255 255 255 255 +255 254 254 220 221 219 187 191 189 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 254 254 251 251 251 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 237 236 235 69 69 72 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 56 57 57 242 242 243 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 243 244 243 134 134 139 24 24 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 6 6 7 +35 36 34 98 97 101 212 214 214 255 255 255 255 255 255 255 255 255 255 255 255 248 247 247 +179 182 178 184 189 184 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 219 219 221 +63 66 61 0 0 0 0 0 0 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 86 89 234 236 235 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 250 250 250 126 128 130 +1 1 2 0 0 0 0 0 0 79 79 80 225 226 225 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 218 217 218 52 54 51 0 0 0 0 0 0 0 0 0 +0 0 0 28 29 33 15 16 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 35 36 34 121 125 125 236 236 237 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 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 240 239 94 95 97 2 2 2 +0 0 0 0 0 0 0 0 0 52 54 51 255 254 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 197 197 199 24 24 26 6 6 7 113 114 119 243 244 243 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 239 63 66 61 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 102 103 105 244 244 245 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 153 153 148 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 4 4 4 92 91 89 234 233 233 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 148 147 154 0 0 0 0 0 0 3 3 7 248 247 247 +255 255 255 255 255 255 255 255 255 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 247 247 184 189 184 98 97 101 41 41 42 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 24 24 26 76 76 75 +137 136 139 206 207 206 250 250 250 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +212 214 214 153 153 148 234 233 233 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 254 252 178 178 177 240 240 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 252 252 253 187 191 189 +41 41 42 0 0 0 0 0 0 0 0 0 0 0 0 65 69 67 242 242 243 255 255 255 +255 255 255 255 255 255 255 255 255 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 240 239 165 165 164 79 79 80 14 13 15 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 24 24 26 69 69 72 124 126 122 +187 191 189 246 245 244 255 255 255 255 255 255 255 255 255 255 255 255 248 248 248 183 183 184 +152 152 156 238 239 238 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 190 191 189 +38 40 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 8 8 9 126 128 130 251 252 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 231 230 231 85 86 89 +0 0 0 0 0 0 0 0 0 113 113 112 248 247 247 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 183 183 184 35 36 34 0 0 0 0 0 0 0 0 0 +26 27 26 178 178 177 148 147 154 101 101 99 63 66 61 35 36 34 2 2 4 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 11 11 12 49 49 55 +101 101 99 183 183 184 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 190 191 189 35 36 34 0 0 0 +0 0 0 0 0 0 0 0 0 113 113 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 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 147 146 143 13 13 13 0 0 0 46 47 47 200 201 199 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 178 178 177 +3 3 7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 79 79 80 240 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 212 214 214 28 29 33 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 52 54 51 209 209 208 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 155 157 162 0 0 0 0 0 0 0 0 0 231 235 229 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 236 235 200 201 199 154 156 155 +119 118 116 86 85 81 65 69 67 85 86 89 124 126 122 153 153 148 184 189 184 225 226 225 +251 251 251 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 254 254 254 216 219 216 +134 134 139 206 207 206 252 252 252 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +231 230 231 73 73 73 126 128 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 246 246 245 +149 151 148 21 21 21 0 0 0 0 0 0 0 0 0 63 66 61 242 242 243 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 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 225 226 225 174 177 173 126 128 130 +94 95 97 86 85 81 102 103 105 126 128 130 159 161 155 190 191 189 220 221 219 249 249 249 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 165 165 164 135 135 131 +230 230 228 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 252 253 251 149 151 148 +6 6 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 29 29 28 179 182 178 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 209 209 208 46 47 47 +0 0 0 0 0 0 12 12 12 147 146 143 255 254 254 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 145 145 147 13 13 13 0 0 0 0 0 0 0 0 0 +113 113 112 246 246 245 255 255 255 242 242 243 218 217 218 193 194 193 165 165 164 149 151 148 +126 128 130 108 107 102 98 97 101 105 105 109 124 126 122 147 146 143 178 178 177 206 207 206 +240 241 241 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 240 241 241 113 114 119 2 3 4 0 0 0 +0 0 0 0 0 0 1 1 1 178 178 177 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 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 247 247 92 91 89 1 1 1 0 0 0 4 4 3 126 128 130 246 246 245 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 239 +85 86 89 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 28 29 33 233 233 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 250 250 250 172 172 174 41 41 42 12 12 12 10 10 9 +13 13 13 26 27 26 107 107 107 220 221 219 253 253 253 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 179 182 178 1 1 1 0 0 0 0 0 0 209 209 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 254 254 254 252 252 251 +246 245 244 238 240 239 236 236 237 238 240 239 246 246 245 251 251 251 254 254 254 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 252 252 252 212 214 214 102 103 105 +193 194 193 251 251 251 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +193 194 193 41 41 42 17 17 20 165 165 164 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 +238 240 239 102 103 105 5 5 5 0 0 0 0 0 0 38 40 37 238 239 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 253 253 253 248 247 247 +240 241 241 238 239 238 242 242 243 248 247 247 252 252 252 255 254 254 255 254 254 255 255 255 +255 255 255 255 255 255 255 255 255 255 254 254 248 247 247 149 151 148 94 95 97 224 224 221 +255 254 254 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 242 242 243 113 114 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 56 57 57 237 236 235 255 255 255 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 182 183 177 4 4 4 +0 0 0 0 0 0 29 29 28 178 178 177 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 248 248 248 119 118 116 0 0 1 0 0 0 0 0 0 19 20 20 +184 189 184 254 254 254 255 255 255 255 255 255 255 255 255 255 254 254 254 254 254 250 250 250 +246 246 245 242 242 243 240 241 241 243 244 243 246 246 245 250 250 250 255 254 254 255 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 193 194 193 17 17 20 0 0 0 0 0 0 +0 0 0 0 0 0 29 29 28 215 216 214 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 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 221 60 60 62 0 0 0 0 0 0 0 0 0 38 40 37 218 217 218 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 253 253 253 +190 191 189 28 29 33 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 197 196 193 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 251 252 251 231 235 229 182 183 177 165 165 164 +184 189 184 226 229 225 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 215 216 214 24 24 26 0 0 0 0 0 0 149 151 148 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 243 244 243 179 182 178 71 71 77 178 178 177 +255 254 252 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 254 254 +154 156 155 13 13 13 0 0 0 46 47 47 193 194 193 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 242 241 241 63 66 61 0 0 0 0 0 0 0 0 0 206 207 206 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 253 253 253 230 230 228 124 126 122 70 70 63 220 221 219 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 225 226 225 69 69 72 +0 0 0 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 107 107 107 255 255 255 255 255 255 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 119 118 116 0 0 0 +0 0 0 0 0 0 38 40 37 197 197 199 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 226 226 227 81 83 81 0 0 0 0 0 0 2 2 2 101 101 99 +234 233 233 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +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 239 65 69 67 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 79 79 80 231 230 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 183 183 184 34 34 38 0 0 0 0 0 0 0 0 0 0 0 0 140 140 141 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +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 239 238 107 107 107 5 5 7 0 0 0 0 0 0 0 0 0 0 0 0 113 113 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 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 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 230 231 75 77 80 0 0 0 0 0 0 79 79 80 +248 247 247 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 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 234 233 233 145 145 147 63 66 61 153 153 148 249 250 247 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 248 247 247 +119 119 122 0 0 0 0 0 0 2 2 2 73 73 73 212 214 214 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 190 191 189 38 40 37 0 0 0 0 0 0 126 128 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 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 218 217 218 102 103 105 76 76 75 190 191 189 254 254 254 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 212 214 214 35 36 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 6 6 7 178 178 177 255 255 255 255 255 255 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 243 56 57 57 0 0 0 +0 0 0 0 0 0 42 42 47 205 205 208 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 212 212 214 56 57 57 0 0 0 0 0 0 29 29 28 174 177 173 +255 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 246 245 244 +140 140 141 3 3 7 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 126 128 130 246 246 245 255 255 255 255 255 255 255 255 255 255 255 255 +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 148 147 154 8 8 12 0 0 0 0 0 0 0 0 0 0 0 0 41 41 42 +242 242 243 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 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 197 197 199 41 41 42 0 0 0 0 0 0 0 0 0 0 0 0 38 40 37 +224 224 221 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 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 145 145 147 8 8 9 0 0 0 28 29 33 +187 191 189 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 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 226 225 85 86 89 46 47 47 145 145 147 240 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 224 224 226 +75 77 80 0 0 0 0 0 0 0 0 0 8 8 7 107 107 107 243 244 243 255 255 255 +255 255 255 255 255 255 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 149 151 148 15 16 17 0 0 0 41 43 42 226 229 225 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 206 207 206 71 71 77 60 60 62 184 189 184 250 250 250 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 254 254 254 179 182 178 5 5 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 17 17 20 231 235 229 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 226 229 225 10 10 9 0 0 0 +0 0 0 0 0 0 49 49 55 212 212 214 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 197 197 199 29 29 28 0 0 0 2 2 2 86 85 81 240 240 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 255 255 255 255 255 255 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 155 157 162 +29 29 28 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 17 17 20 165 166 171 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 +237 236 235 101 101 99 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 6 7 +148 147 154 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 251 251 251 124 126 122 6 6 7 0 0 0 0 0 0 0 0 0 5 5 5 +102 103 105 238 239 238 255 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 252 252 252 191 193 193 43 43 52 0 0 0 1 1 2 +79 79 80 225 226 225 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 254 254 253 253 253 +234 236 235 162 163 162 46 47 47 35 36 34 149 151 148 243 244 243 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 254 254 206 207 206 +35 36 34 0 0 0 0 0 0 0 0 0 0 0 0 6 6 7 140 140 141 250 250 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 254 254 254 236 236 237 113 114 119 8 8 7 8 8 7 119 119 122 +242 245 241 255 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 254 254 254 238 239 238 +155 157 162 34 34 38 56 57 57 197 197 199 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 253 253 253 145 145 147 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 76 76 75 253 253 253 255 255 255 255 255 255 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 174 0 0 0 0 0 0 +0 0 0 0 0 0 46 47 47 212 212 214 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 254 254 183 183 184 11 11 15 0 0 0 24 24 26 191 191 198 250 250 250 +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 243 244 243 161 162 166 34 34 38 +0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 46 47 47 200 201 199 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +218 217 218 56 57 57 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +53 54 59 226 226 227 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 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 226 225 41 41 42 0 0 0 0 0 0 0 0 0 0 0 0 +15 16 17 135 135 131 238 239 238 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 250 250 250 184 189 184 65 69 67 2 2 4 0 0 0 0 0 0 +8 8 7 107 107 107 224 224 221 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 254 254 242 245 241 182 183 177 +92 91 89 17 15 14 6 6 7 172 172 174 255 254 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 253 253 253 174 177 173 +5 5 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 17 17 20 174 177 173 +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 226 226 227 76 76 75 2 2 2 29 29 28 +154 156 155 243 244 243 255 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 251 252 251 206 207 206 107 107 107 +15 16 17 17 15 14 209 209 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 252 252 252 94 95 97 0 0 0 +0 0 0 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 152 156 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 101 101 99 0 0 0 0 0 0 +0 0 0 0 0 0 41 41 42 199 199 200 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 254 254 178 178 177 2 2 4 4 4 3 128 128 137 216 219 216 191 193 193 +248 248 248 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 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 253 251 225 226 225 126 128 130 19 20 20 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 79 79 80 233 233 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 254 254 254 +193 194 193 15 16 17 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +15 16 17 152 152 156 255 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 147 146 143 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 26 27 26 121 125 125 238 239 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 254 254 230 230 228 145 145 147 38 40 37 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 11 11 12 79 79 80 200 199 197 255 254 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 254 254 246 246 245 200 199 197 113 113 112 29 29 28 +0 0 0 0 0 0 29 29 28 249 250 247 255 255 255 255 255 255 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 121 125 125 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 56 57 57 +200 199 197 255 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 197 197 199 28 29 33 0 0 0 +35 36 34 135 135 131 237 236 235 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 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 252 226 229 225 153 153 148 56 57 57 4 4 4 +0 0 0 70 70 63 253 253 253 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 251 251 251 52 54 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 +15 16 17 206 207 206 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 243 244 243 46 47 47 0 0 0 0 0 0 +0 0 0 0 0 0 22 23 25 165 165 164 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 254 254 193 194 193 37 37 44 92 91 89 209 209 208 107 107 107 154 156 155 +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 254 254 234 233 233 162 163 162 81 83 81 6 6 7 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +8 8 7 121 125 125 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 252 252 252 +153 153 148 1 1 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 1 79 79 80 225 226 225 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 226 226 227 52 54 51 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 14 13 15 81 83 81 200 199 197 255 254 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 242 241 241 +149 151 148 69 71 69 15 16 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 41 41 42 107 107 107 187 191 189 246 246 245 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 243 244 243 162 163 162 89 89 95 38 40 37 4 4 4 0 0 0 +0 0 0 0 0 0 71 74 72 255 255 255 255 255 255 255 255 255 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 243 60 60 67 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 +86 85 81 225 226 225 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 155 157 162 3 3 7 +0 0 0 17 15 14 73 73 73 178 178 177 244 244 245 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 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 226 225 137 136 139 63 66 61 17 17 20 0 0 0 0 0 0 +0 0 0 124 126 122 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 240 241 241 10 10 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 +56 57 57 228 229 229 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 205 205 208 22 23 25 0 0 0 0 0 0 +0 0 0 0 0 0 2 2 2 107 107 107 242 242 243 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 242 242 243 205 205 208 199 199 207 92 91 89 38 40 37 179 182 178 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 250 247 +200 199 197 134 134 139 63 66 61 23 23 21 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 +21 21 21 165 165 164 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 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 +85 86 89 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 9 165 165 164 253 253 253 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 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 166 171 11 11 15 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 2 2 2 14 13 15 71 71 77 148 147 154 219 219 221 +234 233 233 240 241 241 243 244 243 249 249 249 252 252 251 255 254 254 255 254 254 251 252 251 +248 248 248 244 244 245 242 242 243 236 236 237 219 219 221 175 176 177 113 114 119 19 20 20 +8 8 7 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 4 4 3 11 11 12 22 23 25 89 89 95 +134 134 139 155 157 162 191 193 193 222 222 222 223 223 225 223 223 225 212 212 214 172 172 174 +137 136 139 81 81 89 22 23 25 8 8 9 2 2 2 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 92 91 89 158 158 170 158 158 170 158 158 170 158 158 170 158 158 170 +158 158 170 158 158 170 158 158 170 158 158 170 158 158 170 158 158 170 152 152 156 12 12 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 +4 4 4 94 95 97 161 162 166 158 158 170 158 158 170 158 158 170 158 158 170 158 158 170 +158 158 170 158 158 170 158 158 170 158 158 170 158 158 170 158 158 170 152 152 156 70 70 63 +0 0 0 0 0 0 1 1 1 10 10 9 29 29 28 94 95 97 149 151 148 201 204 208 +223 223 225 223 223 225 225 226 225 225 226 225 224 224 226 223 223 225 215 216 214 165 166 171 +126 128 130 60 60 62 15 16 17 6 6 7 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 124 126 122 158 158 170 158 158 170 158 158 170 158 158 170 158 158 170 158 158 170 +158 158 170 158 158 170 158 158 170 158 158 170 158 158 170 134 134 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 +86 85 81 155 157 162 158 158 170 158 158 170 158 158 170 158 158 170 158 158 170 158 158 170 +158 158 170 158 158 170 158 158 170 161 162 166 105 105 109 8 8 9 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 24 24 26 174 177 173 249 249 249 255 255 255 255 255 255 +255 255 255 253 253 253 238 240 239 187 191 189 53 54 59 4 4 3 56 57 57 218 217 218 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 251 251 251 226 226 227 223 223 225 223 223 225 223 223 225 223 223 225 223 223 225 +223 223 225 222 222 223 206 207 206 174 177 173 145 145 147 128 128 137 81 83 81 24 24 23 +12 12 12 6 6 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 +35 36 34 190 191 189 222 222 222 222 222 222 222 222 222 222 222 222 222 222 222 222 222 222 +222 222 222 222 222 222 222 222 222 222 222 222 222 222 222 222 222 222 222 222 222 215 216 214 +24 24 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 69 71 69 206 207 206 222 222 222 222 222 222 222 222 222 222 222 222 +222 222 222 222 222 222 222 222 222 222 222 222 222 222 222 222 222 222 222 222 222 222 222 222 +222 222 222 222 222 222 222 222 222 222 222 222 200 201 199 73 73 73 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 7 13 13 20 +63 66 61 102 103 105 113 113 112 148 147 154 165 165 164 178 178 177 178 178 177 159 161 155 +145 145 147 113 114 119 107 107 107 71 71 77 19 19 25 3 3 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 9 9 19 9 9 19 9 9 19 9 9 19 9 9 19 3 3 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 1 8 8 12 +9 9 19 9 9 19 19 20 20 21 21 21 13 13 20 9 9 19 9 9 19 3 3 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 41 41 42 152 152 156 206 207 206 212 214 214 +205 205 208 174 177 173 94 95 97 19 19 25 0 0 0 0 0 1 79 79 80 250 249 248 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 224 224 223 28 29 33 9 9 19 9 9 19 9 9 19 9 9 19 9 9 19 +9 9 19 9 9 19 9 9 19 3 3 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 +13 13 13 69 71 69 73 73 73 73 73 73 73 73 73 73 73 73 73 73 73 73 73 73 +73 73 73 73 73 73 73 73 73 73 73 73 73 73 73 73 73 73 73 73 73 69 71 69 +0 0 0 0 0 0 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 7 63 66 61 73 73 73 73 73 73 73 73 73 73 73 73 +73 73 73 73 73 73 73 73 73 73 73 73 73 73 73 73 73 73 73 73 73 73 73 73 +73 73 73 73 73 73 73 73 73 73 73 73 73 73 73 35 36 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 8 8 12 11 11 15 14 13 15 14 13 15 13 13 13 +8 8 12 1 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 11 11 15 52 54 51 61 61 57 +49 49 55 19 20 20 0 0 0 0 0 0 0 0 0 5 5 5 113 114 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 200 201 199 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 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 161 162 166 255 255 255 +255 255 255 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 146 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 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 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 20 20 206 207 206 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 86 85 81 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 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 47 247 248 247 255 255 255 +255 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 252 52 54 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 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 81 83 81 255 255 255 255 255 255 +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 233 233 17 17 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 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 140 140 141 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +197 197 199 11 11 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 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 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 187 191 189 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +137 136 139 6 6 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 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 22 23 25 234 233 233 255 255 255 255 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 +94 95 97 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 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 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 62 238 239 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 238 239 238 +63 66 61 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 76 76 75 182 183 177 184 189 184 184 189 184 +184 189 184 184 189 184 184 189 184 184 189 184 184 189 184 184 189 184 184 189 184 159 161 155 +35 36 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 diff --git a/bsp/rockchip/dm/hwcrypto/Kconfig b/bsp/rockchip/dm/hwcrypto/Kconfig index ec89f7a0b97e..eff66dfdb4eb 100755 --- a/bsp/rockchip/dm/hwcrypto/Kconfig +++ b/bsp/rockchip/dm/hwcrypto/Kconfig @@ -3,3 +3,23 @@ config RT_HWCRYPTO_RNG_ROCKCHIP depends on RT_HWCRYPTO_USING_RNG depends on RT_USING_RESET default n + +config RT_HWCRYPTO_CRYPTO_ROCKCHIP_V2 + bool "Rockchip Crypto V2 (cipher/hash/pka)" + depends on RT_USING_RESET + depends on (RT_HWCRYPTO_USING_AES && \ + (RT_HWCRYPTO_USING_AES_ECB || RT_HWCRYPTO_USING_AES_CBC || \ + RT_HWCRYPTO_USING_AES_CFB || RT_HWCRYPTO_USING_AES_CTR || \ + RT_HWCRYPTO_USING_AES_OFB)) || \ + (RT_HWCRYPTO_USING_DES && \ + (RT_HWCRYPTO_USING_DES_ECB || RT_HWCRYPTO_USING_DES_CBC)) || \ + (RT_HWCRYPTO_USING_3DES && \ + (RT_HWCRYPTO_USING_3DES_ECB || RT_HWCRYPTO_USING_3DES_CBC)) || \ + (RT_HWCRYPTO_USING_GCM && RT_HWCRYPTO_USING_AES) || \ + RT_HWCRYPTO_USING_MD5 || RT_HWCRYPTO_USING_SHA1 || \ + (RT_HWCRYPTO_USING_SHA2 && \ + (RT_HWCRYPTO_USING_SHA2_224 || RT_HWCRYPTO_USING_SHA2_256 || \ + RT_HWCRYPTO_USING_SHA2_384 || RT_HWCRYPTO_USING_SHA2_512)) || \ + (RT_HWCRYPTO_USING_BIGNUM && \ + RT_HWCRYPTO_USING_BIGNUM_EXPTMOD) + default n diff --git a/bsp/rockchip/dm/hwcrypto/SConscript b/bsp/rockchip/dm/hwcrypto/SConscript index eabfe3e7f1c7..d52398fbe691 100755 --- a/bsp/rockchip/dm/hwcrypto/SConscript +++ b/bsp/rockchip/dm/hwcrypto/SConscript @@ -2,11 +2,16 @@ from building import * cwd = GetCurrentDir() src = [] -CPPPATH = [cwd + '/../include'] +CPPPATH = [cwd + '/../include', cwd] if GetDepend(['RT_HWCRYPTO_RNG_ROCKCHIP']): src += ['hw-rng-rockchip.c'] +if GetDepend(['RT_HWCRYPTO_CRYPTO_ROCKCHIP_V2']): + src += [ + 'hw-crypto-rockchip-v2.c', + ] + group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) Return('group') diff --git a/bsp/rockchip/dm/hwcrypto/hw-crypto-rockchip-v2.c b/bsp/rockchip/dm/hwcrypto/hw-crypto-rockchip-v2.c new file mode 100644 index 000000000000..bf2840b9cb11 --- /dev/null +++ b/bsp/rockchip/dm/hwcrypto/hw-crypto-rockchip-v2.c @@ -0,0 +1,2728 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-3-08 GuEe-GUI the first version + */ + +#include +#include +#include + +#define DBG_TAG "crypto.rockchip.v2" +#define DBG_LVL DBG_INFO +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include "rockchip.h" +#include "hw-crypto-rockchip-v2.h" + +#define RK_CRYPTO_TIMEOUT_US 500000 +#define RK_CRYPTO_DATA_ALIGN 8 +#define RK_CRYPTO_AES_BLOCK 16 +#define RK_CRYPTO_HASH_BLOCK 64 +#define RK_CRYPTO_DES_BLOCK 8 +#define RK_CRYPTO_SM4_KEYLEN 16 +#define RK_CRYPTO_HMAC_KEY_MAX 64 +#define RK_CRYPTO_HASH_CTX_MAGIC 0x1A1A1A1A + +struct rk_crypto_lli +{ + rt_uint32_t src_addr; + rt_uint32_t src_len; + rt_uint32_t dst_addr; + rt_uint32_t dst_len; + rt_uint32_t user_define; + rt_uint32_t reserve; + rt_uint32_t dma_ctrl; + rt_uint32_t next_addr; +}; + +struct rk_crypto_hash_ctx +{ + rt_uint32_t magic; + rt_uint32_t digest_size; + rt_bool_t started; + rt_bool_t is_hmac; + rt_uint8_t hmac_key[RK_CRYPTO_HMAC_KEY_MAX]; + rt_size_t hmac_key_len; + rt_uint8_t leftover[RK_CRYPTO_HASH_BLOCK]; + rt_size_t leftover_len; + struct rk_crypto_lli lli; +}; + +struct rk_crypto_gcm_ctx +{ + rt_uint8_t *aad; + rt_size_t aad_len; + rt_size_t tag_len; + rt_bool_t started; + rt_bool_t aad_done; + hwcrypto_mode mode; +}; + +rt_inline struct rockchip_crypto *rk_crypto_from_hwdev( + struct rt_hwcrypto_device *hwdev) +{ + return rt_container_of(hwdev, struct rockchip_crypto, parent); +} + +static rt_uint32_t rk_crypto_readl(struct rockchip_crypto *rc, rt_uint32_t off) +{ + return HWREG32((rt_uint8_t *)rc->regs + off); +} + +static void rk_crypto_writel(struct rockchip_crypto *rc, rt_uint32_t val, rt_uint32_t off) +{ + HWREG32((rt_uint8_t *)rc->regs + off) = val; +} + +static void rk_crypto_write_masked(struct rockchip_crypto *rc, rt_uint32_t off, rt_uint32_t val) +{ + rk_crypto_writel(rc, val | (val << CRYPTO_WRITE_MASK_SHIFT), off); +} + +static rt_uint32_t rk_crypto_virt_to_phys(const void *addr) +{ + return (rt_uint32_t)(rt_ubase_t)addr; +} + +static rt_err_t rk_crypto_poll_reg(struct rockchip_crypto *rc, rt_uint32_t off, + rt_uint32_t mask, rt_uint32_t expect, rt_uint32_t timeout_us) +{ + while ((rk_crypto_readl(rc, off) & mask) != expect) + { + if (timeout_us == 0) + { + return -RT_ETIMEOUT; + } + + rt_hw_us_delay(1); + timeout_us--; + } + + return RT_EOK; +} + +static rt_err_t rk_crypto_wait_reg_clear(struct rockchip_crypto *rc, rt_uint32_t off) +{ + return rk_crypto_poll_reg(rc, off, 0xffffffffu, 0, RK_CRYPTO_TIMEOUT_US); +} + +static void rk_crypto_dcache_clean(const void *addr, rt_size_t size) +{ + rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, (void *)addr, size); +} + +static void rk_crypto_dcache_invalidate(void *addr, rt_size_t size) +{ + rt_hw_cpu_dcache_ops(RT_HW_CACHE_INVALIDATE, addr, size); +} + +static rt_uint32_t rk_crypto_byte2word_be(const rt_uint8_t *ch) +{ + return ((rt_uint32_t)ch[0] << 24) | ((rt_uint32_t)ch[1] << 16) | + ((rt_uint32_t)ch[2] << 8) | ch[3]; +} + +static void rk_crypto_word2byte_be(rt_uint32_t word, rt_uint8_t *ch) +{ + ch[0] = (word >> 24) & 0xff; + ch[1] = (word >> 16) & 0xff; + ch[2] = (word >> 8) & 0xff; + ch[3] = word & 0xff; +} + +static void rk_crypto_write_regs(struct rockchip_crypto *rc, rt_uint32_t base, + const rt_uint8_t *data, rt_size_t len) +{ + rt_uint8_t tmp[4]; + rt_size_t i; + + for (i = 0; i + 4 <= len; i += 4) + { + rk_crypto_writel(rc, rk_crypto_byte2word_be(data + i), base + i); + } + + if (len % 4) + { + rt_memset(tmp, 0, sizeof(tmp)); + rt_memcpy(tmp, data + i, len % 4); + rk_crypto_writel(rc, rk_crypto_byte2word_be(tmp), base + i); + } +} + +static void rk_crypto_read_regs(struct rockchip_crypto *rc, rt_uint32_t base, + rt_uint8_t *data, rt_size_t len) +{ + rt_uint8_t tmp[4]; + rt_size_t i; + + for (i = 0; i + 4 <= len; i += 4) + { + rk_crypto_word2byte_be(rk_crypto_readl(rc, base + i), data + i); + } + + if (len % 4) + { + rk_crypto_word2byte_be(rk_crypto_readl(rc, base + i), tmp); + rt_memcpy(data + i, tmp, len % 4); + } +} + +static void rk_crypto_clear_regs(struct rockchip_crypto *rc, rt_uint32_t base, rt_uint32_t words) +{ + rt_uint32_t i; + + for (i = 0; i < words; i++) + { + rk_crypto_writel(rc, 0, base + i * 4); + } +} + +static rt_err_t rk_crypto_hw_reset(struct rockchip_crypto *rc) +{ + rt_uint32_t val = CRYPTO_SW_CC_RESET; + + rk_crypto_writel(rc, val | (val << CRYPTO_WRITE_MASK_SHIFT), CRYPTO_RST_CTL); + + return rk_crypto_wait_reg_clear(rc, CRYPTO_RST_CTL); +} + +static rt_err_t rk_crypto_wait_dma(struct rockchip_crypto *rc, rt_uint32_t expect) +{ + rt_uint32_t st; + rt_err_t err; + + err = rk_crypto_poll_reg(rc, CRYPTO_DMA_INT_ST, expect, expect, RK_CRYPTO_TIMEOUT_US); + if (err) + { + return err; + } + + st = rk_crypto_readl(rc, CRYPTO_DMA_INT_ST); + rk_crypto_writel(rc, st, CRYPTO_DMA_INT_ST); + + if (st & (CRYPTO_LIST_ERR_INT_ST | CRYPTO_SRC_ERR_INT_ST | CRYPTO_DST_ERR_INT_ST)) + { + return -RT_EIO; + } + + if ((st & expect) == 0) + { + return -RT_EIO; + } + + return RT_EOK; +} + +static rt_err_t rk_crypto_hash_feed(struct rockchip_crypto *rc, + struct rk_crypto_hash_ctx *hctx, const rt_uint8_t *data, + rt_size_t len, rt_bool_t is_last) +{ + struct rk_crypto_lli *lli = &hctx->lli; + rt_uint32_t dma_ctl; + rt_err_t err; + + if (!is_last && (len % RK_CRYPTO_HASH_BLOCK)) + { + return -RT_EINVAL; + } + + rt_memset(lli, 0, sizeof(*lli)); + lli->src_addr = rk_crypto_virt_to_phys(data); + lli->src_len = len; + lli->dma_ctrl = LLI_DMA_CTRL_SRC_DONE; + + if (is_last) + { + lli->user_define |= LLI_USER_STRING_LAST; + lli->dma_ctrl |= LLI_DMA_CTRL_LAST; + } + else + { + lli->next_addr = rk_crypto_virt_to_phys(lli); + lli->dma_ctrl |= LLI_DMA_CTRL_PAUSE; + } + + if (!hctx->started) + { + lli->user_define |= LLI_USER_STRING_START | LLI_USER_CIPHER_START; + rk_crypto_writel(rc, rk_crypto_virt_to_phys(lli), CRYPTO_DMA_LLI_ADDR); + rk_crypto_write_masked(rc, CRYPTO_HASH_CTL, CRYPTO_HASH_ENABLE); + dma_ctl = CRYPTO_DMA_START; + hctx->started = RT_TRUE; + } + else + { + dma_ctl = CRYPTO_DMA_RESTART; + } + + rk_crypto_dcache_clean(lli, sizeof(*lli)); + rk_crypto_dcache_clean(data, len); + + rk_crypto_write_masked(rc, CRYPTO_DMA_CTL, dma_ctl); + + err = rk_crypto_wait_dma(rc, CRYPTO_SRC_ITEM_DONE_INT_ST | CRYPTO_ZERO_LEN_INT_ST); + + return err; +} + +static rt_err_t rk_crypto_hash_hw_init(struct rockchip_crypto *rc, + struct rk_crypto_hash_ctx *hctx, hwcrypto_type type) +{ + rt_uint32_t reg_ctrl = 0; + rt_err_t err; + + err = rk_crypto_hw_reset(rc); + if (err) + { + return err; + } + + switch (type) + { + case HWCRYPTO_TYPE_SHA1: + reg_ctrl |= CRYPTO_SHA1; + hctx->digest_size = 20; + break; + case HWCRYPTO_TYPE_SHA224: + reg_ctrl |= CRYPTO_SHA224; + hctx->digest_size = 28; + break; + case HWCRYPTO_TYPE_SHA256: + reg_ctrl |= CRYPTO_SHA256; + hctx->digest_size = 32; + break; + case HWCRYPTO_TYPE_SHA384: + reg_ctrl |= CRYPTO_SHA384; + hctx->digest_size = 48; + break; + case HWCRYPTO_TYPE_SHA512: + reg_ctrl |= CRYPTO_SHA512; + hctx->digest_size = 64; + break; + case HWCRYPTO_TYPE_MD5: + reg_ctrl |= CRYPTO_MD5; + hctx->digest_size = 16; + break; + default: + return -RT_ENOSYS; + } + + if (hctx->is_hmac && hctx->hmac_key_len == 0) + { + return -RT_EINVAL; + } + + rk_crypto_clear_regs(rc, CRYPTO_HASH_DOUT_0, 16); + + reg_ctrl |= CRYPTO_HW_PAD_ENABLE; + if (hctx->is_hmac) + { + reg_ctrl |= CRYPTO_HMAC_ENABLE; + } + rk_crypto_write_masked(rc, CRYPTO_HASH_CTL, reg_ctrl); + + if (hctx->is_hmac) + { + rk_crypto_clear_regs(rc, CRYPTO_CH0_KEY_0, 8); + rk_crypto_write_regs(rc, CRYPTO_CH0_KEY_0, hctx->hmac_key, hctx->hmac_key_len); + } + rk_crypto_write_masked(rc, CRYPTO_FIFO_CTL, + CRYPTO_DOUT_BYTESWAP | CRYPTO_DOIN_BYTESWAP); + rk_crypto_writel(rc, 0, CRYPTO_DMA_INT_EN); + + hctx->magic = RK_CRYPTO_HASH_CTX_MAGIC; + hctx->started = RT_FALSE; + hctx->leftover_len = 0; + + return RT_EOK; +} + +static rt_err_t rk_crypto_hash_update(struct hwcrypto_hash *ctx, + const rt_uint8_t *in, rt_size_t length) +{ + struct rockchip_crypto *rc = rk_crypto_from_hwdev(ctx->parent.device); + struct rk_crypto_hash_ctx *hctx = ctx->parent.contex; + rt_uint8_t *buf = RT_NULL; + rt_size_t buf_len = 0; + rt_size_t offset = 0; + rt_err_t err = RT_EOK; + + if (!hctx) + { + return -RT_EINVAL; + } + + if (hctx->magic && hctx->magic != RK_CRYPTO_HASH_CTX_MAGIC) + { + return -RT_EINVAL; + } + + rt_mutex_take(&rc->mutex, RT_WAITING_FOREVER); + + if (hctx->digest_size == 0) + { + err = rk_crypto_hash_hw_init(rc, hctx, ctx->parent.type); + if (err) + { + goto _out; + } + } + + if (hctx->leftover_len) + { + buf_len = hctx->leftover_len + length; + buf = rt_malloc(buf_len); + if (!buf) + { + err = -RT_ENOMEM; + goto _out; + } + + rt_memcpy(buf, hctx->leftover, hctx->leftover_len); + rt_memcpy(buf + hctx->leftover_len, in, length); + hctx->leftover_len = 0; + in = buf; + length = buf_len; + } + + while (offset + RK_CRYPTO_HASH_BLOCK <= length) + { + err = rk_crypto_hash_feed(rc, hctx, in + offset, + RK_CRYPTO_HASH_BLOCK, RT_FALSE); + if (err) + { + goto _out; + } + offset += RK_CRYPTO_HASH_BLOCK; + } + + if (offset < length) + { + hctx->leftover_len = length - offset; + rt_memcpy(hctx->leftover, in + offset, hctx->leftover_len); + } + +_out: + if (buf) + { + rt_free(buf); + } + rt_mutex_release(&rc->mutex); + + return err; +} + +static rt_err_t rk_crypto_hash_finish(struct hwcrypto_hash *ctx, + rt_uint8_t *out, rt_size_t length) +{ + struct rockchip_crypto *rc = rk_crypto_from_hwdev(ctx->parent.device); + struct rk_crypto_hash_ctx *hctx = ctx->parent.contex; + rt_err_t err; + + if (!out || !hctx) + { + return -RT_EINVAL; + } + + if (hctx->magic && hctx->magic != RK_CRYPTO_HASH_CTX_MAGIC) + { + return -RT_EINVAL; + } + + rt_mutex_take(&rc->mutex, RT_WAITING_FOREVER); + + if (hctx->digest_size == 0) + { + err = rk_crypto_hash_hw_init(rc, hctx, ctx->parent.type); + if (err) + { + goto _out; + } + } + + if (length < hctx->digest_size) + { + err = -RT_EINVAL; + goto _out; + } + + err = rk_crypto_hash_feed(rc, hctx, hctx->leftover, hctx->leftover_len, RT_TRUE); + if (err) + { + goto _out; + } + + err = rk_crypto_poll_reg(rc, CRYPTO_HASH_VALID, + CRYPTO_HASH_IS_VALID, CRYPTO_HASH_IS_VALID, RK_CRYPTO_TIMEOUT_US); + if (err) + { + goto _out; + } + + rk_crypto_read_regs(rc, CRYPTO_HASH_DOUT_0, out, hctx->digest_size); + rk_crypto_writel(rc, CRYPTO_HASH_IS_VALID, CRYPTO_HASH_VALID); + rk_crypto_write_masked(rc, CRYPTO_HASH_CTL, 0); + + hctx->digest_size = 0; + hctx->magic = 0; + +_out: + rt_mutex_release(&rc->mutex); + + return err; +} + +static rt_err_t rk_crypto_set_pc_len(struct rockchip_crypto *rc, rt_uint32_t chn, rt_uint64_t len) +{ + rt_uint32_t base = CRYPTO_CH0_PC_LEN_0 + chn * 8; + + rk_crypto_writel(rc, (rt_uint32_t)len, base); + rk_crypto_writel(rc, (rt_uint32_t)(len >> 32), base + 4); + + return RT_EOK; +} + +static rt_err_t rk_crypto_set_aad_len(struct rockchip_crypto *rc, rt_uint32_t chn, rt_uint64_t len) +{ + rt_uint32_t base = CRYPTO_CH0_AAD_LEN_0 + chn * 8; + + rk_crypto_writel(rc, (rt_uint32_t)len, base); + rk_crypto_writel(rc, (rt_uint32_t)(len >> 32), base + 4); + + return RT_EOK; +} + +static rt_err_t rk_crypto_read_tag(struct rockchip_crypto *rc, rt_uint32_t chn, + rt_uint8_t *tag, rt_size_t tag_len) +{ + rt_uint32_t base = CRYPTO_CH0_TAG_0 + chn * 0x10; + + rk_crypto_read_regs(rc, base, tag, tag_len); + return RT_EOK; +} + +static rt_err_t rk_crypto_wait_tag_valid(struct rockchip_crypto *rc, rt_uint32_t chn) +{ + rt_uint32_t mask = CRYPTO_CH0_TAG_VALID << chn; + + return rk_crypto_poll_reg(rc, CRYPTO_TAG_VALID, mask, mask, RK_CRYPTO_TIMEOUT_US); +} + +static rt_err_t rk_crypto_decode_sym_type(hwcrypto_type type, rt_uint32_t *bc_alg, + rt_uint32_t *bc_mode, rt_size_t *block_size, rt_bool_t *need_iv, rt_bool_t *ctr_mode) +{ + rt_uint32_t sub = (type >> 8) & 0xff; + + *ctr_mode = RT_FALSE; + *need_iv = RT_TRUE; + + switch (type & HWCRYPTO_MAIN_TYPE_MASK) + { + case HWCRYPTO_TYPE_AES: + *bc_alg = CRYPTO_BC_AES; + *block_size = RK_CRYPTO_AES_BLOCK; + break; + case HWCRYPTO_TYPE_DES: + *bc_alg = CRYPTO_BC_DES; + *block_size = RK_CRYPTO_DES_BLOCK; + break; + case HWCRYPTO_TYPE_3DES: + *bc_alg = CRYPTO_BC_TDES; + *block_size = RK_CRYPTO_DES_BLOCK; + break; + default: + return -RT_ENOSYS; + } + + switch (sub) + { + case 0x01: + *bc_mode = CRYPTO_BC_ECB; + *need_iv = RT_FALSE; + break; + case 0x02: + *bc_mode = CRYPTO_BC_CBC; + break; + case 0x03: + *bc_mode = CRYPTO_BC_CFB; + break; + case 0x04: + *bc_mode = CRYPTO_BC_CTR; + *ctr_mode = RT_TRUE; + break; + case 0x05: + *bc_mode = CRYPTO_BC_OFB; + break; + default: + return -RT_ENOSYS; + } + + return RT_EOK; +} + +static rt_err_t rk_crypto_decode_gcm_alg(hwcrypto_type crypt_type, rt_uint32_t *bc_alg) +{ + switch (crypt_type & HWCRYPTO_MAIN_TYPE_MASK) + { + case HWCRYPTO_TYPE_AES: + *bc_alg = CRYPTO_BC_AES; + return RT_EOK; + default: + return -RT_ENOSYS; + } +} + +static rt_err_t rk_crypto_cipher_setup(struct rockchip_crypto *rc, + struct hwcrypto_symmetric *sym, hwcrypto_type effective_type, + hwcrypto_mode mode, rt_bool_t gcm_mode) +{ + rt_uint32_t bc_alg, bc_mode; + rt_size_t block_size; + rt_bool_t need_iv, ctr_mode; + rt_uint32_t reg_ctrl = 0; + rt_uint32_t key_len = sym->key_bitlen >> 3; + rt_err_t err; + + if (gcm_mode) + { + err = rk_crypto_decode_gcm_alg(effective_type, &bc_alg); + if (err) + { + return err; + } + bc_mode = CRYPTO_BC_GCM; + block_size = RK_CRYPTO_AES_BLOCK; + need_iv = RT_TRUE; + ctr_mode = RT_FALSE; + } + else + { + err = rk_crypto_decode_sym_type(effective_type, &bc_alg, &bc_mode, + &block_size, &need_iv, &ctr_mode); + if (err) + { + return err; + } + } + + reg_ctrl |= bc_alg | bc_mode; + + if (bc_alg == CRYPTO_BC_AES) + { + switch (key_len) + { + case 16: + reg_ctrl |= CRYPTO_BC_128_bit_key; + break; + case 24: + reg_ctrl |= CRYPTO_BC_192_bit_key; + break; + case 32: + reg_ctrl |= CRYPTO_BC_256_bit_key; + break; + default: + return -RT_EINVAL; + } + } + else if (bc_alg == CRYPTO_BC_DES) + { + if (key_len != RK_CRYPTO_DES_BLOCK) + { + return -RT_EINVAL; + } + } + else if (bc_alg == CRYPTO_BC_TDES) + { + if (key_len != 16 && key_len != 24) + { + return -RT_EINVAL; + } + } + + if (mode == HWCRYPTO_MODE_DECRYPT) + { + reg_ctrl |= CRYPTO_BC_DECRYPT; + } + + rk_crypto_clear_regs(rc, CRYPTO_CH0_KEY_0, 8); + rk_crypto_write_regs(rc, CRYPTO_CH0_KEY_0, sym->key, key_len); + + if (need_iv || gcm_mode) + { + if (!sym->iv_len || sym->iv_len > RK_CRYPTO_AES_BLOCK) + { + return -RT_EINVAL; + } + rk_crypto_clear_regs(rc, CRYPTO_CH0_IV_0, 4); + rk_crypto_write_regs(rc, CRYPTO_CH0_IV_0, sym->iv, sym->iv_len); + rk_crypto_writel(rc, sym->iv_len, CRYPTO_CH0_IV_LEN_0); + } + + rk_crypto_write_masked(rc, CRYPTO_FIFO_CTL, + CRYPTO_DOUT_BYTESWAP | CRYPTO_DOIN_BYTESWAP); + rk_crypto_writel(rc, 0, CRYPTO_DMA_INT_EN); + rk_crypto_write_masked(rc, CRYPTO_BC_CTL, reg_ctrl); + + return RT_EOK; +} + +static rt_err_t rk_crypto_cipher_dma(struct rockchip_crypto *rc, + const rt_uint8_t *in, rt_uint8_t *out, rt_size_t in_len, rt_size_t out_len, + struct rk_crypto_lli *aad_lli, rt_size_t aad_len) +{ + struct rk_crypto_lli lli; + rt_uint8_t *dma_in = RT_NULL; + rt_uint8_t *dma_out = RT_NULL; + rt_err_t err; + + if (((rt_ubase_t)in % RK_CRYPTO_DATA_ALIGN) == 0) + { + dma_in = (rt_uint8_t *)in; + } + else + { + dma_in = rt_malloc_align(in_len, RK_CRYPTO_DATA_ALIGN); + if (!dma_in) + { + return -RT_ENOMEM; + } + rt_memcpy(dma_in, in, in_len); + } + + if (out) + { + if (((rt_ubase_t)out % RK_CRYPTO_DATA_ALIGN) == 0) + { + dma_out = out; + } + else + { + dma_out = rt_malloc_align(out_len, RK_CRYPTO_DATA_ALIGN); + if (!dma_out) + { + err = -RT_ENOMEM; + goto _out; + } + } + } + + rt_memset(&lli, 0, sizeof(lli)); + lli.src_addr = rk_crypto_virt_to_phys(dma_in); + lli.src_len = in_len; + if (dma_out) + { + lli.dst_addr = rk_crypto_virt_to_phys(dma_out); + lli.dst_len = out_len; + } + lli.dma_ctrl = LLI_DMA_CTRL_LAST | LLI_DMA_CTRL_DST_DONE; + lli.user_define = LLI_USER_CIPHER_START | LLI_USER_STRING_START | LLI_USER_STRING_LAST; + + if (aad_lli && aad_len) + { + aad_lli->next_addr = rk_crypto_virt_to_phys(&lli); + aad_lli->user_define = LLI_USER_CIPHER_START | LLI_USER_STRING_START | + LLI_USER_STRING_LAST | LLI_USER_STRING_AAD; + rk_crypto_dcache_clean(aad_lli, sizeof(*aad_lli)); + rk_crypto_writel(rc, rk_crypto_virt_to_phys(aad_lli), CRYPTO_DMA_LLI_ADDR); + lli.user_define = LLI_USER_STRING_START | LLI_USER_STRING_LAST; + } + else + { + rk_crypto_writel(rc, rk_crypto_virt_to_phys(&lli), CRYPTO_DMA_LLI_ADDR); + } + + rk_crypto_dcache_clean(&lli, sizeof(lli)); + rk_crypto_dcache_clean(dma_in, in_len); + if (dma_out) + { + rk_crypto_dcache_invalidate(dma_out, out_len); + } + + rk_crypto_write_masked(rc, CRYPTO_BC_CTL, + rk_crypto_readl(rc, CRYPTO_BC_CTL) | CRYPTO_BC_ENABLE); + rk_crypto_write_masked(rc, CRYPTO_DMA_CTL, CRYPTO_DMA_START); + + err = rk_crypto_wait_dma(rc, CRYPTO_DST_ITEM_DONE_INT_ST); + if (err) + { + goto _out; + } + + if (dma_out) + { + rk_crypto_dcache_invalidate(dma_out, out_len); + if (dma_out != out) + { + rt_memcpy(out, dma_out, out_len); + } + } + +_out: + if (dma_in && dma_in != in) + { + rt_free_align(dma_in); + } + if (dma_out && dma_out != out) + { + rt_free_align(dma_out); + } + + return err; +} + +static rt_err_t rk_crypto_cipher_crypt(struct hwcrypto_symmetric *sym, + struct hwcrypto_symmetric_info *info) +{ + struct rockchip_crypto *rc = rk_crypto_from_hwdev(sym->parent.device); + hwcrypto_type effective_type = sym->parent.type; + rt_size_t block_size = RK_CRYPTO_AES_BLOCK; + const rt_uint8_t *in_buf = info->in; + rt_uint8_t *out_buf = info->out; + rt_uint8_t *tmp_in = RT_NULL; + rt_uint8_t *tmp_out = RT_NULL; + rt_bool_t need_iv, ctr_mode; + rt_uint32_t bc_alg, bc_mode; + rt_size_t tmp_len; + rt_err_t err; + + if (!info->length) + { + return -RT_EINVAL; + } + + if ((effective_type & HWCRYPTO_MAIN_TYPE_MASK) == HWCRYPTO_TYPE_GCM) + { + struct hwcrypto_gcm *gcm = (struct hwcrypto_gcm *)sym; + effective_type = gcm->crypt_type; + } + + err = rk_crypto_decode_sym_type(effective_type, &bc_alg, &bc_mode, + &block_size, &need_iv, &ctr_mode); + if (err) + { + return err; + } + + if (ctr_mode) + { + tmp_len = (info->length + block_size - 1) / block_size * block_size; + } + else if (info->length % block_size) + { + return -RT_EINVAL; + } + else + { + tmp_len = info->length; + } + + if (ctr_mode && tmp_len != info->length) + { + tmp_in = rt_calloc(1, tmp_len); + tmp_out = rt_malloc(tmp_len); + if (!tmp_in || !tmp_out) + { + err = -RT_ENOMEM; + goto _cleanup; + } + + rt_memcpy(tmp_in, info->in, info->length); + in_buf = tmp_in; + out_buf = tmp_out; + } + + rt_mutex_take(&rc->mutex, RT_WAITING_FOREVER); + + err = rk_crypto_cipher_setup(rc, sym, effective_type, info->mode, RT_FALSE); + if (err) + { + goto _out; + } + + err = rk_crypto_cipher_dma(rc, in_buf, out_buf, tmp_len, tmp_len, RT_NULL, 0); + +_out: + rt_mutex_release(&rc->mutex); + +_cleanup: + if (!err && tmp_out) + { + rt_memcpy(info->out, tmp_out, info->length); + } + if (tmp_in) + { + rt_free(tmp_in); + } + if (tmp_out) + { + rt_free(tmp_out); + } + + return err; +} + +static rt_err_t rk_crypto_gcm_start(struct hwcrypto_gcm *gcm, + const rt_uint8_t *add, rt_size_t add_len) +{ + struct rockchip_crypto *rc = rk_crypto_from_hwdev(gcm->parent.parent.device); + struct rk_crypto_gcm_ctx *gctx = gcm->parent.parent.contex; + rt_err_t err; + + if (!gctx || (add_len && !add)) + { + return -RT_EINVAL; + } + + if (gctx->aad) + { + rt_free(gctx->aad); + gctx->aad = RT_NULL; + } + + gctx->aad_len = add_len; + gctx->started = RT_FALSE; + gctx->aad_done = RT_FALSE; + gctx->mode = HWCRYPTO_MODE_ENCRYPT; + + if (add_len) + { + gctx->aad = rt_malloc(add_len); + if (!gctx->aad) + { + return -RT_ENOMEM; + } + rt_memcpy(gctx->aad, add, add_len); + } + + rt_mutex_take(&rc->mutex, RT_WAITING_FOREVER); + err = rk_crypto_hw_reset(rc); + rt_mutex_release(&rc->mutex); + + return err; +} + +static rt_err_t rk_crypto_gcm_finish(struct hwcrypto_gcm *gcm, + const rt_uint8_t *tag, rt_size_t tag_len) +{ + struct rockchip_crypto *rc = rk_crypto_from_hwdev(gcm->parent.parent.device); + struct rk_crypto_gcm_ctx *gctx = gcm->parent.parent.contex; + rt_uint8_t hw_tag[RK_CRYPTO_AES_BLOCK]; + rt_err_t err; + + if (!gctx || !tag || !tag_len || tag_len > RK_CRYPTO_AES_BLOCK) + { + return -RT_EINVAL; + } + + gctx->tag_len = tag_len; + + rt_mutex_take(&rc->mutex, RT_WAITING_FOREVER); + + err = rk_crypto_wait_tag_valid(rc, 0); + if (err) + { + goto _out; + } + + rk_crypto_read_tag(rc, 0, hw_tag, tag_len); + + if (gctx->mode == HWCRYPTO_MODE_DECRYPT) + { + if (rt_memcmp(hw_tag, tag, tag_len) != 0) + { + err = -RT_EINVAL; + } + } + else + { + rt_memcpy((rt_uint8_t *)tag, hw_tag, tag_len); + } + +_out: + rt_mutex_release(&rc->mutex); + + return err; +} + +static rt_err_t rk_crypto_gcm_crypt_locked(struct hwcrypto_gcm *gcm, + hwcrypto_mode mode, rt_size_t length, const rt_uint8_t *in, rt_uint8_t *out) +{ + struct rockchip_crypto *rc = rk_crypto_from_hwdev(gcm->parent.parent.device); + struct rk_crypto_gcm_ctx *gctx = gcm->parent.parent.contex; + struct rk_crypto_lli aad_lli; + rt_uint8_t *aad_dma = RT_NULL; + rt_err_t err; + + if (!gctx) + { + return -RT_EINVAL; + } + + gctx->mode = mode; + + if (!gctx->started) + { + err = rk_crypto_cipher_setup(rc, &gcm->parent, gcm->crypt_type, mode, RT_TRUE); + if (err) + { + return err; + } + + if (gctx->aad_len) + { + rk_crypto_set_aad_len(rc, 0, gctx->aad_len); + rk_crypto_set_pc_len(rc, 0, length); + + if (((rt_ubase_t)gctx->aad % RK_CRYPTO_DATA_ALIGN) == 0) + { + aad_dma = gctx->aad; + } + else + { + aad_dma = rt_malloc_align(gctx->aad_len, RK_CRYPTO_DATA_ALIGN); + if (!aad_dma) + { + return -RT_ENOMEM; + } + rt_memcpy(aad_dma, gctx->aad, gctx->aad_len); + } + + rt_memset(&aad_lli, 0, sizeof(aad_lli)); + aad_lli.src_addr = rk_crypto_virt_to_phys(aad_dma); + aad_lli.src_len = gctx->aad_len; + rk_crypto_dcache_clean(aad_dma, gctx->aad_len); + } + + gctx->started = RT_TRUE; + } + else + { + rk_crypto_set_pc_len(rc, 0, length); + } + + err = rk_crypto_cipher_dma(rc, in, out, length, length, + gctx->aad_len ? &aad_lli : RT_NULL, gctx->aad_len); + + if (aad_dma && aad_dma != gctx->aad) + { + rt_free_align(aad_dma); + } + + return err; +} + +static rt_err_t rk_crypto_gcm_crypt_wrapper(struct hwcrypto_symmetric *sym, + struct hwcrypto_symmetric_info *info) +{ + struct hwcrypto_gcm *gcm = (struct hwcrypto_gcm *)sym; + struct rockchip_crypto *rc = rk_crypto_from_hwdev(sym->parent.device); + rt_err_t err; + + rt_mutex_take(&rc->mutex, RT_WAITING_FOREVER); + err = rk_crypto_gcm_crypt_locked(gcm, info->mode, info->length, info->in, info->out); + rt_mutex_release(&rc->mutex); + + return err; +} + +static const struct hwcrypto_hash_ops rk_crypto_hash_ops = +{ + .update = rk_crypto_hash_update, + .finish = rk_crypto_hash_finish, +}; + +static const struct hwcrypto_symmetric_ops rk_crypto_gcm_sym_ops = +{ + .crypt = rk_crypto_gcm_crypt_wrapper, +}; + +static const struct hwcrypto_symmetric_ops rk_crypto_sym_ops = +{ + .crypt = rk_crypto_cipher_crypt, +}; + +static const struct hwcrypto_gcm_ops rk_crypto_gcm_ops = +{ + .start = rk_crypto_gcm_start, + .finish = rk_crypto_gcm_finish, +}; + +static rt_bool_t rk_crypto_is_hash_type(hwcrypto_type type) +{ + switch (type & HWCRYPTO_MAIN_TYPE_MASK) + { + case HWCRYPTO_TYPE_MD5: + case HWCRYPTO_TYPE_SHA1: + case HWCRYPTO_TYPE_SHA2: + return RT_TRUE; + default: + return RT_FALSE; + } +} + +static rt_err_t rockchip_crypto_create(struct rt_hwcrypto_ctx *ctx) +{ + switch (ctx->type & HWCRYPTO_MAIN_TYPE_MASK) + { + case HWCRYPTO_TYPE_AES: + case HWCRYPTO_TYPE_DES: + case HWCRYPTO_TYPE_3DES: + ((struct hwcrypto_symmetric *)ctx)->ops = &rk_crypto_sym_ops; + break; + case HWCRYPTO_TYPE_GCM: + ctx->contex = rt_calloc(1, sizeof(struct rk_crypto_gcm_ctx)); + if (!ctx->contex) + { + return -RT_ENOMEM; + } + ((struct hwcrypto_gcm *)ctx)->ops = &rk_crypto_gcm_ops; + ((struct hwcrypto_gcm *)ctx)->parent.ops = &rk_crypto_gcm_sym_ops; + break; + case HWCRYPTO_TYPE_MD5: + case HWCRYPTO_TYPE_SHA1: + case HWCRYPTO_TYPE_SHA2: + ctx->contex = rt_calloc(1, sizeof(struct rk_crypto_hash_ctx)); + if (!ctx->contex) + { + return -RT_ENOMEM; + } + ((struct hwcrypto_hash *)ctx)->ops = &rk_crypto_hash_ops; + break; + case HWCRYPTO_TYPE_BIGNUM: + ((struct hwcrypto_bignum *)ctx)->ops = rk_crypto_bignum_ops_get(); + if (!((struct hwcrypto_bignum *)ctx)->ops) + { + return -RT_ENOSYS; + } + break; + default: + return -RT_ENOSYS; + } + + return RT_EOK; +} + +static void rockchip_crypto_destroy(struct rt_hwcrypto_ctx *ctx) +{ + if ((ctx->type & HWCRYPTO_MAIN_TYPE_MASK) == HWCRYPTO_TYPE_GCM) + { + struct rk_crypto_gcm_ctx *gctx = ctx->contex; + + if (gctx) + { + rt_free(gctx->aad); + } + } + + rt_free(ctx->contex); + ctx->contex = RT_NULL; +} + +static rt_err_t rockchip_crypto_copy(struct rt_hwcrypto_ctx *des, + const struct rt_hwcrypto_ctx *src) +{ + if ((des->type & HWCRYPTO_MAIN_TYPE_MASK) != (src->type & HWCRYPTO_MAIN_TYPE_MASK)) + { + return -RT_EINVAL; + } + + switch (des->type & HWCRYPTO_MAIN_TYPE_MASK) + { + case HWCRYPTO_TYPE_AES: + case HWCRYPTO_TYPE_DES: + case HWCRYPTO_TYPE_3DES: + return RT_EOK; + case HWCRYPTO_TYPE_GCM: + if (src->contex && des->contex) + { + struct rk_crypto_gcm_ctx *dctx = des->contex; + struct rk_crypto_gcm_ctx *sctx = src->contex; + + rt_free(dctx->aad); + dctx->aad = RT_NULL; + if (sctx->aad_len) + { + dctx->aad = rt_malloc(sctx->aad_len); + if (!dctx->aad) + { + return -RT_ENOMEM; + } + rt_memcpy(dctx->aad, sctx->aad, sctx->aad_len); + } + dctx->aad_len = sctx->aad_len; + dctx->tag_len = sctx->tag_len; + dctx->started = sctx->started; + dctx->aad_done = sctx->aad_done; + dctx->mode = sctx->mode; + ((struct hwcrypto_gcm *)des)->crypt_type = ((struct hwcrypto_gcm *)src)->crypt_type; + return RT_EOK; + } + return -RT_EINVAL; + case HWCRYPTO_TYPE_MD5: + case HWCRYPTO_TYPE_SHA1: + case HWCRYPTO_TYPE_SHA2: + if (src->contex && des->contex) + { + rt_memcpy(des->contex, src->contex, sizeof(struct rk_crypto_hash_ctx)); + return RT_EOK; + } + return -RT_EINVAL; + case HWCRYPTO_TYPE_BIGNUM: + return RT_EOK; + default: + return -RT_ENOSYS; + } +} + +static void rockchip_crypto_reset(struct rt_hwcrypto_ctx *ctx) +{ + struct rk_crypto_hash_ctx *hctx = ctx->contex; + + if (rk_crypto_is_hash_type(ctx->type) && hctx) + { + rt_memset(hctx, 0, sizeof(*hctx)); + } + else if ((ctx->type & HWCRYPTO_MAIN_TYPE_MASK) == HWCRYPTO_TYPE_GCM && ctx->contex) + { + struct rk_crypto_gcm_ctx *gctx = ctx->contex; + + rt_free(gctx->aad); + rt_memset(gctx, 0, sizeof(*gctx)); + } +} + +static const struct rt_hwcrypto_ops rockchip_crypto_ops = +{ + .create = rockchip_crypto_create, + .destroy = rockchip_crypto_destroy, + .copy = rockchip_crypto_copy, + .reset = rockchip_crypto_reset, +}; + +static void rockchip_crypto_free(struct rockchip_crypto *rc) +{ + if (rc->regs) + { + rt_iounmap(rc->regs); + } + + if (!rt_is_err_or_null(rc->rstc)) + { + rt_reset_control_assert(rc->rstc); + rt_reset_control_put(rc->rstc); + } + + if (!rt_is_err_or_null(rc->clk_arr)) + { + rt_clk_array_disable_unprepare(rc->clk_arr); + rt_clk_array_put(rc->clk_arr); + } + + rt_mutex_delete(&rc->mutex); + rt_free(rc); +} + +static rt_err_t rockchip_crypto_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + struct rt_device *dev = &pdev->parent; + struct rockchip_crypto *rc = rt_calloc(1, sizeof(*rc)); + + if (!rc) + { + return -RT_ENOMEM; + } + + rt_mutex_init(&rc->mutex, "rk-crypto", RT_IPC_FLAG_PRIO); + + rc->regs = rt_dm_dev_iomap(dev, 0); + if (!rc->regs) + { + err = -RT_EIO; + goto _fail; + } + + rc->rstc = rt_reset_control_get_by_name(dev, "crypto-rst"); + if (!rt_is_err(rc->rstc)) + { + rt_reset_control_assert(rc->rstc); + rt_hw_us_delay(10); + rt_reset_control_deassert(rc->rstc); + } + + rc->clk_arr = rt_clk_get_array(dev); + if (rt_is_err(rc->clk_arr)) + { + err = rt_ptr_err(rc->clk_arr); + goto _fail; + } + + err = rt_clk_array_prepare_enable(rc->clk_arr); + if (err) + { + goto _fail; + } + + dev->user_data = rc; + rc->parent.user_data = rc; + rc->parent.ops = &rockchip_crypto_ops; + + err = rt_hwcrypto_register(&rc->parent, RT_HWCRYPTO_DEFAULT_NAME); + if (err) + { + goto _fail; + } + + rk_crypto_pka_init(rc); + rk_crypto_ecc_init(rc); +#ifdef RT_HWCRYPTO_USING_BIGNUM + rt_hwcrypto_bignum_default(&rc->parent); +#endif + + return RT_EOK; + +_fail: + rockchip_crypto_free(rc); + + return err; +} + +static rt_err_t rockchip_crypto_remove(struct rt_platform_device *pdev) +{ + struct rockchip_crypto *rc = pdev->parent.user_data; + + if (!rc) + { + return RT_EOK; + } + + pdev->parent.user_data = RT_NULL; + rt_device_unregister(&rc->parent.parent); + rockchip_crypto_free(rc); + + return RT_EOK; +} + +static const struct rt_ofw_node_id rockchip_crypto_ids[] = +{ + { .compatible = "rockchip,rk3568-crypto" }, + { .compatible = "rockchip,rk3588-crypto" }, + { /* sentinel */ }, +}; + +static struct rt_platform_driver rockchip_crypto_driver = +{ + .name = "rockchip-crypto-v2", + .ids = rockchip_crypto_ids, + + .probe = rockchip_crypto_probe, + .remove = rockchip_crypto_remove, +}; +RT_PLATFORM_DRIVER_EXPORT(rockchip_crypto_driver); + +#ifdef RT_HWCRYPTO_USING_BIGNUM + +#define CRYPTO_TRACE(...) +#define RK_BN_DEFAULT_ENDIAN RK_BG_LITTILE_ENDIAN +#define RK_BN_BYTES2WORDS(bytes) (((bytes) + sizeof(rt_uint32_t) - 1) / sizeof(rt_uint32_t)) +#define RK_BN_WORDS2BYTES(words) ((words) * sizeof(rt_uint32_t)) +#define RK_BN_WORD_SIZE 32 + +static void rk_reverse_memcpy(void *dst, const void *src, rt_uint32_t size) +{ + char *_dst = (char *)dst; + char *_src = (char *)src; + rt_uint32_t i; + + if (!dst || !src || !size) + { + return; + } + + for (i = 0; i < size; ++i) + { + _dst[size - i - 1] = _src[i]; + } +} + +struct rk_bignum *rk_bn_alloc(rt_uint32_t max_size) +{ + struct rk_bignum *bn; + rt_uint32_t words = RK_BN_BYTES2WORDS(max_size); + + bn = rt_calloc(1, sizeof(*bn)); + if (!bn) + { + return RT_NULL; + } + + bn->data = rt_calloc(words, sizeof(rt_uint32_t)); + if (!bn->data) + { + rt_free(bn); + return RT_NULL; + } + + bn->n_words = words; + + return bn; +} + +void rk_bn_free(struct rk_bignum *bn) +{ + if (!bn) + { + return; + } + + if (bn->data) + { + rt_memset(bn->data, 0, RK_BN_WORDS2BYTES(bn->n_words)); + rt_free(bn->data); + } + + rt_free(bn); +} + +rt_err_t rk_bn_set_data(struct rk_bignum *bn, const rt_uint8_t *data, + rt_uint32_t size, enum rk_bignum_endian endian) +{ + if (!bn || !data) + { + return -RT_EINVAL; + } + + if (RK_BN_BYTES2WORDS(size) > bn->n_words) + { + return -RT_EINVAL; + } + + if (endian == RK_BN_DEFAULT_ENDIAN) + { + rt_memcpy(bn->data, data, size); + } + else + { + rk_reverse_memcpy(bn->data, data, size); + } + + return RT_EOK; +} + +rt_err_t rk_bn_get_data(const struct rk_bignum *bn, rt_uint8_t *data, + rt_uint32_t size, enum rk_bignum_endian endian) +{ + if (!bn || !data) + { + return -RT_EINVAL; + } + + if (size < RK_BN_WORDS2BYTES(bn->n_words)) + { + return -RT_EINVAL; + } + + rt_memset(data, 0, size); + + if (endian == RK_BN_DEFAULT_ENDIAN) + { + rt_memcpy(data + size - RK_BN_WORDS2BYTES(bn->n_words), + bn->data, RK_BN_WORDS2BYTES(bn->n_words)); + } + else + { + rk_reverse_memcpy(data + size - RK_BN_WORDS2BYTES(bn->n_words), + bn->data, RK_BN_WORDS2BYTES(bn->n_words)); + } + + return RT_EOK; +} + +rt_uint32_t rk_bn_get_size(const struct rk_bignum *bn) +{ + if (!bn) + { + return 0; + } + + return RK_BN_WORDS2BYTES(bn->n_words); +} + +int rk_bn_highest_bit(const struct rk_bignum *bn) +{ + rt_uint32_t w; + rt_uint32_t b; + + if (!bn || !bn->data || !bn->n_words) + { + return -1; + } + + w = bn->data[bn->n_words - 1]; + + for (b = 0; b < RK_BN_WORD_SIZE; b++) + { + w >>= 1; + if (w == 0) + { + break; + } + } + + return (int)(bn->n_words - 1) * RK_BN_WORD_SIZE + b; +} + +void rk_ecc_free_point(struct rk_ecp_point *point) +{ + if (!point) + { + return; + } + + rk_bn_free(point->x); + rk_bn_free(point->y); + rt_free(point); +} + +struct rk_ecp_point *rk_ecc_alloc_point_zero(rt_uint32_t max_size) +{ + struct rk_ecp_point *point = rt_calloc(1, sizeof(*point)); + + if (!point) + { + return RT_NULL; + } + + point->x = rk_bn_alloc(max_size); + if (!point->x) + { + goto error; + } + + point->y = rk_bn_alloc(max_size); + if (!point->y) + { + goto error; + } + + return point; + +error: + rk_ecc_free_point(point); + + return RT_NULL; +} + +struct rk_ecp_point *rk_ecc_alloc_point(const rt_uint8_t *x, rt_uint32_t x_len, + const rt_uint8_t *y, rt_uint32_t y_len, + enum rk_bignum_endian endian, rt_uint32_t max_size) +{ + struct rk_ecp_point *point = rt_calloc(1, sizeof(*point)); + + if (!point) + { + return RT_NULL; + } + + point->x = rk_bn_alloc(max_size); + if (!point->x) + { + goto error; + } + + if (rk_bn_set_data(point->x, x, x_len, endian) != RT_EOK) + { + goto error; + } + + point->y = rk_bn_alloc(max_size); + if (!point->y) + { + goto error; + } + + if (rk_bn_set_data(point->y, y, y_len, endian) != RT_EOK) + { + goto error; + } + + return point; + +error: + rk_ecc_free_point(point); + + return RT_NULL; +} + +rt_bool_t rk_ecp_point_is_zero(struct rk_ecp_point *point) +{ + rt_uint32_t i; + rt_bool_t ret = RT_TRUE; + + if (!point || !point->x || !point->y) + { + return RT_FALSE; + } + + for (i = 0; i < point->x->n_words; i++) + { + if (point->x->data[i] != 0) + { + ret = RT_FALSE; + } + } + + for (i = 0; i < point->y->n_words; i++) + { + if (point->y->data[i] != 0) + { + ret = RT_FALSE; + } + } + + return ret; +} + +int rk_pka_expt_mod(struct rk_bignum *in, struct rk_bignum *e, + struct rk_bignum *n, struct rk_bignum *out); + +#define PKA_WORDS2BITS(words) ((words) * 32) +#define PKA_BITS2WORDS(bits) (((bits) + 31) / 32) +#define PKA_WORDS2BYTES(words) ((words) * 4) +#define PKA_BYTES2BITS(bytes) ((bytes) * 8) + +enum +{ + PKA_EXACT_LEN_ID = 0, + PKA_CALC_LEN_ID, + PKA_USED_LEN_MAX, +}; + +#define PKA_POLL_PERIOD_US 1000 +#define PKA_POLL_TIMEOUT_US 50000 +#define PKA_MAX_POLL_PERIOD_US 20000 +#define PKA_MAX_POLL_TIMEOUT_US 2000000 +#define PKA_MAX_CALC_BITS 4096 +#define PKA_MAX_CALC_WORDS PKA_BITS2WORDS(PKA_MAX_CALC_BITS) + +#define PKA_N 0UL +#define PKA_NP 1UL +#define PKA_T0 30UL +#define PKA_T1 31UL +#define PKA_TMP_REG_CNT 2 + +#define PKA_N_NP_T0_T1_REG_DEFAULT \ + (PKA_N << CRYPTO_N_VIRTUAL_ADDR_SHIFT | \ + PKA_NP << CRYPTO_NP_VIRTUAL_ADDR_SHIFT | \ + PKA_T0 << CRYPTO_T0_VIRTUAL_ADDR_SHIFT | \ + PKA_T1 << CRYPTO_T1_VIRTUAL_ADDR_SHIFT) + +#define RES_DISCARD 0x3F +#define PKA_ADDR_NOT_USED 0xFFC + +enum pka_opcode +{ + PKA_OPCODE_ADD = 0x04, + PKA_OPCODE_SUB, + PKA_OPCODE_MOD_ADD, + PKA_OPCODE_MOD_SUB, + PKA_OPCODE_AND, + PKA_OPCODE_OR, + PKA_OPCODE_XOR, + PKA_OPCODE_SHR0 = 0x0C, + PKA_OPCODE_SHR1, + PKA_OPCODE_SHL0, + PKA_OPCODE_SHL1, + PKA_OPCODE_LMUL, + PKA_OPCODE_MOD_MUL, + PKA_OPCODE_MOD_MUL_NR, + PKA_OPCODE_MOD_EXP, + PKA_OPCODE_DIV, + PKA_OPCODE_MOD_INV, + PKA_OPCODE_MOD_DIV, + PKA_OPCODE_HMUL, + PKA_OPCODE_TERMINATE, +}; + +#define PKA_CLK_ENABLE() +#define PKA_CLK_DISABLE() + +#define PKA_READ(offset) HWREG32((rt_uint8_t *)pka_base + (offset)) +#define PKA_WRITE(val, offset) HWREG32((rt_uint8_t *)pka_base + (offset)) = (val) +#define PKA_BIGNUM_WORDS(x) (rk_bn_get_size(x) / sizeof(rt_uint32_t)) + +#define PKA_RAM_FOR_PKA() PKA_WRITE(CRYPTO_RAM_CTL_SEL_MASK | CRYPTO_RAM_CTL_PKA, \ + CRYPTO_RAM_CTL) + +#define PKA_RAM_FOR_CPU() do { \ + PKA_WRITE(CRYPTO_RAM_CTL_SEL_MASK | CRYPTO_RAM_CTL_CPU, CRYPTO_RAM_CTL); \ + while ((PKA_READ(CRYPTO_RAM_ST) & 0x01) != CRYPTO_CLK_RAM_RDY) \ + rt_hw_us_delay(1); \ + } while (0) + +#define PKA_GET_SRAM_ADDR(addr) ((rt_uint32_t *)((rt_uint8_t *)pka_base + CRYPTO_SRAM_BASE + (addr))) +#define PKA_MIN(a, b) ((a) < (b) ? (a) : (b)) + +#define RK_PKA_ADD(op_a, op_b, res) pka_exec_op(PKA_OPCODE_ADD, PKA_CALC_LEN_ID, \ + 0, (op_a), 0, (op_b), 0, (res), 0) +#define RK_PKA_CLR(op_a) pka_exec_op(PKA_OPCODE_AND, PKA_CALC_LEN_ID, \ + 0, (op_a), 1, 0x00, 0, (op_a), 0) +#define RK_PKA_COPY(op_dest, op_src) pka_exec_op(PKA_OPCODE_OR, PKA_CALC_LEN_ID, \ + 0, (op_src), 1, 0x00, 0, (op_dest), 0) +#define RK_PKA_SET_0(op_a, res) pka_exec_op(PKA_OPCODE_OR, PKA_CALC_LEN_ID, \ + 0, (op_a), 1, 0x01, 0, (res), 0) +#define RK_PKA_SHL0(op_a, s, res) pka_exec_op(PKA_OPCODE_SHL0, PKA_CALC_LEN_ID, \ + 0, (op_a), 0, (s), 0, (res), 0) +#define RK_PKA_SHL1(op_a, s, res) pka_exec_op(PKA_OPCODE_SHL1, PKA_CALC_LEN_ID, \ + 0, (op_a), 0, (s), 0, (res), 0) +#define RK_PKA_MOD_EXP(op_a, op_b, res) pka_exec_op(PKA_OPCODE_MOD_EXP, PKA_EXACT_LEN_ID, \ + 0, (op_a), 0, (op_b), 0, (res), 0) +#define RK_PKA_DIV(op_a, op_b, res) pka_exec_op(PKA_OPCODE_DIV, PKA_CALC_LEN_ID, \ + 0, (op_a), 0, (op_b), 0, (res), 0) +#define RK_PKA_TERMINATE() pka_exec_op(PKA_OPCODE_TERMINATE, 0, 0, 0, 0, 0, 0, 0, 0) + +static rt_uint8_t *pka_base; +static struct rockchip_crypto *pka_owner; + +static rt_err_t rk_pka_poll_reg(rt_uint32_t off, rt_uint32_t expect, + rt_uint32_t period_us, rt_uint32_t timeout_us) +{ + rt_uint32_t elapsed = 0; + + while (RT_TRUE) + { + if ((PKA_READ(off) & 1) == expect) + { + return RT_EOK; + } + + if (elapsed >= timeout_us) + { + break; + } + + rt_hw_us_delay(period_us); + elapsed += period_us; + } + + return -RT_ETIMEOUT; +} + +static void pka_word_memcpy(rt_uint32_t *dst, rt_uint32_t *src, rt_uint32_t size) +{ + rt_uint32_t i; + + for (i = 0; i < size; i++) + { + HWREG32((rt_uint8_t *)dst + i * 4) = src[i]; + } +} + +static void pka_word_memset(rt_uint32_t *buff, rt_uint32_t val, rt_uint32_t size) +{ + rt_uint32_t i; + + for (i = 0; i < size; i++) + { + HWREG32((rt_uint8_t *)buff + i * 4) = val; + } +} + +static int pka_wait_pipe_rdy(void) +{ + return rk_pka_poll_reg(CRYPTO_PKA_PIPE_RDY, 1, PKA_POLL_PERIOD_US, PKA_POLL_TIMEOUT_US); +} + +static int pka_wait_done(void) +{ + return rk_pka_poll_reg(CRYPTO_PKA_DONE, 1, PKA_POLL_PERIOD_US, PKA_POLL_TIMEOUT_US); +} + +static int pka_max_wait_done(void) +{ + return rk_pka_poll_reg(CRYPTO_PKA_DONE, 1, PKA_MAX_POLL_PERIOD_US, PKA_MAX_POLL_TIMEOUT_US); +} + +static rt_uint32_t pka_check_status(rt_uint32_t mask) +{ + rt_uint32_t status; + + pka_wait_done(); + status = PKA_READ(CRYPTO_PKA_STATUS); + status = status & mask; + + return !!status; +} + +static void pka_set_len_words(rt_uint32_t words, rt_uint32_t index) +{ + PKA_WRITE(PKA_WORDS2BITS(words), CRYPTO_PKA_L0 + index * sizeof(rt_uint32_t)); +} + +static rt_uint32_t pka_get_len_words(rt_uint32_t index) +{ + pka_wait_done(); + return PKA_BITS2WORDS(PKA_READ(CRYPTO_PKA_L0 + index * sizeof(rt_uint32_t))); +} + +static void pka_set_map_addr(rt_uint32_t addr, rt_uint32_t index) +{ + PKA_WRITE(addr, CRYPTO_MEMORY_MAP0 + sizeof(rt_uint32_t) * index); +} + +static rt_uint32_t pka_get_map_addr(rt_uint32_t index) +{ + pka_wait_done(); + return PKA_READ(CRYPTO_MEMORY_MAP0 + sizeof(rt_uint32_t) * index); +} + +static rt_uint32_t pka_make_full_opcode(rt_uint32_t opcode, rt_uint32_t len_id, + rt_uint32_t is_a_immed, rt_uint32_t op_a, + rt_uint32_t is_b_immed, rt_uint32_t op_b, + rt_uint32_t res_discard, rt_uint32_t res, + rt_uint32_t tag) +{ + rt_uint32_t full_opcode; + + full_opcode = ((opcode & 31) << CRYPTO_OPCODE_CODE_SHIFT | + (len_id & 7) << CRYPTO_OPCODE_LEN_SHIFT | + (is_a_immed & 1) << CRYPTO_OPCODE_A_IMMED_SHIFT | + (op_a & 31) << CRYPTO_OPCODE_A_SHIFT | + (is_b_immed & 1) << CRYPTO_OPCODE_B_IMMED_SHIFT | + (op_b & 31) << CRYPTO_OPCODE_B_SHIFT | + (res_discard & 1) << CRYPTO_OPCODE_R_DIS_SHIFT | + (res & 31) << CRYPTO_OPCODE_R_SHIFT | + (tag & 31) << CRYPTO_OPCODE_TAG_SHIFT); + + return full_opcode; +} + +static void pka_load_data(rt_uint32_t addr, rt_uint32_t *data, rt_uint32_t size_words) +{ + pka_wait_done(); + + PKA_RAM_FOR_CPU(); + pka_word_memcpy(PKA_GET_SRAM_ADDR(addr), data, size_words); + PKA_RAM_FOR_PKA(); +} + +static void pka_clr_mem(rt_uint32_t addr, rt_uint32_t size_words) +{ + pka_wait_done(); + + PKA_RAM_FOR_CPU(); + pka_word_memset(PKA_GET_SRAM_ADDR(addr), 0x00, size_words); + PKA_RAM_FOR_PKA(); +} + +static void pka_read_data(rt_uint32_t addr, rt_uint32_t *data, rt_uint32_t size_words) +{ + pka_wait_done(); + + PKA_RAM_FOR_CPU(); + pka_word_memcpy(data, PKA_GET_SRAM_ADDR(addr), size_words); + PKA_RAM_FOR_PKA(); +} + +static int pka_exec_op(enum pka_opcode opcode, rt_uint8_t len_id, + rt_uint8_t is_a_immed, rt_uint8_t op_a, rt_uint8_t is_b_immed, rt_uint8_t op_b, + rt_uint8_t res_discard, rt_uint8_t res, rt_uint8_t tag) +{ + int ret = 0; + rt_uint32_t full_opcode; + + if (res == RES_DISCARD) + { + res_discard = 1; + res = 0; + } + + full_opcode = pka_make_full_opcode(opcode, len_id, + is_a_immed, op_a, + is_b_immed, op_b, + res_discard, res, tag); + + PKA_WRITE(full_opcode, CRYPTO_OPCODE); + + switch (opcode) + { + case PKA_OPCODE_DIV: + if (pka_check_status(CRYPTO_PKA_DIV_BY_ZERO)) + { + goto end; + } + break; + case PKA_OPCODE_TERMINATE: + ret = pka_wait_done(); + break; + default: + ret = pka_wait_pipe_rdy(); + } +end: + return ret; +} + +static int pk_int_len_tbl(rt_uint32_t exact_size_words, rt_uint32_t calc_size_words) +{ + rt_uint32_t i; + + for (i = 0; i < CRYPTO_LEN_REG_NUM; i++) + { + pka_set_len_words(0, i); + } + + pka_set_len_words(exact_size_words, PKA_EXACT_LEN_ID); + pka_set_len_words(calc_size_words, PKA_CALC_LEN_ID); + + return 0; +} + +static int pka_int_map_tbl(rt_uint32_t *regs_cnt, rt_uint32_t max_size_words) +{ + rt_uint32_t i; + rt_uint32_t cur_addr = 0; + rt_uint32_t max_size_bytes, default_regs_cnt; + + max_size_bytes = PKA_WORDS2BYTES(max_size_words); + default_regs_cnt = PKA_MIN(CRYPTO_MAP_REG_NUM, CRYPTO_SRAM_SIZE / max_size_bytes); + + for (i = 0; i < CRYPTO_MAP_REG_NUM; i++) + { + pka_set_map_addr(PKA_ADDR_NOT_USED, i); + } + + for (i = 0; i < default_regs_cnt - PKA_TMP_REG_CNT; i++, cur_addr += max_size_bytes) + { + pka_set_map_addr(cur_addr, i); + } + + pka_set_map_addr(cur_addr, PKA_T0); + cur_addr += max_size_bytes; + pka_set_map_addr(cur_addr, PKA_T1); + + *regs_cnt = default_regs_cnt; + + PKA_WRITE((rt_uint32_t)PKA_N_NP_T0_T1_REG_DEFAULT, CRYPTO_N_NP_T0_T1_ADDR); + + return 0; +} + +static int pka_clear_regs_block(rt_uint8_t first_reg, rt_uint8_t regs_cnt) +{ + rt_uint32_t i; + rt_uint32_t size_words; + int cnt_tmps = 0; + rt_uint32_t user_reg_num = CRYPTO_MAP_REG_NUM - PKA_TMP_REG_CNT; + + size_words = pka_get_len_words(PKA_CALC_LEN_ID); + + if (first_reg + regs_cnt > user_reg_num) + { + cnt_tmps = PKA_MIN(regs_cnt + first_reg - user_reg_num, PKA_TMP_REG_CNT); + regs_cnt = user_reg_num; + } + else + { + cnt_tmps = PKA_TMP_REG_CNT; + } + + for (i = first_reg; i < regs_cnt; i++) + { + RK_PKA_CLR(i); + } + + pka_wait_done(); + + if (cnt_tmps > 0) + { + pka_clr_mem(pka_get_map_addr(PKA_T0), size_words); + if (cnt_tmps > 1) + { + pka_clr_mem(pka_get_map_addr(PKA_T1), size_words); + } + } + + return 0; +} + +static int pka_init(rt_uint32_t exact_size_words) +{ + int ret; + rt_uint32_t regs_cnt = 0; + rt_uint32_t calc_size_words = exact_size_words + 1; + + PKA_CLK_ENABLE(); + PKA_RAM_FOR_PKA(); + + if (exact_size_words > PKA_MAX_CALC_WORDS) + { + return -1; + } + + ret = pk_int_len_tbl(exact_size_words, calc_size_words); + if (ret) + { + goto exit; + } + + ret = pka_int_map_tbl(®s_cnt, calc_size_words); + if (ret) + { + goto exit; + } + + pka_clear_regs_block(0, regs_cnt - PKA_TMP_REG_CNT); + pka_clr_mem(pka_get_map_addr(PKA_T0), calc_size_words); + pka_clr_mem(pka_get_map_addr(PKA_T1), calc_size_words); + +exit: + return ret; +} + +static void pka_finish(void) +{ + RK_PKA_TERMINATE(); + PKA_RAM_FOR_CPU(); + PKA_CLK_DISABLE(); +} + +static void pka_copy_bn_into_reg(rt_uint8_t dst_reg, struct rk_bignum *bn) +{ + rt_uint32_t cur_addr; + rt_uint32_t size_words, bn_words; + + RK_PKA_TERMINATE(); + + bn_words = PKA_BIGNUM_WORDS(bn); + size_words = pka_get_len_words(PKA_CALC_LEN_ID); + cur_addr = pka_get_map_addr(dst_reg); + + pka_load_data(cur_addr, bn->data, bn_words); + cur_addr += PKA_WORDS2BYTES(bn_words); + + pka_clr_mem(cur_addr, size_words - bn_words); +} + +static int pka_copy_bn_from_reg(struct rk_bignum *bn, rt_uint32_t size_words, + rt_uint8_t src_reg, rt_bool_t is_max_poll) +{ + int ret; + + PKA_WRITE(0, CRYPTO_OPCODE); + + ret = is_max_poll ? pka_max_wait_done() : pka_wait_done(); + if (ret) + { + return ret; + } + + pka_read_data(pka_get_map_addr(src_reg), bn->data, size_words); + + return 0; +} + +static int pka_div_bignum(rt_uint8_t op_a, rt_uint32_t s, rt_uint8_t op_b, + rt_uint8_t res, rt_uint8_t r_t1, rt_uint8_t r_t2) +{ + rt_uint8_t s1; + rt_uint32_t i; + rt_uint32_t n_bits, n_words; + + n_words = ((rt_uint32_t)s + 31) / 32; + n_bits = (rt_uint32_t)s % 32; + + RK_PKA_COPY(r_t1, op_a); + RK_PKA_CLR(res); + + for (i = 0; i < n_words; i++) + { + s1 = i > 0 ? 32 : n_bits; + + if (s1 > 0) + { + RK_PKA_SHL0(r_t1, s1 - 1, r_t1); + } + + RK_PKA_DIV(r_t1, op_b, r_t2); + + if (s1 > 0) + { + RK_PKA_SHL0(res, s1 - 1, res); + } + + RK_PKA_ADD(res, r_t2, res); + } + + pka_wait_done(); + + return 0; +} + +static rt_uint32_t pka_calc_and_init_np(struct rk_bignum *bn, + rt_uint8_t r_t0, rt_uint8_t r_t1, rt_uint8_t r_t2) +{ + int ret; + rt_uint32_t i; + rt_uint32_t s; + rt_uint32_t mod_size_bits; + rt_uint32_t num_bits, num_words; + + s = 132; + mod_size_bits = PKA_BYTES2BITS(rk_bn_get_size(bn)); + + CRYPTO_TRACE("size_bits = %u", mod_size_bits); + + pka_copy_bn_into_reg(PKA_N, bn); + + RK_PKA_CLR(r_t0); + + num_bits = mod_size_bits % 32; + num_words = mod_size_bits / 32; + + CRYPTO_TRACE("num_bits = %u, num_words = %u, size_bits = %u", + num_bits, num_words, mod_size_bits); + + RK_PKA_SET_0(r_t0, r_t0); + + if (num_bits > 0) + { + RK_PKA_SHL0(r_t0, num_bits - 1, r_t0); + } + + for (i = 0; i < num_words; i++) + { + RK_PKA_SHL0(r_t0, 31, r_t0); + } + + ret = pka_div_bignum(r_t0, s, PKA_N, PKA_NP, r_t1, r_t2); + + return ret; +} + +void rk_crypto_pka_init(struct rockchip_crypto *rc) +{ + pka_owner = rc; + pka_base = rc->regs + CRYPTO_PKA_BASE_OFFSET; +} + +static struct rk_bignum *rk_crypto_mpi_to_bn(const struct hw_bignum_mpi *mpi) +{ + struct rk_bignum *bn; + rt_uint32_t len; + + if (!mpi || !mpi->p) + { + return RT_NULL; + } + + len = rt_hwcrypto_bignum_get_len(mpi); + if (!len) + { + return RT_NULL; + } + + bn = rk_bn_alloc(len); + if (!bn) + { + return RT_NULL; + } + + if (rk_bn_set_data(bn, mpi->p, len, RK_BG_BIG_ENDIAN) != RT_EOK) + { + rk_bn_free(bn); + return RT_NULL; + } + + return bn; +} + +static rt_err_t rk_crypto_bn_to_mpi(struct hw_bignum_mpi *mpi, struct rk_bignum *bn) +{ + rt_uint32_t len = rk_bn_get_size(bn); + rt_uint8_t *buf; + rt_err_t err; + + buf = rt_malloc(len); + if (!buf) + { + return -RT_ENOMEM; + } + + err = rk_bn_get_data(bn, buf, len, RK_BG_BIG_ENDIAN); + if (err == RT_EOK) + { + err = rt_hwcrypto_bignum_import_bin(mpi, buf, len) > 0 ? RT_EOK : -RT_ERROR; + } + + rt_free(buf); + + return err; +} + +static rt_err_t rk_crypto_bignum_exptmod(struct hwcrypto_bignum *bignum_ctx, + struct hw_bignum_mpi *x, const struct hw_bignum_mpi *a, + const struct hw_bignum_mpi *b, const struct hw_bignum_mpi *c) +{ + struct rk_bignum *in, *e, *n, *out; + rt_err_t err = -RT_ERROR; + + RT_UNUSED(bignum_ctx); + + if (!pka_owner) + { + return -RT_EINVAL; + } + + in = rk_crypto_mpi_to_bn(a); + e = rk_crypto_mpi_to_bn(b); + n = rk_crypto_mpi_to_bn(c); + out = rk_bn_alloc(rt_hwcrypto_bignum_get_len(c)); + if (!in || !e || !n || !out) + { + goto _out; + } + + rt_mutex_take(&pka_owner->mutex, RT_WAITING_FOREVER); + if (rk_pka_expt_mod(in, e, n, out) == 0) + { + err = rk_crypto_bn_to_mpi(x, out); + } + rt_mutex_release(&pka_owner->mutex); + +_out: + rk_bn_free(in); + rk_bn_free(e); + rk_bn_free(n); + rk_bn_free(out); + + return err; +} + +static const struct hwcrypto_bignum_ops rk_crypto_bignum_ops = +{ + .exptmod = rk_crypto_bignum_exptmod, +}; + +const struct hwcrypto_bignum_ops *rk_crypto_bignum_ops_get(void) +{ + return &rk_crypto_bignum_ops; +} + +int rk_pka_expt_mod(struct rk_bignum *in, + struct rk_bignum *e, + struct rk_bignum *n, + struct rk_bignum *out) +{ + int ret = -1; + rt_uint32_t max_word_size; + rt_bool_t is_max_poll; + rt_uint8_t r_in = 2, r_e = 3, r_out = 4; + rt_uint8_t r_t0 = 2, r_t1 = 3, r_t2 = 4; + + if (!in || !e || !n || !out || PKA_BIGNUM_WORDS(n) == 0) + { + return -1; + } + + max_word_size = PKA_BIGNUM_WORDS(n); + + ret = pka_init(max_word_size); + if (ret) + { + CRYPTO_TRACE("pka_init error\n"); + goto exit; + } + + ret = pka_calc_and_init_np(n, r_t0, r_t1, r_t2); + if (ret) + { + CRYPTO_TRACE("pka_calc_and_init_np error\n"); + goto exit; + } + + pka_clear_regs_block(r_in, 3); + + pka_copy_bn_into_reg(r_in, in); + pka_copy_bn_into_reg(r_e, e); + pka_copy_bn_into_reg(PKA_N, n); + + ret = RK_PKA_MOD_EXP(r_in, r_e, r_out); + if (ret) + { + CRYPTO_TRACE("RK_PKA_MOD_EXP error\n"); + goto exit; + } + + is_max_poll = rk_bn_highest_bit(e) * 2 > rk_bn_highest_bit(n) ? RT_TRUE : RT_FALSE; + + ret = pka_copy_bn_from_reg(out, max_word_size, r_out, is_max_poll); + +exit: + pka_clear_regs_block(0, 5); + pka_clear_regs_block(30, 2); + pka_finish(); + + return ret; +} + +#define RK_ECP_WORDS2BYTES(words) ((words) * sizeof(rt_uint32_t)) +#define RK_ECP_POLL_PERIOD_US 10000 +#define RK_ECP_POLL_TIMEOUT_US 500000 + +#define RK_ECP_WRITE_REG(offset, val) HWREG32(ecc_base + (offset)) = (val) +#define RK_ECP_READ_REG(offset) HWREG32(ecc_base + (offset)) + +#define RK_ECP_RAM_FOR_ECC() RK_ECP_WRITE_REG(RK_ECC_RAM_CTL, \ + RK_ECC_RAM_CTL_SEL_MASK | RK_ECC_RAM_CTL_ECC) +#define RK_ECP_RAM_FOR_CPU() RK_ECP_WRITE_REG(RK_ECC_RAM_CTL, \ + RK_ECC_RAM_CTL_SEL_MASK | RK_ECC_RAM_CTL_CPU) + +#define RK_ECP_LOAD_DATA(dst, big_src) do { \ + ecc_word_memset((dst), 0, RK_ECP_MAX_WORDS); \ + ecc_word_memcpy((dst), (big_src->data), (big_src->n_words)); \ + } while (0) + +#define RK_ECP_LOAD_DATA_EXT(dst, src, n_bytes) do { \ + ecc_word_memset((void *)(dst), 0, RK_ECP_MAX_WORDS); \ + ecc_word_memcpy((void *)(dst), (void *)(src), (n_bytes) / 4); \ + } while (0) + +#define RK_ECP_IS_BIGNUM_INVALID(b) (!b || !b->data || b->n_words < RK_ECP_MAX_WORDS) +#define RK_ECP_IS_POINT_INVALID(p) (RK_ECP_IS_BIGNUM_INVALID((p)->x) && \ + RK_ECP_IS_BIGNUM_INVALID((p)->y)) + +#define RK_LOAD_GROUP_A(G) do { \ + grp->curve_name = #G; \ + grp->wide = G ## _wide; \ + grp->p = G ## _p; \ + grp->p_len = sizeof(G ## _p); \ + grp->a = G ## _a; \ + grp->a_len = sizeof(G ## _a); \ + grp->n = G ## _n; \ + grp->n_len = sizeof(G ## _n); \ + grp->gx = G ## _gx; \ + grp->gx_len = sizeof(G ## _gx); \ + grp->gy = G ## _gy; \ + grp->gy_len = sizeof(G ## _gy); \ + } while (0) + +static rt_uint8_t *ecc_base; +static rt_uint8_t *ecc_sram; + +static const rt_uint32_t secp192r1_wide = RK_ECC_CURVE_WIDE_192; +static const rt_uint8_t secp192r1_p[] = +{ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +}; +static const rt_uint8_t secp192r1_a[] = +{ + 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +}; +static const rt_uint8_t secp192r1_gx[] = +{ + 0x12, 0x10, 0xFF, 0x82, 0xFD, 0x0A, 0xFF, 0xF4, + 0x00, 0x88, 0xA1, 0x43, 0xEB, 0x20, 0xBF, 0x7C, + 0xF6, 0x90, 0x30, 0xB0, 0x0E, 0xA8, 0x8D, 0x18, +}; +static const rt_uint8_t secp192r1_gy[] = +{ + 0x11, 0x48, 0x79, 0x1E, 0xA1, 0x77, 0xF9, 0x73, + 0xD5, 0xCD, 0x24, 0x6B, 0xED, 0x11, 0x10, 0x63, + 0x78, 0xDA, 0xC8, 0xFF, 0x95, 0x2B, 0x19, 0x07, +}; +static const rt_uint8_t secp192r1_n[] = +{ + 0x31, 0x28, 0xD2, 0xB4, 0xB1, 0xC9, 0x6B, 0x14, + 0x36, 0xF8, 0xDE, 0x99, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +}; + +static const rt_uint32_t secp224r1_wide = RK_ECC_CURVE_WIDE_224; +static const rt_uint8_t secp224r1_p[] = +{ + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, +}; +static const rt_uint8_t secp224r1_a[] = +{ + 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, +}; +static const rt_uint8_t secp224r1_gx[] = +{ + 0x21, 0x1D, 0x5C, 0x11, 0xD6, 0x80, 0x32, 0x34, + 0x22, 0x11, 0xC2, 0x56, 0xD3, 0xC1, 0x03, 0x4A, + 0xB9, 0x90, 0x13, 0x32, 0x7F, 0xBF, 0xB4, 0x6B, + 0xBD, 0x0C, 0x0E, 0xB7, +}; +static const rt_uint8_t secp224r1_gy[] = +{ + 0x34, 0x7E, 0x00, 0x85, 0x99, 0x81, 0xD5, 0x44, + 0x64, 0x47, 0x07, 0x5A, 0xA0, 0x75, 0x43, 0xCD, + 0xE6, 0xDF, 0x22, 0x4C, 0xFB, 0x23, 0xF7, 0xB5, + 0x88, 0x63, 0x37, 0xBD, +}; +static const rt_uint8_t secp224r1_n[] = +{ + 0x3D, 0x2A, 0x5C, 0x5C, 0x45, 0x29, 0xDD, 0x13, + 0x3E, 0xF0, 0xB8, 0xE0, 0xA2, 0x16, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, +}; + +static const rt_uint32_t secp256r1_wide = RK_ECC_CURVE_WIDE_256; +static const rt_uint8_t secp256r1_p[] = +{ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, +}; +static const rt_uint8_t secp256r1_a[] = +{ + 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, +}; +static const rt_uint8_t secp256r1_gx[] = +{ + 0x96, 0xC2, 0x98, 0xD8, 0x45, 0x39, 0xA1, 0xF4, + 0xA0, 0x33, 0xEB, 0x2D, 0x81, 0x7D, 0x03, 0x77, + 0xF2, 0x40, 0xA4, 0x63, 0xE5, 0xE6, 0xBC, 0xF8, + 0x47, 0x42, 0x2C, 0xE1, 0xF2, 0xD1, 0x17, 0x6B, +}; +static const rt_uint8_t secp256r1_gy[] = +{ + 0xF5, 0x51, 0xBF, 0x37, 0x68, 0x40, 0xB6, 0xCB, + 0xCE, 0x5E, 0x31, 0x6B, 0x57, 0x33, 0xCE, 0x2B, + 0x16, 0x9E, 0x0F, 0x7C, 0x4A, 0xEB, 0xE7, 0x8E, + 0x9B, 0x7F, 0x1A, 0xFE, 0xE2, 0x42, 0xE3, 0x4F, +}; +static const rt_uint8_t secp256r1_n[] = +{ + 0x51, 0x25, 0x63, 0xFC, 0xC2, 0xCA, 0xB9, 0xF3, + 0x84, 0x9E, 0x17, 0xA7, 0xAD, 0xFA, 0xE6, 0xBC, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, +}; + +static const rt_uint32_t sm2p256v1_wide = RK_ECC_CURVE_WIDE_256; +static const rt_uint8_t sm2p256v1_p[] = +{ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, +}; +static const rt_uint8_t sm2p256v1_a[] = +{ + 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, +}; +static const rt_uint8_t sm2p256v1_gx[] = +{ + 0xC7, 0x74, 0x4C, 0x33, 0x89, 0x45, 0x5A, 0x71, + 0xE1, 0x0B, 0x66, 0xF2, 0xBF, 0x0B, 0xE3, 0x8F, + 0x94, 0xC9, 0x39, 0x6A, 0x46, 0x04, 0x99, 0x5F, + 0x19, 0x81, 0x19, 0x1F, 0x2C, 0xAE, 0xC4, 0x32, +}; +static const rt_uint8_t sm2p256v1_gy[] = +{ + 0xA0, 0xF0, 0x39, 0x21, 0xE5, 0x32, 0xDF, 0x02, + 0x40, 0x47, 0x2A, 0xC6, 0x7C, 0x87, 0xA9, 0xD0, + 0x53, 0x21, 0x69, 0x6B, 0xE3, 0xCE, 0xBD, 0x59, + 0x9C, 0x77, 0xF6, 0xF4, 0xA2, 0x36, 0x37, 0xBC, +}; +static const rt_uint8_t sm2p256v1_n[] = +{ + 0x23, 0x41, 0xD5, 0x39, 0x09, 0xF4, 0xBB, 0x53, + 0x2B, 0x05, 0xC6, 0x21, 0x6B, 0xDF, 0x03, 0x72, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, +}; + +static void dump_ecc_sram(void) +{ +} + +static void ecc_word_memcpy(rt_uint32_t *dst, rt_uint32_t *src, rt_uint32_t size) +{ + rt_uint32_t i; + + for (i = 0; i < size; i++) + { + HWREG32((rt_uint8_t *)dst + i * 4) = src[i]; + } +} + +static void ecc_word_memset(rt_uint32_t *buff, rt_uint32_t val, rt_uint32_t size) +{ + rt_uint32_t i; + + for (i = 0; i < size; i++) + { + HWREG32((rt_uint8_t *)buff + i * 4) = val; + } +} + +static void rk_reverse_buf(rt_uint8_t *buff, rt_uint32_t size) +{ + rt_uint8_t *buf_h_swap, *buf_l_swap; + rt_uint32_t i; + rt_uint32_t temp; + + buf_h_swap = buff + size - 1; + buf_l_swap = buff; + + for (i = 0; i < (size / 2); i++) + { + temp = *buf_h_swap; + *(buf_h_swap--) = *buf_l_swap; + *(buf_l_swap++) = temp; + } +} + +static int rk_word_cmp_zero(rt_uint32_t *buf1, rt_uint32_t n_words) +{ + int ret = 0; + rt_uint32_t i; + + for (i = 0; i < n_words; i++) + { + if (buf1[i] != 0) + { + ret = -RT_EINVAL; + } + } + + return ret; +} + +static int rk_load_hash_bn(struct rk_ecp_group *grp, struct rk_bignum *bn, + rt_uint8_t *hash, rt_uint32_t hash_len) +{ + if (grp == RT_NULL || RK_ECP_IS_BIGNUM_INVALID(bn)) + { + return -RT_EINVAL; + } + + hash_len = hash_len > grp->p_len ? grp->p_len : hash_len; + + rt_memset(bn->data, 0x00, RK_ECP_WORDS2BYTES(bn->n_words)); + rt_memcpy(bn->data, hash, hash_len); + + rk_reverse_buf((void *)bn->data, hash_len); + + return 0; +} + +static int rk_ecp_group_load(struct rk_ecp_group *grp, enum rk_ecp_group_id id) +{ + rt_memset(grp, 0x00, sizeof(*grp)); + + grp->id = id; + grp->endian = RK_BG_LITTILE_ENDIAN; + + switch (id) + { + case RK_ECP_DP_SECP192R1: + RK_LOAD_GROUP_A(secp192r1); + return 0; + case RK_ECP_DP_SECP224R1: + RK_LOAD_GROUP_A(secp224r1); + return 0; + case RK_ECP_DP_SECP256R1: + RK_LOAD_GROUP_A(secp256r1); + return 0; + case RK_ECP_DP_SM2P256V1: + RK_LOAD_GROUP_A(sm2p256v1); + return 0; + default: + return -RT_EINVAL; + } +} + +static int rockchip_ecc_request_set(rt_uint32_t ecc_ctl, rt_uint32_t wide) +{ + RK_ECP_WRITE_REG(RK_ECC_CURVE_WIDE, wide); + RK_ECP_WRITE_REG(RK_ECC_INT_EN, 0); + RK_ECP_WRITE_REG(RK_ECC_INT_ST, RK_ECP_READ_REG(RK_ECC_INT_ST)); + RK_ECP_WRITE_REG(RK_ECC_CTL, ecc_ctl); + + return 0; +} + +static rt_err_t rockchip_ecc_request_wait_done(void) +{ + rt_uint32_t reg_val = 0; + rt_uint32_t elapsed = 0; + rt_err_t err = RT_EOK; + + while (RT_TRUE) + { + reg_val = RK_ECP_READ_REG(RK_ECC_INT_ST); + if (reg_val) + { + break; + } + + if (elapsed >= RK_ECP_POLL_TIMEOUT_US) + { + err = -RT_ETIMEOUT; + goto out; + } + + rt_hw_us_delay(RK_ECP_POLL_PERIOD_US); + elapsed += RK_ECP_POLL_PERIOD_US; + } + + if (RK_ECP_READ_REG(RK_ECC_ABN_ST)) + { + err = -RT_ERROR; + } + +out: + RK_ECP_WRITE_REG(RK_ECC_CTL, 0); + RK_ECP_RAM_FOR_CPU(); + + return err; +} + +static int rockchip_ecc_request_trigger(void) +{ + rt_uint32_t ecc_ctl = RK_ECP_READ_REG(RK_ECC_CTL); + + RK_ECP_RAM_FOR_ECC(); + RK_ECP_WRITE_REG(RK_ECC_CTL, ecc_ctl | RK_ECC_CTL_REQ_ECC); + + return rockchip_ecc_request_wait_done(); +} + +int rockchip_ecc_verify(int group_id, rt_uint8_t *hash, rt_uint32_t hash_len, + struct rk_ecp_point *point_P, struct rk_ecp_point *point_sign) +{ + int ret; + rt_uint32_t curve_sel = 0; + struct rk_bignum *bn_hash = RT_NULL; + struct rk_ecp_group grp; + struct rk_ecc_verify *ecc_st = (struct rk_ecc_verify *)ecc_sram; + + CRYPTO_TRACE("ecc_st = %p, ecc_base = %p\n", ecc_st, ecc_base); + + if (!hash || + RK_ECP_IS_POINT_INVALID(point_P) || + RK_ECP_IS_POINT_INVALID(point_sign)) + { + ret = -RT_EINVAL; + goto exit; + } + + ret = rk_ecp_group_load(&grp, group_id); + if (ret) + { + goto exit; + } + + bn_hash = rk_bn_alloc(RK_ECP_MAX_BYTES); + if (!bn_hash) + { + ret = -RT_ENOMEM; + goto exit; + } + + curve_sel = group_id == RK_ECP_DP_SM2P256V1 ? + RK_ECC_CTL_FUNC_SM2_CURVER : RK_ECC_CTL_FUNC_ECC_CURVER; + + rk_load_hash_bn(&grp, bn_hash, hash, hash_len); + + RK_ECP_LOAD_DATA(ecc_st->e, bn_hash); + RK_ECP_LOAD_DATA(ecc_st->r_, point_sign->x); + RK_ECP_LOAD_DATA(ecc_st->s_, point_sign->y); + RK_ECP_LOAD_DATA(ecc_st->p_x, point_P->x); + RK_ECP_LOAD_DATA(ecc_st->p_y, point_P->y); + RK_ECP_LOAD_DATA_EXT(ecc_st->A, grp.a, grp.a_len); + RK_ECP_LOAD_DATA_EXT(ecc_st->P, grp.p, grp.p_len); + RK_ECP_LOAD_DATA_EXT(ecc_st->N, grp.n, grp.n_len); + RK_ECP_LOAD_DATA_EXT(ecc_st->G_x, grp.gx, grp.gx_len); + RK_ECP_LOAD_DATA_EXT(ecc_st->G_y, grp.gy, grp.gy_len); + + rockchip_ecc_request_set(curve_sel | RK_ECC_CTL_FUNC_SEL_VERIFY, grp.wide); + ret = rockchip_ecc_request_trigger(); + +exit: + if (ret || + rk_word_cmp_zero(ecc_st->v, RK_ECP_MAX_WORDS) || + rk_word_cmp_zero(ecc_st->r_, RK_ECP_MAX_WORDS) == 0) + { + ret = -RT_EINVAL; + dump_ecc_sram(); + } + + rk_bn_free(bn_hash); + + return ret; +} + +void rk_crypto_ecc_init(struct rockchip_crypto *rc) +{ + ecc_base = rc->regs + RK_ECC_BASE_OFFSET; + ecc_sram = ecc_base + SM2_RAM_BASE_OFFSET; + + RK_ECP_WRITE_REG(RK_ECC_DATA_ENDIAN, RK_ECC_DATA_ENDIAN_LITTLE); +} + +rt_err_t rk_crypto_ecc_verify(int group_id, rt_uint8_t *hash, rt_uint32_t hash_len, + struct rk_ecp_point *point_p, struct rk_ecp_point *point_sign) +{ + int ret = rockchip_ecc_verify(group_id, hash, hash_len, point_p, point_sign); + + return ret == 0 ? RT_EOK : ret; +} + +rt_uint32_t rk_crypto_ecc_get_max_size(void) +{ + return RK_ECP_MAX_BYTES; +} + +rt_uint32_t rk_crypto_ecc_get_curve_nbits(rt_uint32_t group_id) +{ + switch (group_id) + { + case RK_ECP_DP_SECP192R1: + return 192; + case RK_ECP_DP_SECP224R1: + return 224; + case RK_ECP_DP_SECP256R1: + case RK_ECP_DP_SM2P256V1: + return 256; + default: + return 0; + } +} + +#endif /* RT_HWCRYPTO_USING_BIGNUM */ diff --git a/bsp/rockchip/dm/hwcrypto/hw-crypto-rockchip-v2.h b/bsp/rockchip/dm/hwcrypto/hw-crypto-rockchip-v2.h new file mode 100644 index 000000000000..3e7331316a7b --- /dev/null +++ b/bsp/rockchip/dm/hwcrypto/hw-crypto-rockchip-v2.h @@ -0,0 +1,326 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-3-08 GuEe-GUI the first version + */ + +#ifndef __HW_CRYPTO_ROCKCHIP_V2_H__ +#define __HW_CRYPTO_ROCKCHIP_V2_H__ + +#include +#include +#include + +#include + +#define _SBF(s, v) ((v) << (s)) + +#define CRYPTO_WRITE_MASK_SHIFT (16) +#define CRYPTO_WRITE_MASK_ALL ((0xffffu << CRYPTO_WRITE_MASK_SHIFT)) + +#define CRYPTO_CLK_CTL 0x0000 +#define CRYPTO_AUTO_CLKGATE_EN RT_BIT(0) + +#define CRYPTO_RST_CTL 0x0004 +#define CRYPTO_SW_PKA_RESET RT_BIT(2) +#define CRYPTO_SW_RNG_RESET RT_BIT(1) +#define CRYPTO_SW_CC_RESET RT_BIT(0) + +#define CRYPTO_DMA_INT_EN 0x0008 +#define CRYPTO_ZERO_ERR_INT_EN RT_BIT(6) +#define CRYPTO_LIST_ERR_INT_EN RT_BIT(5) +#define CRYPTO_SRC_ERR_INT_EN RT_BIT(4) +#define CRYPTO_DST_ERR_INT_EN RT_BIT(3) +#define CRYPTO_SRC_ITEM_INT_EN RT_BIT(2) +#define CRYPTO_DST_ITEM_DONE_INT_EN RT_BIT(1) +#define CRYPTO_LIST_DONE_INT_EN RT_BIT(0) + +#define CRYPTO_DMA_INT_ST 0x000C +#define CRYPTO_LOCKSTEP_INT_ST RT_BIT(7) +#define CRYPTO_ZERO_LEN_INT_ST RT_BIT(6) +#define CRYPTO_LIST_ERR_INT_ST RT_BIT(5) +#define CRYPTO_SRC_ERR_INT_ST RT_BIT(4) +#define CRYPTO_DST_ERR_INT_ST RT_BIT(3) +#define CRYPTO_SRC_ITEM_DONE_INT_ST RT_BIT(2) +#define CRYPTO_DST_ITEM_DONE_INT_ST RT_BIT(1) +#define CRYPTO_LIST_DONE_INT_ST RT_BIT(0) + +#define CRYPTO_DMA_CTL 0x0010 +#define CRYPTO_DMA_RESTART RT_BIT(1) +#define CRYPTO_DMA_START RT_BIT(0) + +#define CRYPTO_DMA_LLI_ADDR 0x0014 + +#define CRYPTO_FIFO_CTL 0x0040 +#define CRYPTO_DOUT_BYTESWAP RT_BIT(1) +#define CRYPTO_DOIN_BYTESWAP RT_BIT(0) + +#define CRYPTO_BC_CTL 0x0044 +#define CRYPTO_BC_AES _SBF(8, 0x00) +#define CRYPTO_BC_SM4 _SBF(8, 0x01) +#define CRYPTO_BC_DES _SBF(8, 0x02) +#define CRYPTO_BC_TDES _SBF(8, 0x03) +#define CRYPTO_BC_ECB _SBF(4, 0x00) +#define CRYPTO_BC_CBC _SBF(4, 0x01) +#define CRYPTO_BC_CTS _SBF(4, 0x02) +#define CRYPTO_BC_CTR _SBF(4, 0x03) +#define CRYPTO_BC_CFB _SBF(4, 0x04) +#define CRYPTO_BC_OFB _SBF(4, 0x05) +#define CRYPTO_BC_XTS _SBF(4, 0x06) +#define CRYPTO_BC_CCM _SBF(4, 0x07) +#define CRYPTO_BC_GCM _SBF(4, 0x08) +#define CRYPTO_BC_128_bit_key _SBF(2, 0x00) +#define CRYPTO_BC_192_bit_key _SBF(2, 0x01) +#define CRYPTO_BC_256_bit_key _SBF(2, 0x02) +#define CRYPTO_BC_DECRYPT RT_BIT(1) +#define CRYPTO_BC_ENABLE RT_BIT(0) + +#define CRYPTO_HASH_CTL 0x0048 +#define CRYPTO_SHA1 _SBF(4, 0x00) +#define CRYPTO_MD5 _SBF(4, 0x01) +#define CRYPTO_SHA256 _SBF(4, 0x02) +#define CRYPTO_SHA224 _SBF(4, 0x03) +#define CRYPTO_SM3 _SBF(4, 0x06) +#define CRYPTO_SHA512 _SBF(4, 0x08) +#define CRYPTO_SHA384 _SBF(4, 0x09) +#define CRYPTO_HMAC_ENABLE RT_BIT(3) +#define CRYPTO_HW_PAD_ENABLE RT_BIT(2) +#define CRYPTO_HASH_ENABLE RT_BIT(0) + +#define CRYPTO_CH0_IV_0 0x0100 +#define CRYPTO_CH0_KEY_0 0x0180 +#define CRYPTO_CH0_IV_LEN_0 0x0300 + +#define CRYPTO_CH0_PC_LEN_0 0x0280 +#define CRYPTO_CH0_PC_LEN_1 0x0284 +#define CRYPTO_CH0_AAD_LEN_0 0x02c0 +#define CRYPTO_CH0_AAD_LEN_1 0x02c4 + +#define CRYPTO_CH0_TAG_0 0x0320 +#define CRYPTO_CH0_TAG_1 0x0324 +#define CRYPTO_CH0_TAG_2 0x0328 +#define CRYPTO_CH0_TAG_3 0x032c + +#define CRYPTO_HASH_DOUT_0 0x03a0 + +#define CRYPTO_TAG_VALID 0x03e0 +#define CRYPTO_CH0_TAG_VALID RT_BIT(0) + +#define CRYPTO_HASH_VALID 0x03e4 +#define CRYPTO_HASH_IS_VALID RT_BIT(0) + +#define LLI_DMA_CTRL_LAST RT_BIT(0) +#define LLI_DMA_CTRL_PAUSE RT_BIT(1) +#define LLI_DMA_CTRL_LIST_DONE RT_BIT(8) +#define LLI_DMA_CTRL_DST_DONE RT_BIT(9) +#define LLI_DMA_CTRL_SRC_DONE RT_BIT(10) + +#define LLI_USER_CIPHER_START RT_BIT(0) +#define LLI_USER_STRING_START RT_BIT(1) +#define LLI_USER_STRING_LAST RT_BIT(2) +#define LLI_USER_STRING_AAD RT_BIT(3) + +#define CRYPTO_PKA_BASE_OFFSET 0x0480 + +#define CRYPTO_RAM_CTL (0x0480 - CRYPTO_PKA_BASE_OFFSET) +#define CRYPTO_RAM_CTL_SEL_MASK _SBF(16, 3) +#define CRYPTO_RAM_CTL_CPU _SBF(0, 0) +#define CRYPTO_RAM_CTL_PKA _SBF(0, 1) +#define CRYPTO_RAM_CTL_ECC _SBF(0, 2) + +#define CRYPTO_RAM_ST (0x0484 - CRYPTO_PKA_BASE_OFFSET) +#define CRYPTO_CLK_RAM_RDY RT_BIT(0) + +#define CRYPTO_OPCODE (0x0880 - CRYPTO_PKA_BASE_OFFSET) +#define CRYPTO_OPCODE_TAG_SHIFT 0 +#define CRYPTO_OPCODE_R_SHIFT 6 +#define CRYPTO_OPCODE_R_DIS_SHIFT 11 +#define CRYPTO_OPCODE_B_SHIFT 12 +#define CRYPTO_OPCODE_B_IMMED_SHIFT 17 +#define CRYPTO_OPCODE_A_SHIFT 18 +#define CRYPTO_OPCODE_A_IMMED_SHIFT 23 +#define CRYPTO_OPCODE_LEN_SHIFT 24 +#define CRYPTO_OPCODE_CODE_SHIFT 27 +#define CRYPTO_MEMORY_MAP0 (0x0800 - CRYPTO_PKA_BASE_OFFSET) +#define CRYPTO_MAP_REG_NUM 32 +#define CRYPTO_LEN_REG_NUM 8 +#define CRYPTO_N_NP_T0_T1_ADDR (0x0884 - CRYPTO_PKA_BASE_OFFSET) +#define CRYPTO_N_VIRTUAL_ADDR_SHIFT 0 +#define CRYPTO_NP_VIRTUAL_ADDR_SHIFT 5 +#define CRYPTO_T0_VIRTUAL_ADDR_SHIFT 10 +#define CRYPTO_T1_VIRTUAL_ADDR_SHIFT 15 + +#define CRYPTO_PKA_STATUS (0x0888 - CRYPTO_PKA_BASE_OFFSET) +#define CRYPTO_PKA_PIPE_IS_RDY RT_BIT(0) +#define CRYPTO_PKA_BUSY RT_BIT(1) +#define CRYPTO_PKA_ALU_OUT_ZERO RT_BIT(2) +#define CRYPTO_PKA_ALU_MODOVRFLW RT_BIT(3) +#define CRYPTO_PKA_DIV_BY_ZERO RT_BIT(4) +#define CRYPTO_PKA_ALU_CARRY RT_BIT(5) +#define CRYPTO_PKA_ALU_SIGN_OUT RT_BIT(6) +#define CRYPTO_PKA_MODINV_OF_ZERO RT_BIT(7) +#define CRYPTO_PKA_CPU_BUSY RT_BIT(8) +#define CRYPTO_PKA_OPCODE_STATUS_SHIFT 9 +#define CRYPTO_PKA_OPCODE_STATUS_MASK 0x00003e00 +#define CRYPTO_PKA_TAG_STATUS_SHIFT 14 +#define CRYPTO_PKA_TAG_STATUS_MASK 0x0003c000 + +#define CRYPTO_PKA_SW_RESET (0x088C - CRYPTO_PKA_BASE_OFFSET) +#define CRYPTO_PKA_L0 (0x0890 - CRYPTO_PKA_BASE_OFFSET) +#define CRYPTO_PKA_PIPE_RDY (0x08B0 - CRYPTO_PKA_BASE_OFFSET) +#define CRYPTO_PKA_DONE (0x08B4 - CRYPTO_PKA_BASE_OFFSET) +#define CRYPTO_SRAM_BASE (0x1000 - CRYPTO_PKA_BASE_OFFSET) +#define CRYPTO_SRAM_SIZE 0x1000 + +#ifndef RK_ECC_BASE_OFFSET +#define RK_ECC_BASE_OFFSET CRYPTO_PKA_BASE_OFFSET +#endif + +struct rt_clk_array; +struct rt_reset_control; + +struct rockchip_crypto +{ + struct rt_hwcrypto_device parent; + struct rt_mutex mutex; + rt_uint8_t *regs; + struct rt_clk_array *clk_arr; + struct rt_reset_control *rstc; +}; + +enum rk_bignum_endian +{ + RK_BG_BIG_ENDIAN, + RK_BG_LITTILE_ENDIAN +}; + +struct rk_bignum +{ + rt_uint32_t n_words; + rt_uint32_t *data; +}; + +struct rk_ecp_point +{ + struct rk_bignum *x; + struct rk_bignum *y; +}; + +struct rk_bignum *rk_bn_alloc(rt_uint32_t max_size); +void rk_bn_free(struct rk_bignum *bn); +rt_err_t rk_bn_set_data(struct rk_bignum *bn, const rt_uint8_t *data, + rt_uint32_t size, enum rk_bignum_endian endian); +rt_err_t rk_bn_get_data(const struct rk_bignum *bn, rt_uint8_t *data, + rt_uint32_t size, enum rk_bignum_endian endian); +rt_uint32_t rk_bn_get_size(const struct rk_bignum *bn); +int rk_bn_highest_bit(const struct rk_bignum *bn); + +struct rk_ecp_point *rk_ecc_alloc_point_zero(rt_uint32_t max_size); +struct rk_ecp_point *rk_ecc_alloc_point(const rt_uint8_t *x, rt_uint32_t x_len, + const rt_uint8_t *y, rt_uint32_t y_len, + enum rk_bignum_endian endian, rt_uint32_t max_size); +void rk_ecc_free_point(struct rk_ecp_point *point); +rt_bool_t rk_ecp_point_is_zero(struct rk_ecp_point *point); + +#ifdef RT_HWCRYPTO_USING_BIGNUM +const struct hwcrypto_bignum_ops *rk_crypto_bignum_ops_get(void); +void rk_crypto_pka_init(struct rockchip_crypto *rc); +void rk_crypto_ecc_init(struct rockchip_crypto *rc); +#else +rt_inline const struct hwcrypto_bignum_ops *rk_crypto_bignum_ops_get(void) +{ + return RT_NULL; +} + +rt_inline void rk_crypto_pka_init(struct rockchip_crypto *rc) +{ + RT_UNUSED(rc); +} + +rt_inline void rk_crypto_ecc_init(struct rockchip_crypto *rc) +{ + RT_UNUSED(rc); +} +#endif /* RT_HWCRYPTO_USING_BIGNUM */ + +#define RK_ECP_MAX_BITS 256 +#define RK_ECP_MAX_BYTES (RK_ECP_MAX_BITS / 8) +#define RK_ECP_MAX_WORDS (RK_ECP_MAX_BITS / 32) +#define RK_ECP_MAX_WORDS_ALL (512 / 32) + +#define RK_ECC_CTL 0x03F0 +#define RK_ECC_CTL_FUNC_SM2_CURVER _SBF(8, 0x0) +#define RK_ECC_CTL_FUNC_ECC_CURVER _SBF(8, 0x1) +#define RK_ECC_CTL_FUNC_SEL_VERIFY _SBF(4, 0x3) +#define RK_ECC_CTL_REQ_ECC _SBF(0, 1) + +#define RK_ECC_INT_EN 0x03F4 +#define RK_ECC_INT_ST 0x03F8 +#define RK_ECC_ABN_ST 0x03FC +#define RK_ECC_CURVE_WIDE 0x0400 +#define RK_ECC_CURVE_WIDE_192 192 +#define RK_ECC_CURVE_WIDE_224 224 +#define RK_ECC_CURVE_WIDE_256 256 +#define RK_ECC_DATA_ENDIAN 0x0408 +#define RK_ECC_DATA_ENDIAN_LITTLE 0x0 + +#define RK_ECC_RAM_CTL 0x0480 +#define RK_ECC_RAM_CTL_SEL_MASK _SBF(16, 3) +#define RK_ECC_RAM_CTL_CPU _SBF(0, 0) +#define RK_ECC_RAM_CTL_ECC _SBF(0, 2) + +#define SM2_RAM_BASE_OFFSET 0x1000 + +enum rk_ecp_group_id +{ + RK_ECP_DP_NONE = 0, + RK_ECP_DP_SECP192R1, + RK_ECP_DP_SECP224R1, + RK_ECP_DP_SECP256R1, + RK_ECP_DP_SM2P256V1, +}; + +struct rk_ecp_group +{ + enum rk_ecp_group_id id; + const char *curve_name; + rt_uint32_t wide; + const rt_uint8_t *p; + const rt_uint8_t *a; + const rt_uint8_t *n; + const rt_uint8_t *gx; + const rt_uint8_t *gy; + rt_size_t p_len; + rt_size_t a_len; + rt_size_t n_len; + rt_size_t gx_len; + rt_size_t gy_len; + enum rk_bignum_endian endian; +}; + +struct rk_ecc_verify +{ + rt_uint32_t e[RK_ECP_MAX_WORDS_ALL]; + rt_uint32_t r_[RK_ECP_MAX_WORDS_ALL]; + rt_uint32_t s_[RK_ECP_MAX_WORDS_ALL]; + rt_uint32_t p_x[RK_ECP_MAX_WORDS_ALL]; + rt_uint32_t p_y[RK_ECP_MAX_WORDS_ALL]; + rt_uint32_t A[RK_ECP_MAX_WORDS_ALL]; + rt_uint32_t P[RK_ECP_MAX_WORDS_ALL]; + rt_uint32_t N[RK_ECP_MAX_WORDS_ALL]; + rt_uint32_t G_x[RK_ECP_MAX_WORDS_ALL]; + rt_uint32_t G_y[RK_ECP_MAX_WORDS_ALL]; + rt_uint32_t r[RK_ECP_MAX_WORDS_ALL]; + rt_uint32_t v[RK_ECP_MAX_WORDS_ALL]; +}; + +rt_err_t rk_crypto_ecc_verify(int group_id, rt_uint8_t *hash, rt_uint32_t hash_len, + struct rk_ecp_point *point_p, struct rk_ecp_point *point_sign); +rt_uint32_t rk_crypto_ecc_get_max_size(void); +rt_uint32_t rk_crypto_ecc_get_curve_nbits(rt_uint32_t group_id); + +#endif /* __HW_CRYPTO_ROCKCHIP_V2_H__ */ diff --git a/bsp/rockchip/dm/i2c/i2c-rk3x.c b/bsp/rockchip/dm/i2c/i2c-rk3x.c index d73873acd9d5..bc5d8569c39c 100755 --- a/bsp/rockchip/dm/i2c/i2c-rk3x.c +++ b/bsp/rockchip/dm/i2c/i2c-rk3x.c @@ -92,6 +92,9 @@ enum /* Constants */ #define WAIT_TIMEOUT 200 /* ms */ #define DEFAULT_SCL_RATE (100 * 1000) /* Hz */ +#define DATA_UPDATE_POINT 0x3 +#define START_SETUP_MAX 0x3 +#define STOP_SETUP_MAX 0x3 /* I2C specification values for various modes */ struct i2c_spec_values @@ -183,6 +186,10 @@ struct rk3x_i2c struct rt_clk_notifier clk_notifier; struct i2c_timings timings; + rt_uint32_t timing_clkdiv; + rt_uint32_t timing_tuning; + rt_uint32_t timing_scl_oe_db; + rt_bool_t timing_valid; struct rt_spinlock lock; struct rt_completion done; @@ -203,6 +210,9 @@ struct rk3x_i2c static rt_uint32_t rk3x_i2c_fill_transmit_buf(struct rk3x_i2c *i2c, rt_bool_t sendend); static void rk3x_i2c_prepare_read(struct rk3x_i2c *i2c); +static rt_err_t rk3x_i2c_apply_timings(struct rk3x_i2c *i2c); +static rt_err_t rk3x_i2c_v1_calc_timings(rt_ubase_t clk_rate, + struct i2c_timings *t, struct rk3x_i2c_calced_timings *t_calc); rt_inline void i2c_writel(struct rk3x_i2c *i2c, rt_uint32_t value, int offset) { @@ -313,12 +323,20 @@ static rt_bool_t rk3x_i2c_use_autostop(struct rk3x_i2c *i2c) } /* Generate a START condition and kick off the transfer (RK Linux FIFO path) */ -static void rk3x_i2c_start(struct rk3x_i2c *i2c) +static rt_err_t rk3x_i2c_start(struct rk3x_i2c *i2c) { - rt_uint32_t val = i2c_readl(i2c, REG_CON) & REG_CON_TUNING_MASK; + rt_err_t err; + rt_uint32_t val; rt_bool_t auto_stop = rk3x_i2c_auto_stop(i2c); rt_uint32_t length = 0; + if ((err = rk3x_i2c_apply_timings(i2c))) + { + return err; + } + + val = i2c_readl(i2c, REG_CON) & REG_CON_TUNING_MASK; + if (i2c->mode == REG_CON_MOD_TX) { if (!auto_stop) @@ -354,6 +372,17 @@ static void rk3x_i2c_start(struct rk3x_i2c *i2c) { rk3x_i2c_prepare_read(i2c); } + + val = i2c_readl(i2c, REG_CLKDIV); + if (val != i2c->timing_clkdiv) + { + LOG_E("I2C timing lost on START: div=0x%08x expected=0x%08x con=0x%08x", + val, i2c->timing_clkdiv, i2c_readl(i2c, REG_CON)); + + return -RT_EIO; + } + + return RT_EOK; } /* Generate a STOP condition, which triggers a REG_INT_STOP interrupt */ @@ -609,37 +638,143 @@ static void rk3x_i2c_handle_stop(struct rk3x_i2c *i2c, rt_uint32_t ipd) rt_completion_done(&i2c->done); } -static void rk3x_i2c_adapt_div(struct rk3x_i2c *i2c, rt_ubase_t clk_rate) +static rt_err_t rk3x_i2c_apply_timings(struct rk3x_i2c *i2c) +{ + rt_uint32_t val, clkdiv; + + if (!i2c->timing_valid) + { + return -RT_EINVAL; + } + + if (i2c->soc_data->calc_timings == rk3x_i2c_v1_calc_timings && + (!(i2c->timing_clkdiv & 0xffff) || + !(i2c->timing_clkdiv >> 16))) + { + LOG_E("Refusing invalid V1 CLKDIV 0x%08x", i2c->timing_clkdiv); + + return -RT_EINVAL; + } + + val = i2c_readl(i2c, REG_CON); + val &= ~REG_CON_TUNING_MASK; + val |= i2c->timing_tuning; + i2c_writel(i2c, val, REG_CON); + i2c_writel(i2c, i2c->timing_clkdiv, REG_CLKDIV); + i2c_writel(i2c, i2c->timing_scl_oe_db, REG_SCL_OE_DB); + + val = i2c_readl(i2c, REG_CON); + clkdiv = i2c_readl(i2c, REG_CLKDIV); + + if ((val & REG_CON_TUNING_MASK) != i2c->timing_tuning || + clkdiv != i2c->timing_clkdiv) + { + LOG_E("I2C timing restore failed: con=0x%08x div=0x%08x expected=0x%08x", + val, clkdiv, i2c->timing_clkdiv); + + return -RT_EIO; + } + + return RT_EOK; +} + +static void rk3x_i2c_v1_safe_timings(rt_ubase_t clk_rate, + struct i2c_timings *timings, + struct rk3x_i2c_calced_timings *calc) +{ + rt_uint64_t denominator; + rt_ubase_t total_div, div_low, div_high; + rt_ubase_t bus_freq = timings->bus_freq_hz; + + if (bus_freq < 1000) + { + bus_freq = DEFAULT_SCL_RATE; + } + else if (bus_freq > I2C_MAX_FAST_MODE_PLUS_FREQ) + { + bus_freq = I2C_MAX_FAST_MODE_PLUS_FREQ; + } + + denominator = (rt_uint64_t)bus_freq * 8; + total_div = (clk_rate + denominator - 1) / denominator; + total_div = rt_max(total_div, (rt_ubase_t)4); + + div_low = RT_DIV_ROUND_UP(total_div, 2); + div_high = total_div - div_low; + div_low = rt_max(div_low, (rt_ubase_t)2); + div_high = rt_max(div_high, (rt_ubase_t)2); + + calc->div_low = rt_min(div_low - 1, (rt_ubase_t)0xffff); + calc->div_high = rt_min(div_high - 1, (rt_ubase_t)0xffff); + + /* + * Keep SDA setup conservative and maximize START/STOP setup time. + * This path is only used if the full timing calculation is invalid. + */ + calc->tuning = REG_CON_STA_CFG(START_SETUP_MAX - 1) | + REG_CON_STO_CFG(STOP_SETUP_MAX - 1); +} + +static rt_err_t rk3x_i2c_adapt_div(struct rk3x_i2c *i2c, rt_ubase_t clk_rate) { rt_err_t err; rt_ubase_t level; - rt_uint32_t val, cnt; + rt_uint32_t clkdiv; rt_ubase_t period, time_hold = (WAIT_TIMEOUT / 2) * 1000000; - struct rk3x_i2c_calced_timings calc; + struct rk3x_i2c_calced_timings calc = { 0 }; struct i2c_timings *timings = &i2c->timings; + if (!clk_rate) + { + return -RT_EINVAL; + } + if ((err = i2c->soc_data->calc_timings(clk_rate, timings, &calc))) { LOG_W("Could not reach SCL freq %u", timings->bus_freq_hz); } - rt_clk_enable(i2c->pclk); + if (i2c->soc_data->calc_timings == rk3x_i2c_v1_calc_timings && + (!calc.div_low || !calc.div_high)) + { + LOG_W("Invalid V1 timing clk=%lu bus=%u div=%lu/%lu, using safe timing", + (unsigned long)clk_rate, timings->bus_freq_hz, + (unsigned long)calc.div_low, (unsigned long)calc.div_high); + rk3x_i2c_v1_safe_timings(clk_rate, timings, &calc); + } - level = rt_spin_lock_irqsave(&i2c->lock); + if ((err = rt_clk_enable(i2c->pclk))) + { + LOG_E("Can't enable i2c pclk for timing setup: %s", rt_strerror(err)); - val = i2c_readl(i2c, REG_CON); - val &= ~REG_CON_TUNING_MASK; - val |= calc.tuning; - i2c_writel(i2c, val, REG_CON); - i2c_writel(i2c, (calc.div_high << 16) | (calc.div_low & 0xffff), REG_CLKDIV); + return err; + } period = RT_DIV_ROUND_UP(1000000000, clk_rate); - cnt = RT_DIV_ROUND_UP(time_hold, period); - i2c_writel(i2c, cnt, REG_SCL_OE_DB); + clkdiv = (calc.div_high << 16) | (calc.div_low & 0xffff); + + level = rt_spin_lock_irqsave(&i2c->lock); + + i2c->timing_tuning = calc.tuning; + i2c->timing_clkdiv = clkdiv; + i2c->timing_scl_oe_db = RT_DIV_ROUND_UP(time_hold, period); + i2c->timing_valid = RT_TRUE; + err = rk3x_i2c_apply_timings(i2c); rt_spin_unlock_irqrestore(&i2c->lock, level); rt_clk_disable(i2c->pclk); + + if (err) + { + level = rt_spin_lock_irqsave(&i2c->lock); + i2c->timing_valid = RT_FALSE; + rt_spin_unlock_irqrestore(&i2c->lock, level); + + return err; + } + + return RT_EOK; } static rt_err_t rk3x_i2c_clk_notifier(struct rt_clk_notifier *notifier, @@ -664,7 +799,7 @@ static rt_err_t rk3x_i2c_clk_notifier(struct rt_clk_notifier *notifier, /* scale up */ if (new_rate > old_rate) { - rk3x_i2c_adapt_div(i2c, new_rate); + return rk3x_i2c_adapt_div(i2c, new_rate); } break; @@ -672,7 +807,7 @@ static rt_err_t rk3x_i2c_clk_notifier(struct rt_clk_notifier *notifier, /* scale down */ if (new_rate < old_rate) { - rk3x_i2c_adapt_div(i2c, new_rate); + return rk3x_i2c_adapt_div(i2c, new_rate); } break; @@ -680,7 +815,7 @@ static rt_err_t rk3x_i2c_clk_notifier(struct rt_clk_notifier *notifier, /* scale up */ if (new_rate > old_rate) { - rk3x_i2c_adapt_div(i2c, old_rate); + return rk3x_i2c_adapt_div(i2c, old_rate); } break; @@ -946,8 +1081,8 @@ static rt_err_t rk3x_i2c_v1_calc_timings(rt_ubase_t clk_rate, * Final divh and divl must be greater than 0, otherwise the * hardware would not output the i2c clk. */ - min_high_div = (min_high_div < 1) ? 2 : min_high_div; - min_low_div = (min_low_div < 1) ? 2 : min_low_div; + min_high_div = (min_high_div <= 1) ? 2 : min_high_div; + min_low_div = (min_low_div <= 1) ? 2 : min_low_div; /* These are the min dividers needed for min hold times. */ min_div_for_hold = (min_low_div + min_high_div); @@ -985,7 +1120,7 @@ static rt_err_t rk3x_i2c_v1_calc_timings(rt_ubase_t clk_rate, * calculate sda data hold count by the rules, data_upd_st:3 * is a appropriate value to reduce calculated times. */ - for (sda_update_cfg = 3; sda_update_cfg > 0; --sda_update_cfg) + for (sda_update_cfg = DATA_UPDATE_POINT; sda_update_cfg > 0; --sda_update_cfg) { max_hold_data_ns = RT_DIV_ROUND_UP((sda_update_cfg * (t_calc->div_low) + 1) * 1000000, clk_rate_khz); @@ -998,16 +1133,19 @@ static rt_err_t rk3x_i2c_v1_calc_timings(rt_ubase_t clk_rate, break; } } + sda_update_cfg = (sda_update_cfg ? sda_update_cfg : 1) & DATA_UPDATE_POINT; /* calculate setup start config */ min_setup_start_ns = t->scl_rise_ns + spec->min_setup_start_ns; stp_sta_cfg = RT_DIV_ROUND_UP(clk_rate_khz * min_setup_start_ns - 1000000, 8 * 1000000 * (t_calc->div_high)); + stp_sta_cfg = stp_sta_cfg > START_SETUP_MAX ? START_SETUP_MAX : stp_sta_cfg; /* calculate setup stop config */ min_setup_stop_ns = t->scl_rise_ns + spec->min_setup_stop_ns; stp_sto_cfg = RT_DIV_ROUND_UP(clk_rate_khz * min_setup_stop_ns - 1000000, 8 * 1000000 * (t_calc->div_high)); + stp_sto_cfg = stp_sto_cfg > STOP_SETUP_MAX ? STOP_SETUP_MAX : stp_sto_cfg; t_calc->tuning = REG_CON_SDA_CFG(--sda_update_cfg) | REG_CON_STA_CFG(--stp_sta_cfg) | REG_CON_STO_CFG(--stp_sto_cfg); @@ -1115,17 +1253,17 @@ static rt_ssize_t rk3x_i2c_master_xfer(struct rt_i2c_bus_device *bus, rt_ssize_t res = 0; rt_uint32_t val; rt_ubase_t level; + rt_ubase_t clk_rate; + rt_ubase_t pclk_rate; rt_err_t err; rt_err_t timeout_err; + struct rt_clk *clk_parent; struct rk3x_i2c *i2c = raw_to_rk3x_i2c(bus); - level = rt_spin_lock_irqsave(&i2c->lock); - err = rt_clk_enable(i2c->clk); if (err) { LOG_E("Can't enable i2c clk: %s", rt_strerror(err)); - rt_spin_unlock_irqrestore(&i2c->lock, level); return err; } @@ -1137,12 +1275,46 @@ static rt_ssize_t rk3x_i2c_master_xfer(struct rt_i2c_bus_device *bus, { LOG_E("Can't enable i2c pclk: %s", rt_strerror(err)); rt_clk_disable(i2c->clk); - rt_spin_unlock_irqrestore(&i2c->lock, level); return err; } } + clk_parent = rt_clk_get_parent(i2c->clk); + if (!rt_clk_cell_is_enabled(i2c->clk->cell) || + (clk_parent && !rt_clk_cell_is_enabled(clk_parent->cell))) + { + LOG_E("%s functional clock gate disabled: %s=%d parent %s=%d", + rt_dm_dev_get_name(&i2c->parent.parent), + i2c->clk->cell->name, + rt_clk_cell_is_enabled(i2c->clk->cell), + clk_parent ? clk_parent->cell->name : "", + clk_parent ? rt_clk_cell_is_enabled(clk_parent->cell) : 1); + err = -RT_EIO; + + goto _disable_clocks; + } + + clk_rate = rt_clk_get_rate(i2c->clk); + pclk_rate = rt_clk_get_rate(i2c->pclk); + + if (!i2c->timing_valid || + (i2c->soc_data->calc_timings == rk3x_i2c_v1_calc_timings && + (!(i2c->timing_clkdiv & 0xffff) || + !(i2c->timing_clkdiv >> 16)))) + { + if ((err = rk3x_i2c_adapt_div(i2c, clk_rate))) + { + LOG_E("%s failed to refresh timing: %s", + rt_dm_dev_get_name(&i2c->parent.parent), + rt_strerror(err)); + + goto _disable_clocks; + } + } + + level = rt_spin_lock_irqsave(&i2c->lock); + rk3x_i2c_hw_idle(i2c); i2c->is_last_msg = RT_FALSE; @@ -1166,17 +1338,31 @@ static rt_ssize_t rk3x_i2c_master_xfer(struct rt_i2c_bus_device *bus, rt_completion_init(&i2c->done); - rt_spin_unlock_irqrestore(&i2c->lock, level); + if ((err = rk3x_i2c_start(i2c))) + { + rk3x_i2c_hw_idle(i2c); + res = err; - rk3x_i2c_start(i2c); + break; + } + rt_spin_unlock_irqrestore(&i2c->lock, level); timeout_err = rt_completion_wait(&i2c->done, rt_tick_from_millisecond(WAIT_TIMEOUT)); level = rt_spin_lock_irqsave(&i2c->lock); if (timeout_err) { - LOG_E("timeout, ipd: 0x%02x, state: %d", i2c_readl(i2c, REG_IPD), i2c->state); + LOG_E("%s timeout addr=0x%02x state=%d clk=%lu pclk=%lu " + "con=0x%08x div=0x%08x expected=0x%08x " + "ien=0x%03x ipd=0x%03x fcnt=%u", + rt_dm_dev_get_name(&i2c->parent.parent), i2c->msg->addr, + i2c->state, (unsigned long)clk_rate, + (unsigned long)pclk_rate, + i2c_readl(i2c, REG_CON), i2c_readl(i2c, REG_CLKDIV), + i2c->timing_clkdiv, + i2c_readl(i2c, REG_IEN), i2c_readl(i2c, REG_IPD), + i2c_readl(i2c, REG_FCNT)); /* Force a STOP condition without interrupt */ i2c_writel(i2c, 0, REG_IEN); @@ -1201,15 +1387,16 @@ static rt_ssize_t rk3x_i2c_master_xfer(struct rt_i2c_bus_device *bus, rk3x_i2c_disable_irq(i2c); rk3x_i2c_disable(i2c); + rt_spin_unlock_irqrestore(&i2c->lock, level); + +_disable_clocks: if (!rt_is_err_or_null(i2c->pclk) && i2c->pclk != i2c->clk) { rt_clk_disable(i2c->pclk); } rt_clk_disable(i2c->clk); - rt_spin_unlock_irqrestore(&i2c->lock, level); - - return res < 0 ? res : num; + return err ? err : (res < 0 ? res : num); } const static struct rt_i2c_bus_device_ops rk3x_i2c_ops = @@ -1337,6 +1524,7 @@ static rt_err_t rk3x_i2c_probe(struct rt_platform_device *pdev) i2c->soc_data = pdev->id->data; i2c_timings_ofw_parse(dev->ofw_node, &i2c->timings, RT_TRUE); + rt_spin_lock_init(&i2c->lock); i2c->regs = rt_dm_dev_iomap(dev, 0); @@ -1439,12 +1627,16 @@ static rt_err_t rk3x_i2c_probe(struct rt_platform_device *pdev) goto _fail; } - rk3x_i2c_adapt_div(i2c, rt_clk_get_rate(i2c->clk)); + err = rk3x_i2c_adapt_div(i2c, rt_clk_get_rate(i2c->clk)); rt_clk_disable(i2c->clk); + if (err) + { + goto _fail; + } + i2c->autostop_supported = rk3x_i2c_use_autostop(i2c); - rt_spin_lock_init(&i2c->lock); rt_completion_init(&i2c->done); if (id >= 0) diff --git a/bsp/rockchip/dm/include/dt-bindings/display/rockchip_vop.h b/bsp/rockchip/dm/include/dt-bindings/display/rockchip_vop.h new file mode 100644 index 000000000000..7ea8a2515f70 --- /dev/null +++ b/bsp/rockchip/dm/include/dt-bindings/display/rockchip_vop.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __DT_BINDINGS_DISPLAY_ROCKCHIP_VOP_H__ +#define __DT_BINDINGS_DISPLAY_ROCKCHIP_VOP_H__ + +#define RK_PLANE_CLUSTER0 0 +#define RK_PLANE_CLUSTER1 1 +#define RK_PLANE_ESMART0 2 +#define RK_PLANE_ESMART1 3 +#define RK_PLANE_SMART0 4 +#define RK_PLANE_SMART1 5 +#define RK_PLANE_ESMART2 8 +#define RK_PLANE_ESMART3 9 + +#endif /* __DT_BINDINGS_DISPLAY_ROCKCHIP_VOP_H__ */ diff --git a/bsp/rockchip/dm/include/jpegd.h b/bsp/rockchip/dm/include/jpegd.h new file mode 100644 index 000000000000..059870ea441d --- /dev/null +++ b/bsp/rockchip/dm/include/jpegd.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-11-21 GuEe-GUI first version + */ + +#ifndef __JPEGD_H__ +#define __JPEGD_H__ + +#include +#include + +#define JPEGD_REG_NUM 42 +#define JPEGD_NAME "jpegd" + +/* + * Standalone JPEG decode request. + * + * Input: reg[] must contain a full register set prepared for the hardware. + * DMA buffer addresses (register indices 9-13) should use IOVA from + * rt_dma_alloc_coherent() on the jpegd device. + * Output: reg[] is updated with post-decode register values; irq_status + * reports the raw interrupt status word. + */ +struct jpegd_req +{ + uint32_t reg[JPEGD_REG_NUM]; + uint32_t irq_status; +}; + +#define JPEGD_IOC_MAGIC 'J' + +#define JPEGD_RUN _IOWR(JPEGD_IOC_MAGIC, 0, struct jpegd_req) +#define JPEGD_GET_HW_ID _IOR(JPEGD_IOC_MAGIC, 1, uint32_t) + +#endif /* __JPEGD_H__ */ diff --git a/bsp/rockchip/dm/include/rga2.h b/bsp/rockchip/dm/include/rga2.h new file mode 100644 index 000000000000..305f92d768eb --- /dev/null +++ b/bsp/rockchip/dm/include/rga2.h @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-11-21 GuEe-GUI first version + */ + +#ifndef __ROCKCHIP_RGA2_H__ +#define __ROCKCHIP_RGA2_H__ + +#include +#include + +#define RGA2_NAME "rga" +#define RGA2_BUFFER_MAX_SIZE (64U * 1024U * 1024U) + +enum rga2_render_mode +{ + RGA2_MODE_BITBLT = 0, + RGA2_MODE_COLOR_FILL = 2, +}; + +enum rga2_format +{ + RGA2_FORMAT_RGBA8888, + RGA2_FORMAT_BGRA8888, + RGA2_FORMAT_RGBX8888, + RGA2_FORMAT_BGRX8888, + RGA2_FORMAT_RGB888, + RGA2_FORMAT_BGR888, + RGA2_FORMAT_RGB565, + RGA2_FORMAT_BGR565, +}; + +enum rga2_rotate +{ + RGA2_ROTATE_0, + RGA2_ROTATE_90, + RGA2_ROTATE_180, + RGA2_ROTATE_270, +}; + +#define RGA2_MIRROR_X (1U << 0) +#define RGA2_MIRROR_Y (1U << 1) + +struct rga2_buffer +{ + uint32_t size; + uint32_t reserved; + uint64_t phys_addr; + void *virt_addr; +}; + +struct rga2_rect +{ + uint16_t x; + uint16_t y; + uint16_t width; + uint16_t height; +}; + +struct rga2_image +{ + uint64_t address; + uint16_t width; + uint16_t height; + uint16_t stride; + uint16_t format; + struct rga2_rect rect; +}; + +struct rga2_req +{ + uint8_t render_mode; + uint8_t rotate; + uint8_t mirror; + uint8_t reserved; + uint32_t color; + struct rga2_image src; + struct rga2_image dst; + uint32_t irq_status; +}; + +#define RGA2_IOC_MAGIC 'R' +#define RGA2_SUBMIT _IOWR(RGA2_IOC_MAGIC, 0, struct rga2_req) +#define RGA2_ALLOC_BUFFER _IOWR(RGA2_IOC_MAGIC, 1, struct rga2_buffer) +#define RGA2_FREE_BUFFER _IOW(RGA2_IOC_MAGIC, 2, struct rga2_buffer) +#define RGA2_GET_VERSION _IOR(RGA2_IOC_MAGIC, 3, uint32_t) +#define RGA2_RESET _IO(RGA2_IOC_MAGIC, 4) + +#endif /* __ROCKCHIP_RGA2_H__ */ diff --git a/bsp/rockchip/dm/include/rockchip-hdmi.h b/bsp/rockchip/dm/include/rockchip-hdmi.h new file mode 100644 index 000000000000..f15e5c507dcb --- /dev/null +++ b/bsp/rockchip/dm/include/rockchip-hdmi.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-11-21 GuEe-GUI first version + */ + +#ifndef __ROCKCHIP_HDMI_H__ +#define __ROCKCHIP_HDMI_H__ + +#include + +#ifdef RT_GRAPHIC_CONNECTOR_HDMI +rt_err_t rk_hdmi_audio_configure(struct rt_ofw_node *np, + rt_uint32_t samplerate, rt_uint8_t channels, rt_uint8_t samplebits); +rt_err_t rk_hdmi_audio_enable(struct rt_ofw_node *np, rt_bool_t enable); +#else +rt_inline rt_err_t rk_hdmi_audio_configure(struct rt_ofw_node *np, + rt_uint32_t samplerate, rt_uint8_t channels, rt_uint8_t samplebits) +{ + RT_UNUSED(np); + RT_UNUSED(samplerate); + RT_UNUSED(channels); + RT_UNUSED(samplebits); + + return -RT_ENOSYS; +} + +rt_inline rt_err_t rk_hdmi_audio_enable(struct rt_ofw_node *np, rt_bool_t enable) +{ + RT_UNUSED(np); + RT_UNUSED(enable); + + return -RT_ENOSYS; +} +#endif + +#endif /* __ROCKCHIP_HDMI_H__ */ diff --git a/bsp/rockchip/dm/pci/Kconfig b/bsp/rockchip/dm/pci/Kconfig index 761b844e4825..b78de27d227d 100755 --- a/bsp/rockchip/dm/pci/Kconfig +++ b/bsp/rockchip/dm/pci/Kconfig @@ -1,3 +1,26 @@ +config RT_PCIE_ROCKCHIP + bool "Rockchip PCIe controller" + depends on RT_USING_OFW + depends on RT_USING_CLK + depends on RT_USING_PIN + depends on RT_USING_PINCTRL + depends on RT_USING_RESET + depends on RT_USING_REGULATOR + depends on RT_USING_PHYE + default n + +config RT_PCIE_ROCKCHIP_EP + bool "Rockchip PCIe endpoint" + depends on RT_PCI_ENDPOINT + depends on RT_USING_OFW + depends on RT_USING_CLK + depends on RT_USING_PIN + depends on RT_USING_PINCTRL + depends on RT_USING_RESET + depends on RT_USING_REGULATOR + depends on RT_USING_PHYE + default n + config RT_PCI_DW_ROCKCHIP bool "Rockchip DesignWare PCIe" depends on RT_PCI_DW diff --git a/bsp/rockchip/dm/pci/SConscript b/bsp/rockchip/dm/pci/SConscript index 3e0e8ed40d64..bb6a9366ea23 100755 --- a/bsp/rockchip/dm/pci/SConscript +++ b/bsp/rockchip/dm/pci/SConscript @@ -7,6 +7,15 @@ CPPPATH = [cwd + '/../include', cwd + '/../../../../components/drivers/pci', cwd src = [] +if GetDepend(['RT_PCIE_ROCKCHIP']): + src += ['pcie-rockchip-host.c'] + +if GetDepend(['RT_PCIE_ROCKCHIP_EP']): + src += ['pcie-rockchip-ep.c'] + +if GetDepend(['RT_PCIE_ROCKCHIP']) or GetDepend(['RT_PCIE_ROCKCHIP_EP']): + src += ['pcie-rockchip.c'] + if GetDepend(['RT_PCI_DW_ROCKCHIP']): src += ['pcie-dw-rockchip.c'] diff --git a/bsp/rockchip/dm/pci/pcie-rockchip-ep.c b/bsp/rockchip/dm/pci/pcie-rockchip-ep.c new file mode 100755 index 000000000000..eef410266083 --- /dev/null +++ b/bsp/rockchip/dm/pci/pcie-rockchip-ep.c @@ -0,0 +1,676 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-09-23 GuEe-GUI first version + */ + +#define DBG_TAG "pcie.rk-ep" +#define DBG_LVL DBG_INFO +#include + +#include "pcie-rockchip.h" + +struct rockchip_pcie_ep +{ + struct rockchip_pcie rk_pcie; + struct rt_pci_ep epc; + + rt_ubase_t *ob_addr; + rt_uint32_t max_regions; + rt_bitmap_t ob_region_map; + rt_slab_t addr_slab; + + void *irq_cpu_addr; + rt_ubase_t irq_phys_addr; + rt_uint64_t irq_pci_addr; + rt_uint8_t irq_pci_fn; + rt_uint8_t irq_pending; +}; + +rt_inline int __fls64(rt_uint64_t x) +{ + const rt_uint64_t bits_per_u64 = (sizeof(x) * 8); + int num = bits_per_u64 - 1; + + if (x == 0) + { + return 0; + } + + if (!(x & (~0ULL << (bits_per_u64 - 32)))) + { + num -= 32; + x <<= 32; + } + + if (!(x & (~0ULL << (bits_per_u64 - 16)))) + { + num -= 16; + x <<= 16; + } + + if (!(x & (~0ULL << (bits_per_u64 - 8)))) + { + num -= 8; + x <<= 8; + } + + if (!(x & (~0ULL << (bits_per_u64 - 4)))) + { + num -= 4; + x <<= 4; + } + + if (!(x & (~0ULL << (bits_per_u64 - 2)))) + { + num -= 2; + x <<= 2; + } + + if (!(x & (~0ULL << (bits_per_u64 - 1)))) + { + num -= 1; + } + + return num + 1; +} + +static void rockchip_pcie_clear_ep_ob_atu(struct rockchip_pcie *rk_pcie, + rt_uint32_t region) +{ + rockchip_pcie_write(rk_pcie, 0, RK_PCIE_AT_OB_REGION_PCI_ADDR0(region)); + rockchip_pcie_write(rk_pcie, 0, RK_PCIE_AT_OB_REGION_PCI_ADDR1(region)); + rockchip_pcie_write(rk_pcie, 0, RK_PCIE_AT_OB_REGION_DESC0(region)); + rockchip_pcie_write(rk_pcie, 0, RK_PCIE_AT_OB_REGION_DESC1(region)); + rockchip_pcie_write(rk_pcie, 0, RK_PCIE_AT_OB_REGION_CPU_ADDR0(region)); + rockchip_pcie_write(rk_pcie, 0, RK_PCIE_AT_OB_REGION_CPU_ADDR1(region)); +} + +static void rockchip_pcie_prog_ep_ob_atu(struct rockchip_pcie *rk_pcie, + rt_uint8_t func_no, rt_uint32_t r, rt_uint32_t type, + rt_uint64_t cpu_addr, rt_uint64_t pci_addr, rt_size_t size) +{ + rt_uint64_t sz = 1ULL << __fls64(size - 1); + int num_pass_bits = rt_ilog2(sz); + rt_uint32_t addr0, addr1, desc0, desc1; + rt_bool_t is_nor_msg = (type == AXI_WRAPPER_NOR_MSG); + + /* The minimal region size is 1MB */ + if (num_pass_bits < 8) + { + num_pass_bits = 8; + } + + cpu_addr -= rk_pcie->mem_base_addr; + addr0 = ((is_nor_msg ? 0x10 : (num_pass_bits - 1)) & + PCIE_CORE_OB_REGION_ADDR0_NUM_BITS) | + (rt_lower_32_bits(cpu_addr) & PCIE_CORE_OB_REGION_ADDR0_LO_ADDR); + addr1 = rt_upper_32_bits(is_nor_msg ? cpu_addr : pci_addr); + desc0 = RK_PCIE_AT_OB_REGION_DESC0_DEVFN(func_no) | type; + desc1 = 0; + + if (is_nor_msg) + { + rockchip_pcie_write(rk_pcie, 0, RK_PCIE_AT_OB_REGION_PCI_ADDR0(r)); + rockchip_pcie_write(rk_pcie, 0, RK_PCIE_AT_OB_REGION_PCI_ADDR1(r)); + rockchip_pcie_write(rk_pcie, desc0, RK_PCIE_AT_OB_REGION_DESC0(r)); + rockchip_pcie_write(rk_pcie, desc1, RK_PCIE_AT_OB_REGION_DESC1(r)); + } + else + { + /* PCI bus address region */ + rockchip_pcie_write(rk_pcie, addr0, RK_PCIE_AT_OB_REGION_PCI_ADDR0(r)); + rockchip_pcie_write(rk_pcie, addr1, RK_PCIE_AT_OB_REGION_PCI_ADDR1(r)); + rockchip_pcie_write(rk_pcie, desc0, RK_PCIE_AT_OB_REGION_DESC0(r)); + rockchip_pcie_write(rk_pcie, desc1, RK_PCIE_AT_OB_REGION_DESC1(r)); + + addr0 = ((num_pass_bits - 1) & PCIE_CORE_OB_REGION_ADDR0_NUM_BITS) | + (rt_lower_32_bits(cpu_addr) & PCIE_CORE_OB_REGION_ADDR0_LO_ADDR); + addr1 = rt_upper_32_bits(cpu_addr); + } + + /* CPU bus address region */ + rockchip_pcie_write(rk_pcie, addr0, RK_PCIE_AT_OB_REGION_CPU_ADDR0(r)); + rockchip_pcie_write(rk_pcie, addr1, RK_PCIE_AT_OB_REGION_CPU_ADDR1(r)); +} + +static rt_err_t rockchip_pcie_ep_write_header(struct rt_pci_ep *epc, rt_uint8_t func_no, + struct rt_pci_ep_header *hdr) +{ + rt_uint32_t reg; + struct rockchip_pcie_ep *ep = epc->priv; + struct rockchip_pcie *rk_pcie = &ep->rk_pcie; + + /* All functions share the same vendor ID with function 0 */ + if (func_no == 0) + { + rt_uint32_t vid_regs = (hdr->vendor & RT_GENMASK(15, 0)) | + (hdr->subsystem_vendor & RT_GENMASK(31, 16)) << 16; + + rockchip_pcie_write(rk_pcie, vid_regs, PCIE_CORE_CONFIG_VENDOR); + } + + reg = rockchip_pcie_read(rk_pcie, PCIE_EP_CONFIG_DID_VID); + reg = (reg & 0xffff) | (hdr->device << 16); + rockchip_pcie_write(rk_pcie, reg, PCIE_EP_CONFIG_DID_VID); + + rockchip_pcie_write(rk_pcie, + hdr->revision | hdr->progif << 8 | + hdr->subclass << 16 | hdr->class_code << 24, + RK_PCIE_EP_FUNC_BASE(func_no) + PCIR_REVID); + rockchip_pcie_write(rk_pcie, hdr->cache_line_size, + RK_PCIE_EP_FUNC_BASE(func_no) + PCIR_CACHELNSZ); + rockchip_pcie_write(rk_pcie, hdr->subsystem_device << 16, + RK_PCIE_EP_FUNC_BASE(func_no) + PCIR_SUBVEND_0); + rockchip_pcie_write(rk_pcie, hdr->intx << 8, + RK_PCIE_EP_FUNC_BASE(func_no) + PCIR_INTPIN); + + return RT_EOK; +} + +static rt_err_t rockchip_pcie_ep_set_bar(struct rt_pci_ep *epc, rt_uint8_t func_no, + struct rt_pci_ep_bar *bar, int bar_idx) +{ + rt_uint64_t sz; + rt_ubase_t bar_phys, flags = bar->bus.flags; + rt_uint32_t addr0, addr1, reg, cfg, b, aperture, ctrl; + struct rockchip_pcie_ep *ep = epc->priv; + struct rockchip_pcie *rk_pcie = &ep->rk_pcie; + + bar_phys = bar->bus.base; + sz = rt_max_t(rt_size_t, bar->bus.size, MIN_EP_APERTURE); + sz = 1ULL << __fls64(sz - 1); + aperture = rt_ilog2(sz) - 7; + + if ((flags & PCIM_BAR_SPACE) == PCIM_BAR_SPACE_IO) + { + ctrl = RK_PCIE_CORE_BAR_CFG_CTRL_IO_32BITS; + } + else + { + rt_bool_t is_prefetch = !!(flags & PCIM_BAR_MEM_PREFETCH); + rt_bool_t is_64bits = sz > (2UL * SIZE_GB); + + if (is_64bits && (bar_idx & 1)) + { + return -RT_EINVAL; + } + + if (is_64bits && is_prefetch) + { + ctrl = RK_PCIE_CORE_BAR_CFG_CTRL_PREFETCH_MEM_64BITS; + } + else if (is_prefetch) + { + ctrl = RK_PCIE_CORE_BAR_CFG_CTRL_PREFETCH_MEM_32BITS; + } + else if (is_64bits) + { + ctrl = RK_PCIE_CORE_BAR_CFG_CTRL_MEM_64BITS; + } + else + { + ctrl = RK_PCIE_CORE_BAR_CFG_CTRL_MEM_32BITS; + } + } + + if (bar_idx < 4) + { + reg = RK_PCIE_CORE_EP_FUNC_BAR_CFG0(func_no); + b = bar_idx; + } + else + { + reg = RK_PCIE_CORE_EP_FUNC_BAR_CFG1(func_no); + b = bar_idx - 4; + } + + addr0 = rt_lower_32_bits(bar_phys); + addr1 = rt_upper_32_bits(bar_phys); + + cfg = rockchip_pcie_read(rk_pcie, reg); + cfg &= ~(RK_PCIE_CORE_EP_FUNC_BAR_CFG_BAR_APERTURE_MASK(b) | + RK_PCIE_CORE_EP_FUNC_BAR_CFG_BAR_CTRL_MASK(b)); + cfg |= (RK_PCIE_CORE_EP_FUNC_BAR_CFG_BAR_APERTURE(b, aperture) | + RK_PCIE_CORE_EP_FUNC_BAR_CFG_BAR_CTRL(b, ctrl)); + + rockchip_pcie_write(rk_pcie, cfg, reg); + rockchip_pcie_write(rk_pcie, addr0, RK_PCIE_AT_IB_EP_FUNC_BAR_ADDR0(func_no, bar_idx)); + rockchip_pcie_write(rk_pcie, addr1, RK_PCIE_AT_IB_EP_FUNC_BAR_ADDR1(func_no, bar_idx)); + + return RT_EOK; +} + +static rt_err_t rockchip_pcie_ep_clear_bar(struct rt_pci_ep *epc, rt_uint8_t func_no, + struct rt_pci_ep_bar *bar, int bar_idx) +{ + rt_uint32_t reg, cfg, b, ctrl; + struct rockchip_pcie_ep *ep = epc->priv; + struct rockchip_pcie *rk_pcie = &ep->rk_pcie; + + if (bar_idx < 4) + { + reg = RK_PCIE_CORE_EP_FUNC_BAR_CFG0(func_no); + b = bar_idx; + } + else + { + reg = RK_PCIE_CORE_EP_FUNC_BAR_CFG1(func_no); + b = bar_idx - 4; + } + + ctrl = RK_PCIE_CORE_BAR_CFG_CTRL_DISABLED; + cfg = rockchip_pcie_read(rk_pcie, reg); + cfg &= ~(RK_PCIE_CORE_EP_FUNC_BAR_CFG_BAR_APERTURE_MASK(b) | + RK_PCIE_CORE_EP_FUNC_BAR_CFG_BAR_CTRL_MASK(b)); + cfg |= RK_PCIE_CORE_EP_FUNC_BAR_CFG_BAR_CTRL(b, ctrl); + + rockchip_pcie_write(rk_pcie, cfg, reg); + rockchip_pcie_write(rk_pcie, 0x0, RK_PCIE_AT_IB_EP_FUNC_BAR_ADDR0(func_no, bar_idx)); + rockchip_pcie_write(rk_pcie, 0x0, RK_PCIE_AT_IB_EP_FUNC_BAR_ADDR1(func_no, bar_idx)); + + return RT_EOK; +} + +static rt_err_t rockchip_pcie_ep_map_addr(struct rt_pci_ep *epc, rt_uint8_t func_no, + rt_ubase_t addr, rt_uint64_t pci_addr, rt_size_t size) +{ + struct rockchip_pcie_ep *ep = epc->priv; + struct rockchip_pcie *pcie = &ep->rk_pcie; + rt_uint32_t r; + + r = rt_bitmap_next_clear_bit(&ep->ob_region_map, 0, RT_BITS_PER_LONG); + /* + * Region 0 is reserved for configuration space and shouldn't + * be used elsewhere per TRM, so leave it out. + */ + if (r >= ep->max_regions - 1) + { + return -RT_EINVAL; + } + + rockchip_pcie_prog_ep_ob_atu(pcie, func_no, r, AXI_WRAPPER_MEM_WRITE, + addr, pci_addr, size); + + rt_bitmap_set_bit(&ep->ob_region_map, r); + ep->ob_addr[r] = addr; + + return 0; +} + +static rt_err_t rockchip_pcie_ep_unmap_addr(struct rt_pci_ep *epc, rt_uint8_t func_no, + rt_ubase_t addr) +{ + rt_uint32_t r; + struct rockchip_pcie_ep *ep = epc->priv; + struct rockchip_pcie *rk_pcie = &ep->rk_pcie; + + for (r = 0; r < ep->max_regions - 1; ++r) + { + if (ep->ob_addr[r] == addr) + { + break; + } + } + + /* + * Region 0 is reserved for configuration space and shouldn't + * be used elsewhere per TRM, so leave it out. + */ + if (r == ep->max_regions - 1) + { + return RT_EOK; + } + + rockchip_pcie_clear_ep_ob_atu(rk_pcie, r); + + ep->ob_addr[r] = 0; + rt_bitmap_clear_bit(&ep->ob_region_map, r); + + return RT_EOK; +} + +static rt_err_t rockchip_pcie_ep_set_msi(struct rt_pci_ep *epc, rt_uint8_t func_no, + unsigned irq_nr) +{ + rt_uint32_t flags; + struct rockchip_pcie_ep *ep = epc->priv; + struct rockchip_pcie *rk_pcie = &ep->rk_pcie; + + flags = rockchip_pcie_read(rk_pcie, RK_PCIE_EP_FUNC_BASE(func_no) + + RK_PCIE_EP_MSI_CTRL_REG); + flags &= ~RK_PCIE_EP_MSI_CTRL_MMC_MASK; + flags |= (irq_nr << RK_PCIE_EP_MSI_CTRL_MMC_OFFSET) | + (PCIM_MSICTRL_64BIT << RK_PCIE_EP_MSI_FLAGS_OFFSET); + flags &= ~RK_PCIE_EP_MSI_CTRL_MASK_MSI_CAP; + rockchip_pcie_write(rk_pcie, flags, RK_PCIE_EP_FUNC_BASE(func_no) + + RK_PCIE_EP_MSI_CTRL_REG); + + return RT_EOK; +} + +static rt_err_t rockchip_pcie_ep_get_msi(struct rt_pci_ep *epc, rt_uint8_t func_no, + unsigned *out_irq_nr) +{ + rt_uint32_t flags; + struct rockchip_pcie_ep *ep = epc->priv; + struct rockchip_pcie *rk_pcie = &ep->rk_pcie; + + flags = rockchip_pcie_read(rk_pcie, RK_PCIE_EP_FUNC_BASE(func_no) + + RK_PCIE_EP_MSI_CTRL_REG); + + if (!(flags & RK_PCIE_EP_MSI_CTRL_ME)) + { + return -RT_EINVAL; + } + + *out_irq_nr = ((flags & RK_PCIE_EP_MSI_CTRL_MME_MASK) >> RK_PCIE_EP_MSI_CTRL_MME_OFFSET); + return RT_EOK; +} + +static void rockchip_pcie_ep_assert_intx(struct rockchip_pcie_ep *ep, + rt_uint8_t func_no, rt_uint8_t intx, rt_bool_t do_assert) +{ + struct rockchip_pcie *rk_pcie = &ep->rk_pcie; + + intx &= 3; + + if (do_assert) + { + ep->irq_pending |= RT_BIT(intx); + rockchip_pcie_write(rk_pcie, PCIE_CLIENT_INT_IN_ASSERT | + PCIE_CLIENT_INT_PEND_ST_PEND, PCIE_CLIENT_LEGACY_INT_CTRL); + } + else + { + ep->irq_pending &= ~RT_BIT(intx); + rockchip_pcie_write(rk_pcie, PCIE_CLIENT_INT_IN_DEASSERT | + PCIE_CLIENT_INT_PEND_ST_NORMAL, PCIE_CLIENT_LEGACY_INT_CTRL); + } +} + +static rt_err_t rockchip_pcie_ep_send_legacy_irq(struct rockchip_pcie_ep *ep, + rt_uint8_t func_no, rt_uint8_t intx) +{ + rt_uint16_t cmd; + + cmd = rockchip_pcie_read(&ep->rk_pcie, RK_PCIE_EP_FUNC_BASE(func_no) + + RK_PCIE_EP_CMD_STATUS); + + if (cmd & PCIM_CMD_INTxDIS) + { + return -RT_EINVAL; + } + + /* + * Should add some delay between toggling INTx per TRM vaguely saying + * it depends on some cycles of the AHB bus clock to function it. So + * add sufficient 1ms here. + */ + rockchip_pcie_ep_assert_intx(ep, func_no, intx, RT_TRUE); + rt_thread_mdelay(1); + rockchip_pcie_ep_assert_intx(ep, func_no, intx, RT_FALSE); + + return RT_EOK; +} + +static rt_err_t rockchip_pcie_ep_send_msi_irq(struct rockchip_pcie_ep *ep, + rt_uint8_t func_no, unsigned irq_nr) +{ + rt_uint8_t msi_count; + rt_uint32_t flags, mme, data, data_mask; + rt_uint64_t pci_addr, pci_addr_mask = 0xff; + struct rockchip_pcie *rk_pcie = &ep->rk_pcie; + + /* Check MSI enable bit */ + flags = rockchip_pcie_read(&ep->rk_pcie, RK_PCIE_EP_FUNC_BASE(func_no) + + RK_PCIE_EP_MSI_CTRL_REG); + + if (!(flags & RK_PCIE_EP_MSI_CTRL_ME)) + { + return -RT_EINVAL; + } + + /* Get MSI numbers from MME */ + mme = ((flags & RK_PCIE_EP_MSI_CTRL_MME_MASK) >> RK_PCIE_EP_MSI_CTRL_MME_OFFSET); + msi_count = 1 << mme; + if (!irq_nr || irq_nr > msi_count) + { + return -RT_EINVAL; + } + + /* Set MSI private data */ + data_mask = msi_count - 1; + data = rockchip_pcie_read(rk_pcie, RK_PCIE_EP_FUNC_BASE(func_no) + + RK_PCIE_EP_MSI_CTRL_REG + PCIR_MSI_DATA_64BIT); + data = (data & ~data_mask) | ((irq_nr - 1) & data_mask); + + /* Get MSI PCI address */ + pci_addr = rockchip_pcie_read(rk_pcie, RK_PCIE_EP_FUNC_BASE(func_no) + + RK_PCIE_EP_MSI_CTRL_REG + PCIR_MSI_ADDR_HIGH); + pci_addr <<= 32; + pci_addr |= rockchip_pcie_read(rk_pcie, RK_PCIE_EP_FUNC_BASE(func_no) + + RK_PCIE_EP_MSI_CTRL_REG + PCIR_MSI_ADDR); + pci_addr &= RT_GENMASK_ULL(63, 2); + + /* Set the outbound region if needed. */ + if (ep->irq_pci_addr != (pci_addr & ~pci_addr_mask) || ep->irq_pci_fn != func_no) + { + rockchip_pcie_prog_ep_ob_atu(rk_pcie, func_no, ep->max_regions - 1, + AXI_WRAPPER_MEM_WRITE, ep->irq_phys_addr, + pci_addr & ~pci_addr_mask, pci_addr_mask + 1); + + ep->irq_pci_addr = (pci_addr & ~pci_addr_mask); + ep->irq_pci_fn = func_no; + } + + HWREG16(ep->irq_cpu_addr + (pci_addr & pci_addr_mask)) = data; + + return RT_EOK; +} + +static rt_err_t rockchip_pcie_ep_raise_irq(struct rt_pci_ep *epc, rt_uint8_t func_no, + enum rt_pci_ep_irq type, unsigned irq) +{ + struct rockchip_pcie_ep *ep = epc->priv; + + switch (type) + { + case RT_PCI_EP_IRQ_LEGACY: + return rockchip_pcie_ep_send_legacy_irq(ep, func_no, 0); + + case RT_PCI_EP_IRQ_MSI: + return rockchip_pcie_ep_send_msi_irq(ep, func_no, irq); + + default: + return -RT_EINVAL; + } +} + +static rt_err_t rockchip_pcie_ep_start(struct rt_pci_ep *epc) +{ + rt_uint32_t cfg = RT_BIT(0); + struct rt_pci_epf *epf; + struct rockchip_pcie_ep *ep = epc->priv; + struct rockchip_pcie *rk_pcie = &ep->rk_pcie; + + rt_list_for_each_entry(epf, &epc->epf_nodes, list) + { + cfg |= RT_BIT(epf->func_no); + } + + rockchip_pcie_write(rk_pcie, cfg, PCIE_CORE_PHY_FUNC_CFG); + + return RT_EOK; +} + +static const struct rt_pci_ep_ops rockchip_pcie_ep_ops = +{ + .write_header = rockchip_pcie_ep_write_header, + .set_bar = rockchip_pcie_ep_set_bar, + .clear_bar = rockchip_pcie_ep_clear_bar, + .map_addr = rockchip_pcie_ep_map_addr, + .unmap_addr = rockchip_pcie_ep_unmap_addr, + .set_msi = rockchip_pcie_ep_set_msi, + .get_msi = rockchip_pcie_ep_get_msi, + .raise_irq = rockchip_pcie_ep_raise_irq, + .start = rockchip_pcie_ep_start, +}; + +static rt_err_t rockchip_pcie_ep_ofw_parse(struct rockchip_pcie *rk_pcie, + struct rockchip_pcie_ep *ep) +{ + rt_err_t err; + struct rt_device *dev = rk_pcie->dev; + + if ((err = rockchip_pcie_ofw_parse(rk_pcie))) + { + return err; + } + + if ((err = rockchip_pcie_get_phys(rk_pcie))) + { + return err; + } + + if (rt_dm_dev_prop_read_u32(dev, "rk_pcie,max-outbound-regions", &ep->max_regions) || + ep->max_regions > MAX_REGION_LIMIT) + { + ep->max_regions = MAX_REGION_LIMIT; + } + + if (rt_dm_dev_prop_read_u8(dev, "max-functions", &ep->epc.max_functions)) + { + ep->epc.max_functions = 1; + } + + return RT_EOK; +} + +static rt_err_t rockchip_pcie_ep_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + rt_size_t max_regions; + struct rockchip_pcie_ep *ep; + struct rockchip_pcie *rk_pcie; + struct rt_pci_ep *epc = RT_NULL; + struct rt_device *dev = &pdev->parent; + + if (!(ep = rt_calloc(1, sizeof(*ep)))) + { + return -RT_ENOMEM; + } + + rk_pcie = &ep->rk_pcie; + rk_pcie->is_rc = RT_FALSE; + rk_pcie->dev = dev; + + epc = &ep->epc; + epc->name = rt_dm_dev_get_name(dev); + epc->rc_dev = dev; + epc->ops = &rockchip_pcie_ep_ops; + epc->priv = ep; + + if ((err = rt_pci_ep_register(epc))) + { + goto _fail; + } + + if ((err = rockchip_pcie_ep_ofw_parse(rk_pcie, ep))) + { + return err; + } + + if ((err = rockchip_pcie_enable_clocks(rk_pcie))) + { + return err; + } + + if ((err = rockchip_pcie_init_port(rk_pcie))) + { + goto _err_disable_clocks; + } + + /* Establish the link automatically */ + rockchip_pcie_write(rk_pcie, PCIE_CLIENT_LINK_TRAIN_ENABLE, PCIE_CLIENT_CONFIG); + + max_regions = ep->max_regions; + ep->ob_addr = rt_calloc(max_regions, sizeof(*ep->ob_addr)); + + if (!ep->ob_addr) + { + err = -RT_ENOMEM; + goto _err_uninit_port; + } + + /* Only enable function 0 by default */ + rockchip_pcie_write(rk_pcie, RT_BIT(0), PCIE_CORE_PHY_FUNC_CFG); + + if ((err = rt_pci_ep_mem_init(epc, + rk_pcie->mem_base_addr, rk_pcie->mem_base_size, ARCH_PAGE_SIZE))) + { + goto _fail; + } + + ep->irq_cpu_addr = rt_pci_ep_mem_alloc(epc, &ep->irq_phys_addr, 128 * SIZE_KB); + + if (!ep->irq_cpu_addr) + { + err = -RT_ENOMEM; + goto _err_epc_mem_exit; + } + + ep->irq_pci_addr = RK_PCIE_EP_DUMMY_IRQ_ADDR; + rockchip_pcie_write(rk_pcie, PCIE_CLIENT_CONF_ENABLE, PCIE_CLIENT_CONFIG); + + return RT_EOK; + +_err_epc_mem_exit: + if (ep->irq_phys_addr) + { + if (ep->irq_cpu_addr) + { + rt_iounmap(ep->irq_cpu_addr); + } + + rt_slab_free(ep->addr_slab, (void *)ep->irq_phys_addr); + } + + rt_slab_detach(ep->addr_slab); + +_err_uninit_port: + rockchip_pcie_deinit_phys(rk_pcie); + +_err_disable_clocks: + rockchip_pcie_disable_clocks(rk_pcie); + rockchip_pcie_common_free(rk_pcie); + +_fail: + if (ep) + { + rt_free(ep->ob_addr); + rt_free(ep); + } + + return err; +} + +static const struct rt_ofw_node_id rockchip_pcie_ep_ofw_ids[] = +{ + { .compatible = "rockchip,rk3399-pcie-ep", }, + { /* sentinel */ } +}; + +static struct rt_platform_driver rockchip_pcie_ep_driver = +{ + .name = "rk_pcie-pcie-ep", + .ids = rockchip_pcie_ep_ofw_ids, + + .probe = rockchip_pcie_ep_probe, +}; +RT_PLATFORM_DRIVER_EXPORT(rockchip_pcie_ep_driver); + diff --git a/bsp/rockchip/dm/pci/pcie-rockchip-host.c b/bsp/rockchip/dm/pci/pcie-rockchip-host.c new file mode 100755 index 000000000000..e6608c5b798e --- /dev/null +++ b/bsp/rockchip/dm/pci/pcie-rockchip-host.c @@ -0,0 +1,1259 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-09-23 GuEe-GUI first version + */ + +#define DBG_TAG "pcie.rk-host" +#define DBG_LVL DBG_INFO +#include + +#include "pcie-rockchip.h" + +rt_inline rt_uint8_t __bitrev8(rt_uint8_t x) +{ + x = (x & 0x55) << 1 | (x & 0xaa) >> 1; + x = (x & 0x33) << 2 | (x & 0xcc) >> 2; + x = (x & 0x0f) << 4 | (x & 0xf0) >> 4; + + return x; +} + +static void rockchip_pcie_enable_bw_int(struct rockchip_pcie *rk_pcie) +{ + rt_uint32_t status; + + status = rockchip_pcie_read(rk_pcie, PCIE_RC_CONFIG_LCS); + status |= (PCIEM_LINK_CTL_LBMIE | PCIEM_LINK_CTL_LABIE); + rockchip_pcie_write(rk_pcie, status, PCIE_RC_CONFIG_LCS); +} + +static void rockchip_pcie_clr_bw_int(struct rockchip_pcie *rk_pcie) +{ + rt_uint32_t status; + + status = rockchip_pcie_read(rk_pcie, PCIE_RC_CONFIG_LCS); + status |= (PCIEM_LINK_STA_LINK_BW_MGMT | PCIEM_LINK_STA_LINK_AUTO_BW) << 16; + rockchip_pcie_write(rk_pcie, status, PCIE_RC_CONFIG_LCS); +} + +static void rockchip_pcie_update_txcredit_mui(struct rockchip_pcie *rk_pcie) +{ + rt_uint32_t val; + + /* Update Tx credit maximum update interval */ + val = rockchip_pcie_read(rk_pcie, PCIE_CORE_TXCREDIT_CFG1); + val &= ~PCIE_CORE_TXCREDIT_CFG1_MUI_MASK; + /* NS */ + val |= PCIE_CORE_TXCREDIT_CFG1_MUI_ENCODE(24000); + rockchip_pcie_write(rk_pcie, val, PCIE_CORE_TXCREDIT_CFG1); +} + +static rt_bool_t rockchip_pcie_valid_device(struct rockchip_pcie *rk_pcie, + struct rt_pci_bus *bus, int dev) +{ + if (rt_pci_is_root_bus(bus) || + (bus->parent && rt_pci_is_root_bus(bus->parent))) + { + return dev == 0; + } + + return RT_TRUE; +} + +static void rockchip_pcie_set_power_limit(struct rockchip_pcie *rk_pcie) +{ + int curr; + rt_uint32_t status, scale, power; + + if (rt_is_err(rk_pcie->vpcie3v3)) + { + return; + } + + /* + * Set RC's captured slot power limit and scale if vpcie3v3 available. + * The default values are both zero which means the software + * should set these two according to the actual power supply. + */ + curr = rt_regulator_get_voltage(rk_pcie->vpcie3v3); + if (curr <= 0) + { + return; + } + + scale = 3; /* 0.001x */ + curr = curr / 1000; /* convert to mA */ + power = (curr * 3300) / 1000; /* milliwatt */ + while (power > PCIE_RC_CONFIG_DCR_CSPL_LIMIT) + { + if (!scale) + { + LOG_W("Invalid power supply"); + return; + } + + --scale; + power /= 10; + } + + status = rockchip_pcie_read(rk_pcie, PCIE_RC_CONFIG_DCR); + status |= (power << PCIE_RC_CONFIG_DCR_CSPL_SHIFT) | + (scale << PCIE_RC_CONFIG_DCR_CPLS_SHIFT); + rockchip_pcie_write(rk_pcie, status, PCIE_RC_CONFIG_DCR); +} + +static rt_uint8_t rockchip_pcie_lane_map(struct rockchip_pcie *rk_pcie) +{ + rt_uint8_t map; + rt_uint32_t val; + + if (rk_pcie->legacy_phy) + { + return RT_GENMASK(MAX_LANE_NUM - 1, 0); + } + + val = rockchip_pcie_read(rk_pcie, PCIE_CORE_LANE_MAP); + map = val & PCIE_CORE_LANE_MAP_MASK; + + /* The link may be using a reverse-indexed mapping. */ + if (val & PCIE_CORE_LANE_MAP_REVERSE) + { + map = __bitrev8(map) >> 4; + } + + return map; +} + +static void rockchip_pcie_enable_interrupts(struct rockchip_pcie *rk_pcie) +{ + rockchip_pcie_write(rk_pcie, (PCIE_CLIENT_INT_CLI << 16) & + (~PCIE_CLIENT_INT_CLI), PCIE_CLIENT_INT_MASK); + rockchip_pcie_write(rk_pcie, (rt_uint32_t)(~PCIE_CORE_INT), + PCIE_CORE_INT_MASK); + + rockchip_pcie_enable_bw_int(rk_pcie); + rockchip_pcie_write(rk_pcie, PCIE_UDMA_INT_ENABLE_MASK, + PCIE_APB_CORE_UDMA_BASE + PCIE_UDMA_INT_ENABLE_REG); +} + +static rt_err_t rockchip_pcie_bus_read_own_conf(struct rockchip_pcie *rk_pcie, + int reg, int width, rt_uint32_t *value) +{ + void *addr = rk_pcie->apb_base + PCIE_RC_CONFIG_NORMAL_BASE + reg; + + if (!is_aligned((rt_ubase_t)addr, width)) + { + *value = 0; + return -RT_EINVAL; + } + + if (width == 4) + { + *value = HWREG32(addr); + } + else if (width == 2) + { + *value = HWREG16(addr); + } + else if (width == 1) + { + *value = HWREG8(addr); + } + else + { + *value = 0; + return -RT_EINVAL; + } + + return RT_EOK; +} + +static rt_err_t rockchip_pcie_bus_write_own_conf(struct rockchip_pcie *rk_pcie, + int reg, int width, rt_uint32_t value) +{ + void *addr; + rt_uint32_t mask, tmp, offset; + + offset = reg & ~0x3; + addr = rk_pcie->apb_base + PCIE_RC_CONFIG_NORMAL_BASE + offset; + + if (width == 4) + { + HWREG32(addr) = value; + return RT_EOK; + } + + mask = ~(((1 << (width * 8)) - 1) << ((reg & 0x3) * 8)); + + /* + * N.B. This read/modify/write isn't safe in general because it can + * corrupt RW1C bits in adjacent registers. But the hardware + * doesn't support smaller writes. + */ + tmp = HWREG32(addr) & mask; + tmp |= value << ((reg & 0x3) * 8); + HWREG32(addr) = tmp; + + return RT_EOK; +} + +static rt_err_t rockchip_pcie_bus_read_other_conf(struct rockchip_pcie *rk_pcie, + struct rt_pci_bus *bus, rt_uint32_t devfn, int reg, int width, rt_uint32_t *value) +{ + rt_uint32_t busdev; + + if (rk_pcie->in_remove) + { + return RT_EOK; + } + + busdev = PCIE_ECAM_ADDR(bus->number, RT_PCI_SLOT(devfn), RT_PCI_FUNC(devfn), reg); + + if (!is_aligned(busdev, width)) + { + *value = 0; + return -RT_EINVAL; + } + + if (rt_pci_is_root_bus(bus->parent)) + { + rockchip_pcie_cfg_configuration_accesses(rk_pcie, AXI_WRAPPER_TYPE0_CFG); + } + else + { + rockchip_pcie_cfg_configuration_accesses(rk_pcie, AXI_WRAPPER_TYPE1_CFG); + } + + if (width == 4) + { + *value = HWREG32(rk_pcie->axi_base + busdev); + } + else if (width == 2) + { + *value = HWREG16(rk_pcie->axi_base + busdev); + } + else if (width == 1) + { + *value = HWREG8(rk_pcie->axi_base + busdev); + } + else + { + *value = 0; + return -RT_EINVAL; + } + + return RT_EOK; +} + +static rt_err_t rockchip_pcie_bus_write_other_conf(struct rockchip_pcie *rk_pcie, + struct rt_pci_bus *bus, rt_uint32_t devfn, int reg, int width, rt_uint32_t value) +{ + rt_uint32_t busdev; + + if (rk_pcie->in_remove) + { + return RT_EOK; + } + + busdev = PCIE_ECAM_ADDR(bus->number, RT_PCI_SLOT(devfn), RT_PCI_FUNC(devfn), reg); + if (!is_aligned(busdev, width)) + { + return -RT_EINVAL; + } + + if (rt_pci_is_root_bus(bus->parent)) + { + rockchip_pcie_cfg_configuration_accesses(rk_pcie, AXI_WRAPPER_TYPE0_CFG); + } + else + { + rockchip_pcie_cfg_configuration_accesses(rk_pcie, AXI_WRAPPER_TYPE1_CFG); + } + + if (width == 4) + { + HWREG32(rk_pcie->axi_base + busdev) = value; + } + else if (width == 2) + { + HWREG16(rk_pcie->axi_base + busdev) = value; + } + else if (width == 1) + { + HWREG8(rk_pcie->axi_base + busdev) = value; + } + else + { + return -RT_EINVAL; + } + + return RT_EOK; +} + +static rt_err_t rockchip_pcie_bus_read(struct rt_pci_bus *bus, + rt_uint32_t devfn, int reg, int width, rt_uint32_t *value) +{ + struct rockchip_pcie *rk_pcie = bus->sysdata; + + if (!rockchip_pcie_valid_device(rk_pcie, bus, RT_PCI_SLOT(devfn))) + { + *value = 0xffffffff; + return -RT_EINVAL; + } + + if (rt_pci_is_root_bus(bus)) + { + return rockchip_pcie_bus_read_own_conf(rk_pcie, reg, width, value); + } + + return rockchip_pcie_bus_read_other_conf(rk_pcie, bus, devfn, reg, width, value); +} + +static rt_err_t rockchip_pcie_bus_write(struct rt_pci_bus *bus, + rt_uint32_t devfn, int reg, int width, rt_uint32_t value) +{ + struct rockchip_pcie *rk_pcie = bus->sysdata; + + if (!rockchip_pcie_valid_device(rk_pcie, bus, RT_PCI_SLOT(devfn))) + { + return -RT_EINVAL; + } + + if (rt_pci_is_root_bus(bus)) + { + return rockchip_pcie_bus_write_own_conf(rk_pcie, reg, width, value); + } + + return rockchip_pcie_bus_write_other_conf(rk_pcie, bus, devfn, reg, width, value); +} + +static const struct rt_pci_ops rockchip_pcie_ops = +{ + .read = rockchip_pcie_bus_read, + .write = rockchip_pcie_bus_write, +}; + +static void rockchip_pcie_intx_irq_mask(struct rt_pic_irq *pirq) +{ + struct rockchip_pcie *rk_pcie = pirq->pic->priv_data; + + rt_hw_interrupt_mask(rk_pcie->legacy_irq); +} + +static void rockchip_pcie_intx_irq_unmask(struct rt_pic_irq *pirq) +{ + struct rockchip_pcie *rk_pcie = pirq->pic->priv_data; + + rt_hw_interrupt_umask(rk_pcie->legacy_irq); +} + +static int rockchip_pcie_intx_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); + } + } + else + { + irq = -1; + } + + return irq; +} + +static rt_err_t rockchip_pcie_intx_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; +} + +static const struct rt_pic_ops pcie_intx_ops = +{ + .name = "RK-INTx", + .irq_mask = rockchip_pcie_intx_irq_mask, + .irq_unmask = rockchip_pcie_intx_irq_unmask, + .irq_map = rockchip_pcie_intx_irq_map, + .irq_parse = rockchip_pcie_intx_irq_parse, +}; + +static void rockchip_pcie_subsys_isr(int irqno, void *param) +{ + rt_uint32_t reg, sub_reg; + struct rockchip_pcie *rk_pcie = param; + struct rt_device *dev = rk_pcie->dev; + + RT_UNUSED(dev); + reg = rockchip_pcie_read(rk_pcie, PCIE_CLIENT_INT_STATUS); + sub_reg = rockchip_pcie_read(rk_pcie, PCIE_CORE_INT_STATUS); + + if (reg & PCIE_CLIENT_INT_LOCAL) + { + LOG_D("%s: Local interrupt received", rt_dm_dev_get_name(dev)); + + if (sub_reg & PCIE_CORE_INT_PRFPE) + { + LOG_D("%s: Parity error detected while reading from the PNP receive FIFO RAM", + rt_dm_dev_get_name(dev)); + } + + if (sub_reg & PCIE_CORE_INT_CRFPE) + { + LOG_D("%s: Parity error detected while reading from the Completion Receive FIFO RAM", + rt_dm_dev_get_name(dev)); + } + + if (sub_reg & PCIE_CORE_INT_RRPE) + { + LOG_D("%s: Parity error detected while reading from replay buffer RAM", + rt_dm_dev_get_name(dev)); + } + + if (sub_reg & PCIE_CORE_INT_PRFO) + { + LOG_D("%s: Overflow occurred in the PNP receive FIFO", + rt_dm_dev_get_name(dev)); + } + + if (sub_reg & PCIE_CORE_INT_CRFO) + { + LOG_D("%s: Overflow occurred in the completion receive FIFO", + rt_dm_dev_get_name(dev)); + } + + if (sub_reg & PCIE_CORE_INT_RT) + { + LOG_D("%s: Replay timer timed out", rt_dm_dev_get_name(dev)); + } + + if (sub_reg & PCIE_CORE_INT_RTR) + { + LOG_D("%s: Replay timer rolled over after 4 transmissions of the same TLP", + rt_dm_dev_get_name(dev)); + } + + if (sub_reg & PCIE_CORE_INT_PE) + { + LOG_D("%s: Phy error detected on receive side", + rt_dm_dev_get_name(dev)); + } + + if (sub_reg & PCIE_CORE_INT_MTR) + { + LOG_D("%s: Malformed TLP received from the link", + rt_dm_dev_get_name(dev)); + } + + if (sub_reg & PCIE_CORE_INT_UCR) + { + LOG_D("%s: Malformed TLP received from the link", + rt_dm_dev_get_name(dev)); + } + + if (sub_reg & PCIE_CORE_INT_FCE) + { + LOG_D("%s: An error was observed in the flow control advertisements from the other side", + rt_dm_dev_get_name(dev)); + } + + if (sub_reg & PCIE_CORE_INT_CT) + { + LOG_D("%s: A request timed out waiting for completion", + rt_dm_dev_get_name(dev)); + } + + if (sub_reg & PCIE_CORE_INT_UTC) + { + LOG_D("%s: Unmapped TC error", rt_dm_dev_get_name(dev)); + } + + if (sub_reg & PCIE_CORE_INT_MMVC) + { + LOG_D("%s: MSI mask register changes", rt_dm_dev_get_name(dev)); + } + + rockchip_pcie_write(rk_pcie, sub_reg, PCIE_CORE_INT_STATUS); + } + else if (reg & PCIE_CLIENT_INT_PHY) + { + LOG_D("%s: PHY link changes", rt_dm_dev_get_name(dev)); + rockchip_pcie_update_txcredit_mui(rk_pcie); + rockchip_pcie_clr_bw_int(rk_pcie); + } + + if (reg & PCIE_CLIENT_INT_UDMA) + { + rockchip_pcie_write(rk_pcie, sub_reg, PCIE_CLIENT_INT_STATUS); + rockchip_pcie_write(rk_pcie, reg, PCIE_CLIENT_INT_STATUS); + } + + rockchip_pcie_write(rk_pcie, reg & PCIE_CLIENT_INT_LOCAL, PCIE_CLIENT_INT_STATUS); +} + +static void rockchip_pcie_legacy_intx_isr(int irqno, void *param) +{ + rt_uint32_t reg, hwirq; + struct rt_pic_irq *pirq; + struct rockchip_pcie *rk_pcie = param; + + reg = rockchip_pcie_read(rk_pcie, PCIE_CLIENT_INT_STATUS); + reg = (reg & PCIE_CLIENT_INTR_MASK) >> PCIE_CLIENT_INTR_SHIFT; + + while (reg) + { + hwirq = __rt_ffs(reg) - 1; + reg &= ~RT_BIT(hwirq); + + pirq = rt_pic_find_irq(&rk_pcie->intx_pic, hwirq); + + rt_pic_handle_isr(pirq); + } +} + +static void rockchip_pcie_client_isr(int irqno, void *param) +{ + rt_uint32_t reg; + struct rockchip_pcie *rk_pcie = param; + struct rt_device *dev = rk_pcie->dev; + + RT_UNUSED(dev); + reg = rockchip_pcie_read(rk_pcie, PCIE_CLIENT_INT_STATUS); + + if (reg & PCIE_CLIENT_INT_LEGACY_DONE) + { + LOG_D("%s: Legacy done interrupt received", rt_dm_dev_get_name(dev)); + } + + if (reg & PCIE_CLIENT_INT_MSG) + { + LOG_D("%s: Message done interrupt received", rt_dm_dev_get_name(dev)); + } + + if (reg & PCIE_CLIENT_INT_HOT_RST) + { + LOG_D("%s: Hot reset interrupt received", rt_dm_dev_get_name(dev)); + } + + if (reg & PCIE_CLIENT_INT_DPA) + { + LOG_D("%s: DPA interrupt received", rt_dm_dev_get_name(dev)); + } + + if (reg & PCIE_CLIENT_INT_FATAL_ERR) + { + LOG_D("%s: Fatal error interrupt received", rt_dm_dev_get_name(dev)); + } + + if (reg & PCIE_CLIENT_INT_NFATAL_ERR) + { + LOG_D("%s: No fatal error interrupt received", rt_dm_dev_get_name(dev)); + } + + if (reg & PCIE_CLIENT_INT_CORR_ERR) + { + LOG_D("%s: Correctable error interrupt received", rt_dm_dev_get_name(dev)); + } + + if (reg & PCIE_CLIENT_INT_PHY) + { + LOG_D("%s: PHY interrupt received", rt_dm_dev_get_name(dev)); + } + + rockchip_pcie_write(rk_pcie, reg & (PCIE_CLIENT_INT_LEGACY_DONE | + PCIE_CLIENT_INT_MSG | PCIE_CLIENT_INT_HOT_RST | + PCIE_CLIENT_INT_DPA | PCIE_CLIENT_INT_FATAL_ERR | + PCIE_CLIENT_INT_NFATAL_ERR | + PCIE_CLIENT_INT_CORR_ERR | + PCIE_CLIENT_INT_PHY), PCIE_CLIENT_INT_STATUS); +} + +static rt_err_t rockchip_pcie_host_ofw_parse(struct rockchip_pcie *rk_pcie) +{ + rt_err_t err; + struct rt_device *dev = rk_pcie->dev; + + if ((err = rockchip_pcie_ofw_parse(rk_pcie))) + { + return err; + } + + rk_pcie->vpcie12v = rt_regulator_get(dev, "vpcie12v"); + if (rt_is_err(rk_pcie->vpcie12v)) + { + return rt_ptr_err(rk_pcie->vpcie12v); + } + + rk_pcie->vpcie3v3 = rt_regulator_get(dev, "vpcie3v3"); + if (rt_is_err(rk_pcie->vpcie3v3)) + { + return rt_ptr_err(rk_pcie->vpcie3v3); + } + + rk_pcie->vpcie1v8 = rt_regulator_get(dev, "vpcie1v8"); + if (rt_is_err(rk_pcie->vpcie1v8)) + { + return rt_ptr_err(rk_pcie->vpcie1v8); + } + + rk_pcie->vpcie0v9 = rt_regulator_get(dev, "vpcie0v9"); + if (rt_is_err(rk_pcie->vpcie0v9)) + { + return rt_ptr_err(rk_pcie->vpcie0v9); + } + + return RT_EOK; +} + +static rt_err_t rockchip_pcie_set_vpcie(struct rockchip_pcie *rk_pcie) +{ + rt_err_t err; + + if (rk_pcie->vpcie12v && (err = rt_regulator_enable(rk_pcie->vpcie12v))) + { + return err; + } + + if (rk_pcie->vpcie3v3 && (err = rt_regulator_enable(rk_pcie->vpcie3v3))) + { + goto _err_disable_12v; + } + + if ((err = rt_regulator_enable(rk_pcie->vpcie1v8))) + { + goto _err_disable_3v3; + } + + if ((err = rt_regulator_enable(rk_pcie->vpcie0v9))) + { + goto _err_disable_1v8; + } + + return RT_EOK; + +_err_disable_1v8: + rt_regulator_disable(rk_pcie->vpcie1v8); + +_err_disable_3v3: + if (!rt_is_err(rk_pcie->vpcie3v3)) + { + rt_regulator_disable(rk_pcie->vpcie3v3); + } + +_err_disable_12v: + if (!rt_is_err(rk_pcie->vpcie12v)) + { + rt_regulator_disable(rk_pcie->vpcie12v); + } + + return err; +} + +static rt_err_t rockchip_pcie_host_init_port(struct rockchip_pcie *rk_pcie) +{ + rt_err_t err; + rt_uint32_t status, timeouts = 500; + struct rt_device *dev = rk_pcie->dev; + + rt_pin_write(rk_pcie->ep_pin, !rk_pcie->active_val); + + if ((err = rockchip_pcie_init_port(rk_pcie))) + { + return err; + } + + /* Fix the transmitted FTS count desired to exit from L0s. */ + status = rockchip_pcie_read(rk_pcie, PCIE_CORE_CTRL_PLC1); + status = (status & ~PCIE_CORE_CTRL_PLC1_FTS_MASK) | + (PCIE_CORE_CTRL_PLC1_FTS_CNT << PCIE_CORE_CTRL_PLC1_FTS_SHIFT); + rockchip_pcie_write(rk_pcie, status, PCIE_CORE_CTRL_PLC1); + + rockchip_pcie_set_power_limit(rk_pcie); + + /* Set RC's clock architecture as common clock */ + status = rockchip_pcie_read(rk_pcie, PCIE_RC_CONFIG_LCS); + status |= PCIEM_LINK_STA_SLOT_CLOCK << 16; + rockchip_pcie_write(rk_pcie, status, PCIE_RC_CONFIG_LCS); + + /* Set RC's RCB to 128 */ + status = rockchip_pcie_read(rk_pcie, PCIE_RC_CONFIG_LCS); + status |= PCIEM_LINK_CTL_RCB; + rockchip_pcie_write(rk_pcie, status, PCIE_RC_CONFIG_LCS); + + /* Enable Gen1 training */ + rockchip_pcie_write(rk_pcie, PCIE_CLIENT_LINK_TRAIN_ENABLE, + PCIE_CLIENT_CONFIG); + + rt_pin_write(rk_pcie->ep_pin, rk_pcie->active_val); + + if (rk_pcie->wait_ep) + { + timeouts = 10000; + } + + /* 500ms timeout value should be enough for Gen1/2 training */ + err = readl_poll_timeout(rk_pcie->apb_base + PCIE_CLIENT_BASIC_STATUS1, + status, PCIE_LINK_UP(status), 20, timeouts * 1000L); + if (err) + { + LOG_E("PCIe link training gen1 timeout"); + goto _err_power_off_phy; + } + + err = readl_poll_timeout(rk_pcie->apb_base + PCIE_CLIENT_DEBUG_OUT_0, + status, PCIE_LINK_IS_L0(status), 20, timeouts * 1000L); + if (err) + { + LOG_E("LTSSM is not L0"); + return -ETIMEDOUT; + } + + if (rk_pcie->link_gen == 2) + { + /* + * Enable retrain for gen2. This should be configured only after + * gen1 finished. + */ + status = rockchip_pcie_read(rk_pcie, PCIE_RC_CONFIG_LCS); + status |= PCIEM_LINK_CTL_RETRAIN_LINK; + rockchip_pcie_write(rk_pcie, status, PCIE_RC_CONFIG_LCS); + + err = readl_poll_timeout(rk_pcie->apb_base + PCIE_CORE_CTRL, + status, PCIE_LINK_IS_GEN2(status), 20, 500 * 1000L); + + if (err) + { + LOG_D("PCIe link training gen2 timeout, fall back to gen1"); + } + } + + /* Check the final link width from negotiated lane counter from MGMT */ + status = rockchip_pcie_read(rk_pcie, PCIE_CORE_CTRL); + status = 0x1 << ((status & PCIE_CORE_PL_CONF_LANE_MASK) >> + PCIE_CORE_PL_CONF_LANE_SHIFT); + + /* Power off unused lane(s) */ + rk_pcie->lanes_map = rockchip_pcie_lane_map(rk_pcie); + for (int i = 0; i < MAX_LANE_NUM; ++i) + { + if (!(rk_pcie->lanes_map & RT_BIT(i))) + { + rt_phye_power_off(rk_pcie->phys[i]); + } + } + + rockchip_pcie_write(rk_pcie, RK_VENDOR_ID, PCIE_CORE_CONFIG_VENDOR); + rockchip_pcie_write(rk_pcie, PCIS_BRIDGE_PCI << PCIE_RC_CONFIG_SCC_SHIFT, + PCIE_RC_CONFIG_RID_CCR); + + /* Clear THP cap's next cap pointer to remove L1 substate cap */ + status = rockchip_pcie_read(rk_pcie, PCIE_RC_CONFIG_THP_CAP); + status &= ~PCIE_RC_CONFIG_THP_CAP_NEXT_MASK; + rockchip_pcie_write(rk_pcie, status, PCIE_RC_CONFIG_THP_CAP); + + /* Clear L0s from RC's link cap */ + if (rt_dm_dev_prop_read_bool(dev, "aspm-no-l0s")) + { + status = rockchip_pcie_read(rk_pcie, PCIE_RC_CONFIG_LINK_CAP); + status &= ~PCIE_RC_CONFIG_LINK_CAP_L0S; + rockchip_pcie_write(rk_pcie, status, PCIE_RC_CONFIG_LINK_CAP); + } + + status = rockchip_pcie_read(rk_pcie, PCIE_RC_CONFIG_DCSR); + status &= ~PCIE_RC_CONFIG_DCSR_MPS_MASK; + status |= PCIE_RC_CONFIG_DCSR_MPS_256; + rockchip_pcie_write(rk_pcie, status, PCIE_RC_CONFIG_DCSR); + + return RT_EOK; + +_err_power_off_phy: + for (int i = 0; i < MAX_LANE_NUM; ++i) + { + rt_phye_power_off(rk_pcie->phys[i]); + } + + for (int i = 0; i < MAX_LANE_NUM; ++i) + { + rt_phye_exit(rk_pcie->phys[i]); + } + + return err; +} + +static rt_err_t rockchip_pcie_setup_irq(struct rockchip_pcie *rk_pcie) +{ + struct rt_device *dev = rk_pcie->dev; + struct rt_ofw_node *np = dev->ofw_node, *intx_np; + + rk_pcie->sys_irq = rt_dm_dev_get_irq_by_name(dev, "sys"); + if (rk_pcie->sys_irq < 0) + { + return rk_pcie->sys_irq; + } + + rk_pcie->legacy_irq = rt_dm_dev_get_irq_by_name(dev, "legacy"); + if (rk_pcie->legacy_irq < 0) + { + return rk_pcie->legacy_irq; + } + + rk_pcie->client_irq = rt_dm_dev_get_irq_by_name(dev, "client"); + if (rk_pcie->client_irq < 0) + { + return rk_pcie->client_irq; + } + + intx_np = rt_ofw_get_next_child(np, RT_NULL); + + if (!intx_np) + { + LOG_E("Missing child interrupt-controller node"); + return -RT_EINVAL; + } + + rk_pcie->intx_np = intx_np; + rk_pcie->intx_pic.priv_data = rk_pcie; + rk_pcie->intx_pic.ops = &pcie_intx_ops; + rt_pic_linear_irq(&rk_pcie->intx_pic, RT_PCI_INTX_PIN_MAX); + rt_pic_user_extends(&rk_pcie->intx_pic); + rt_ofw_data(intx_np) = &rk_pcie->intx_pic; + + rt_ofw_node_put(intx_np); + + rt_hw_interrupt_install(rk_pcie->sys_irq, rockchip_pcie_subsys_isr, + rk_pcie, "rk-pcie-sys"); + rt_hw_interrupt_install(rk_pcie->legacy_irq, rockchip_pcie_legacy_intx_isr, + rk_pcie, "rk-pcie-legacy"); + rt_hw_interrupt_install(rk_pcie->client_irq, rockchip_pcie_client_isr, + rk_pcie, "rk-pcie-client"); + + return RT_EOK; +} + +static rt_err_t rockchip_pcie_prog_ob_atu(struct rockchip_pcie *rk_pcie, + int region_no, int type, rt_uint8_t num_pass_bits, + rt_uint32_t lower_addr, rt_uint32_t upper_addr) +{ + rt_uint32_t ob_addr_0, ob_addr_1, ob_desc_0, aw_offset; + + if (region_no >= MAX_AXI_WRAPPER_REGION_NUM) + { + return -RT_EINVAL; + } + + if (num_pass_bits + 1 < 8) + { + return -RT_EINVAL; + } + + if (num_pass_bits > 63) + { + return -RT_EINVAL; + } + + if (region_no == 0) + { + if (AXI_REGION_0_SIZE < (2ULL << num_pass_bits)) + { + return -RT_EINVAL; + } + } + if (region_no != 0) + { + if (AXI_REGION_SIZE < (2ULL << num_pass_bits)) + { + return -RT_EINVAL; + } + } + + aw_offset = (region_no << OB_REG_SIZE_SHIFT); + + ob_addr_0 = num_pass_bits & PCIE_CORE_OB_REGION_ADDR0_NUM_BITS; + ob_addr_0 |= lower_addr & PCIE_CORE_OB_REGION_ADDR0_LO_ADDR; + ob_addr_1 = upper_addr; + ob_desc_0 = (1 << 23 | type); + + rockchip_pcie_write(rk_pcie, ob_addr_0, PCIE_CORE_OB_REGION_ADDR0 + aw_offset); + rockchip_pcie_write(rk_pcie, ob_addr_1, PCIE_CORE_OB_REGION_ADDR1 + aw_offset); + rockchip_pcie_write(rk_pcie, ob_desc_0, PCIE_CORE_OB_REGION_DESC0 + aw_offset); + rockchip_pcie_write(rk_pcie, 0, PCIE_CORE_OB_REGION_DESC1 + aw_offset); + + return RT_EOK; +} + +static rt_err_t rockchip_pcie_prog_ib_atu(struct rockchip_pcie *rk_pcie, + int region_no, rt_uint8_t num_pass_bits, + rt_uint32_t lower_addr, rt_uint32_t upper_addr) +{ + rt_uint32_t ib_addr_0, ib_addr_1, aw_offset; + + if (region_no > MAX_AXI_IB_ROOTPORT_REGION_NUM) + { + return -RT_EINVAL; + } + + if (num_pass_bits + 1 < MIN_AXI_ADDR_BITS_PASSED) + { + return -RT_EINVAL; + } + + if (num_pass_bits > 63) + { + return -RT_EINVAL; + } + + aw_offset = (region_no << IB_ROOT_PORT_REG_SIZE_SHIFT); + + ib_addr_0 = num_pass_bits & PCIE_CORE_IB_REGION_ADDR0_NUM_BITS; + ib_addr_0 |= (lower_addr << 8) & PCIE_CORE_IB_REGION_ADDR0_LO_ADDR; + ib_addr_1 = upper_addr; + + rockchip_pcie_write(rk_pcie, ib_addr_0, PCIE_RP_IB_ADDR0 + aw_offset); + rockchip_pcie_write(rk_pcie, ib_addr_1, PCIE_RP_IB_ADDR1 + aw_offset); + + return RT_EOK; +} + +static rt_err_t rockchip_pcie_cfg_atu(struct rockchip_pcie *rk_pcie) +{ + rt_err_t err; + int reg_no; + rt_off_t offset; + rt_uint64_t pci_addr, size; + struct rt_pci_bus_region *region = RT_NULL; + struct rt_pci_host_bridge *bridge = rk_pcie->bridge; + + rockchip_pcie_cfg_configuration_accesses(rk_pcie, AXI_WRAPPER_TYPE0_CFG); + + for (int i = 0; i < bridge->bus_regions_nr; ++i) + { + if (bridge->bus_regions[i].flags == PCI_BUS_REGION_F_MEM) + { + region = &bridge->bus_regions[i]; + break; + } + } + + if (!region) + { + return -RT_ENOSYS; + } + + size = region->size; + pci_addr = region->phy_addr; + rk_pcie->msg_bus_addr = pci_addr; + + for (reg_no = 0; reg_no < (size >> 20); ++reg_no) + { + err = rockchip_pcie_prog_ob_atu(rk_pcie, reg_no + 1, + AXI_WRAPPER_MEM_WRITE, 20 - 1, pci_addr + (reg_no << 20), 0); + + if (err) + { + LOG_E("Program RC mem outbound ATU error = %s", rt_strerror(err)); + return err; + } + } + + if ((err = rockchip_pcie_prog_ib_atu(rk_pcie, 2, 32 - 1, 0x0, 0))) + { + LOG_E("Program RC mem inbound ATU error = %s", rt_strerror(err)); + return err; + } + + /* Store the register number offset to program RC io outbound ATU */ + offset = size >> 20; + + region = RT_NULL; + for (int i = 0; i < bridge->bus_regions_nr; ++i) + { + if (bridge->bus_regions[i].flags == PCI_BUS_REGION_F_IO) + { + region = &bridge->bus_regions[i]; + break; + } + } + + size = region->size; + pci_addr = region->phy_addr; + + for (reg_no = 0; reg_no < (size >> 20); ++reg_no) + { + err = rockchip_pcie_prog_ob_atu(rk_pcie, reg_no + 1 + offset, + AXI_WRAPPER_IO_WRITE, 20 - 1, pci_addr + (reg_no << 20), 0); + + if (err) + { + LOG_E("Program RC io outbound ATU error = %s", rt_strerror(err)); + return err; + } + } + + /* Assign message regions */ + rockchip_pcie_prog_ob_atu(rk_pcie, reg_no + 1 + offset, + AXI_WRAPPER_NOR_MSG, 20 - 1, 0, 0); + + rk_pcie->msg_bus_addr += (reg_no + offset) << 20; + rk_pcie->msg_region = rt_ioremap((void *)rk_pcie->msg_bus_addr, SIZE_MB); + if (!rk_pcie->msg_region) + { + err = -RT_ENOMEM; + } + + return err; +} + +#ifdef RT_USING_PM +static int rockchip_pcie_pm_suspend(const struct rt_device *dev, rt_uint8_t mode) +{ + struct rockchip_pcie *rk_pcie = dev->user_data; + + rockchip_pcie_disable_clocks(rk_pcie); + rt_regulator_disable(rk_pcie->vpcie0v9); + + return RT_EOK; +} + +static void rockchip_pcie_pm_resume(const struct rt_device *dev, rt_uint8_t mode) +{ + struct rockchip_pcie *rk_pcie = dev->user_data; + + if (rt_regulator_enable(rk_pcie->vpcie0v9)) + { + LOG_E("Fail to enable vpcie0v9 regulator"); + return; + } + + if (rockchip_pcie_enable_clocks(rk_pcie)) + { + rt_regulator_disable(rk_pcie->vpcie0v9); + } +} + +static const struct rt_device_pm_ops rockchip_pcie_pm_ops = +{ + .suspend = rockchip_pcie_pm_suspend, + .resume = rockchip_pcie_pm_resume, +}; +#endif /* RT_USING_PM */ + +static void rockchip_pcie_free(struct rockchip_pcie *rk_pcie) +{ + rockchip_pcie_common_free(rk_pcie); + + if (rk_pcie->sys_irq > 0) + { + rt_hw_interrupt_mask(rk_pcie->sys_irq); + rt_pic_detach_irq(rk_pcie->sys_irq, rk_pcie); + } + + if (rk_pcie->legacy_irq > 0) + { + rt_hw_interrupt_mask(rk_pcie->legacy_irq); + rt_pic_detach_irq(rk_pcie->legacy_irq, rk_pcie); + } + + if (rk_pcie->client_irq > 0) + { + rt_hw_interrupt_mask(rk_pcie->client_irq); + rt_pic_detach_irq(rk_pcie->client_irq, rk_pcie); + } + + rt_pci_host_bridge_free(rk_pcie->bridge); + rt_free(rk_pcie); +} + +static rt_err_t rockchip_pcie_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + struct rockchip_pcie *rk_pcie; + struct rt_pci_host_bridge *bridge; + struct rt_device *dev = &pdev->parent; + + if (!(bridge = rt_pci_host_bridge_alloc(sizeof(*rk_pcie)))) + { + return -RT_ENOMEM; + } + + rk_pcie = (void *)bridge->priv; + rk_pcie->bridge = bridge; + rk_pcie->dev = dev; + rk_pcie->is_rc = RT_TRUE; + + if ((err = rockchip_pcie_host_ofw_parse(rk_pcie))) + { + return err; + } + + if ((err = rockchip_pcie_enable_clocks(rk_pcie))) + { + return err; + } + + if ((err = rockchip_pcie_set_vpcie(rk_pcie))) + { + goto _err_set_vpcie; + } + + if ((err = rockchip_pcie_host_init_port(rk_pcie))) + { + goto _err_deinit_port; + } + + if ((err = rockchip_pcie_setup_irq(rk_pcie))) + { + goto _err_deinit_port; + } + + rockchip_pcie_enable_interrupts(rk_pcie); + + if ((err = rockchip_pcie_cfg_atu(rk_pcie))) + { + goto _err_deinit_port; + } + + rk_pcie->bridge->parent.ofw_node = dev->ofw_node; + rk_pcie->bridge->sysdata = rk_pcie; + rk_pcie->bridge->ops = &rockchip_pcie_ops; + dev->user_data = rk_pcie; + + if ((err = rt_pci_host_bridge_probe(rk_pcie->bridge))) + { + goto _err_deinit_port; + } + +#ifdef RT_USING_PM + rt_pm_device_register(dev, &rockchip_pcie_pm_ops); +#endif + + return RT_EOK; + +_err_deinit_port: + if (rk_pcie->intx_np) + { + rt_pic_cancel_irq(&rk_pcie->intx_pic); + } + + rockchip_pcie_deinit_phys(rk_pcie); + + if (!rt_is_err_or_null(rk_pcie->vpcie12v)) + { + rt_regulator_disable(rk_pcie->vpcie12v); + rt_regulator_put(rk_pcie->vpcie12v); + } + if (!rt_is_err_or_null(rk_pcie->vpcie3v3)) + { + rt_regulator_disable(rk_pcie->vpcie3v3); + rt_regulator_put(rk_pcie->vpcie3v3); + } + rt_regulator_disable(rk_pcie->vpcie1v8); + rt_regulator_put(rk_pcie->vpcie1v8); + rt_regulator_disable(rk_pcie->vpcie0v9); + rt_regulator_put(rk_pcie->vpcie0v9); + +_err_set_vpcie: + rockchip_pcie_disable_clocks(rk_pcie); + rockchip_pcie_free(rk_pcie); + + return err; +} + +static rt_err_t rockchip_pcie_remove(struct rt_platform_device *pdev) +{ + rt_uint32_t status, status1, status2; + struct rockchip_pcie *rk_pcie = pdev->parent.user_data; + + rt_pci_host_bridge_remove(rk_pcie->bridge); + + rt_ofw_data(rk_pcie->intx_np) = RT_NULL; + + rt_hw_interrupt_mask(rk_pcie->sys_irq); + rt_pic_detach_irq(rk_pcie->sys_irq, rk_pcie); + rt_hw_interrupt_mask(rk_pcie->legacy_irq); + rt_pic_detach_irq(rk_pcie->legacy_irq, rk_pcie); + rt_hw_interrupt_mask(rk_pcie->client_irq); + rt_pic_detach_irq(rk_pcie->client_irq, rk_pcie); + +#ifdef RT_USING_PM + rt_pm_device_unregister(&pdev->parent); +#endif + + status1 = rockchip_pcie_read(rk_pcie, PCIE_CLIENT_BASIC_STATUS1); + status2 = rockchip_pcie_read(rk_pcie, PCIE_CLIENT_DEBUG_OUT_0); + + if (!PCIE_LINK_UP(status1) || !PCIE_LINK_IS_L0(status2)) + { + rk_pcie->in_remove = RT_TRUE; + } + + /* Disable link state */ + status = rockchip_pcie_read(rk_pcie, PCIE_RC_CONFIG_LCS); + status |= RT_BIT(4); + rockchip_pcie_write(rk_pcie, status, PCIE_RC_CONFIG_LCS); + + rt_thread_mdelay(1); + + status = rockchip_pcie_read(rk_pcie, PCIE_RC_CONFIG_LCS); + status &= ~RT_BIT(4); + rockchip_pcie_write(rk_pcie, status, PCIE_RC_CONFIG_LCS); + + rockchip_pcie_deinit_phys(rk_pcie); + + rockchip_pcie_disable_clocks(rk_pcie); + + if (!rt_is_err_or_null(rk_pcie->vpcie12v)) + { + rt_regulator_disable(rk_pcie->vpcie12v); + } + if (!rt_is_err_or_null(rk_pcie->vpcie3v3)) + { + rt_regulator_disable(rk_pcie->vpcie3v3); + } + rt_regulator_disable(rk_pcie->vpcie1v8); + rt_regulator_disable(rk_pcie->vpcie0v9); + + rockchip_pcie_free(rk_pcie); + + return RT_EOK; +} + +static const struct rt_ofw_node_id rockchip_pcie_ofw_ids[] = +{ + { .compatible = "rockchip,rk3399-pcie", }, + { /* sentinel */ } +}; + +static struct rt_platform_driver rockchip_pcie_driver = +{ + .name = "rk_pcie-pcie-host", + .ids = rockchip_pcie_ofw_ids, + + .probe = rockchip_pcie_probe, + .remove = rockchip_pcie_remove, +}; +RT_PLATFORM_DRIVER_EXPORT(rockchip_pcie_driver); diff --git a/bsp/rockchip/dm/pci/pcie-rockchip.c b/bsp/rockchip/dm/pci/pcie-rockchip.c new file mode 100755 index 000000000000..5a481e6adc8b --- /dev/null +++ b/bsp/rockchip/dm/pci/pcie-rockchip.c @@ -0,0 +1,528 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-09-23 GuEe-GUI first version + */ + +#define DBG_TAG "pcie.rk" +#define DBG_LVL DBG_INFO +#include + +#include "pcie-rockchip.h" + +#define rockchip_pcie_read_addr(addr) rockchip_pcie_read(rk_pcie, addr) +/* 100 ms max wait time for PHY PLLs to lock */ +#define RK_PHY_PLL_LOCK_TIMEOUT_US 100000 +/* Sleep should be less than 20ms */ +#define RK_PHY_PLL_LOCK_SLEEP_US 1000 + +rt_err_t rockchip_pcie_ofw_parse(struct rockchip_pcie *rk_pcie) +{ + rt_err_t err; + struct rt_device *dev = rk_pcie->dev; + + if (rk_pcie->is_rc) + { + rk_pcie->axi_base = rt_dm_dev_iomap_by_name(dev, "axi-base"); + + if (!rk_pcie->axi_base) + { + return -RT_EIO; + } + } + else + { + if ((err = rt_dm_dev_get_address_by_name(dev, "mem-base", + &rk_pcie->mem_base_addr, &rk_pcie->mem_base_size))) + { + return err; + } + } + + rk_pcie->apb_base = rt_dm_dev_iomap_by_name(dev, "apb-base"); + + if (!rk_pcie->apb_base) + { + err = -RT_EIO; + goto _fail; + } + + if ((err = rockchip_pcie_get_phys(rk_pcie))) + { + goto _fail; + } + + rk_pcie->num_lanes = 1; + err = rt_dm_dev_prop_read_u32(dev, "num-lanes", &rk_pcie->num_lanes); + if (!err && (rk_pcie->num_lanes == 0 || rk_pcie->num_lanes == 3 || rk_pcie->num_lanes > 4)) + { + rk_pcie->num_lanes = 1; + } + + rk_pcie->link_gen = -1; + rt_dm_dev_prop_read_u32(dev, "max-link-speed", &rk_pcie->link_gen); + if (rk_pcie->link_gen < 0 || rk_pcie->link_gen > 2) + { + rk_pcie->link_gen = 2; + } + + rk_pcie->core_rstc = rt_reset_control_get_by_name(dev, "core"); + if (rt_is_err(rk_pcie->core_rstc)) + { + err = rt_ptr_err(rk_pcie->core_rstc); + goto _fail; + } + + rk_pcie->mgmt_rstc = rt_reset_control_get_by_name(dev, "mgmt"); + if (rt_is_err(rk_pcie->mgmt_rstc)) + { + err = rt_ptr_err(rk_pcie->mgmt_rstc); + goto _fail; + } + + rk_pcie->mgmt_sticky_rstc = rt_reset_control_get_by_name(dev, "mgmt-sticky"); + if (rt_is_err(rk_pcie->mgmt_sticky_rstc)) + { + err = rt_ptr_err(rk_pcie->mgmt_sticky_rstc); + goto _fail; + } + + rk_pcie->pipe_rstc = rt_reset_control_get_by_name(dev, "pipe"); + if (rt_is_err(rk_pcie->pipe_rstc)) + { + err = rt_ptr_err(rk_pcie->pipe_rstc); + goto _fail; + } + + rk_pcie->pm_rstc = rt_reset_control_get_by_name(dev, "pm"); + if (rt_is_err(rk_pcie->pm_rstc)) + { + err = rt_ptr_err(rk_pcie->pm_rstc); + goto _fail; + } + + rk_pcie->pclk_rstc = rt_reset_control_get_by_name(dev, "pclk"); + if (rt_is_err(rk_pcie->pclk_rstc)) + { + err = rt_ptr_err(rk_pcie->pclk_rstc); + goto _fail; + } + + rk_pcie->aclk_rstc = rt_reset_control_get_by_name(dev, "aclk"); + if (rt_is_err(rk_pcie->aclk_rstc)) + { + err = rt_ptr_err(rk_pcie->aclk_rstc); + goto _fail; + } + + if (rk_pcie->is_rc) + { + rt_uint8_t mode; + + rk_pcie->ep_pin = rt_pin_get_named_pin(dev, "ep", 0, &mode, &rk_pcie->active_val); + + if (rk_pcie->ep_pin < 0 && rk_pcie->ep_pin != PIN_NONE) + { + err = rk_pcie->ep_pin; + goto _fail; + } + else if (rk_pcie->ep_pin >= 0) + { + rt_pin_mode(rk_pcie->ep_pin, mode); + } + } + + rk_pcie->aclk_pcie = rt_clk_get_by_name(dev, "aclk"); + if (rt_is_err(rk_pcie->aclk_pcie)) + { + err = rt_ptr_err(rk_pcie->aclk_pcie); + goto _fail; + } + + rk_pcie->aclk_perf_pcie = rt_clk_get_by_name(dev, "aclk-perf"); + if (rt_is_err(rk_pcie->aclk_perf_pcie)) + { + err = rt_ptr_err(rk_pcie->aclk_perf_pcie); + goto _fail; + } + + rk_pcie->hclk_pcie = rt_clk_get_by_name(dev, "hclk"); + if (rt_is_err(rk_pcie->hclk_pcie)) + { + err = rt_ptr_err(rk_pcie->hclk_pcie); + goto _fail; + } + + rk_pcie->clk_pcie_pm = rt_clk_get_by_name(dev, "pm"); + if (rt_is_err(rk_pcie->clk_pcie_pm)) + { + err = rt_ptr_err(rk_pcie->clk_pcie_pm); + goto _fail; + } + + return RT_EOK; + +_fail: + rockchip_pcie_common_free(rk_pcie); + + return err; +} + +rt_err_t rockchip_pcie_init_port(struct rockchip_pcie *rk_pcie) +{ + rt_err_t err; + rt_uint32_t regs; + + if ((err = rt_reset_control_assert(rk_pcie->aclk_rstc))) + { + LOG_E("Assert aclk_rstc error = %s", rt_strerror(err)); + return err; + } + + if ((err = rt_reset_control_assert(rk_pcie->pclk_rstc))) + { + LOG_E("Assert pclk_rstc error = %s", rt_strerror(err)); + return err; + } + + if ((err = rt_reset_control_assert(rk_pcie->pm_rstc))) + { + LOG_E("Assert pm_rstc error = %s", rt_strerror(err)); + return err; + } + + for (int i = 0; i < MAX_LANE_NUM; i++) + { + if ((err = rt_phye_init(rk_pcie->phys[i]))) + { + LOG_E("Init phy%d err %d", i, err); + goto _err_exit_phy; + } + } + + if ((err = rt_reset_control_assert(rk_pcie->core_rstc))) + { + LOG_E("Assert core_rstc error = %s", rt_strerror(err)); + goto _err_exit_phy; + } + + if ((err = rt_reset_control_assert(rk_pcie->mgmt_rstc))) + { + LOG_E("Assert mgmt_rstc error = %s", rt_strerror(err)); + goto _err_exit_phy; + } + + if ((err = rt_reset_control_assert(rk_pcie->mgmt_sticky_rstc))) + { + LOG_E("Assert mgmt_sticky_rstc error = %s", rt_strerror(err)); + goto _err_exit_phy; + } + + if ((err = rt_reset_control_assert(rk_pcie->pipe_rstc))) + { + LOG_E("Assert pipe_rstc error = %s", rt_strerror(err)); + goto _err_exit_phy; + } + + rt_hw_us_delay(10); + + if ((err = rt_reset_control_deassert(rk_pcie->pm_rstc))) + { + LOG_E("Deassert pm_rstc error = %s", rt_strerror(err)); + goto _err_exit_phy; + } + + if ((err = rt_reset_control_deassert(rk_pcie->aclk_rstc))) + { + LOG_E("Deassert aclk_rstc error = %s", rt_strerror(err)); + goto _err_exit_phy; + } + + if ((err = rt_reset_control_deassert(rk_pcie->pclk_rstc))) + { + LOG_E("Deassert pclk_rstc error = %s", rt_strerror(err)); + goto _err_exit_phy; + } + + if (rk_pcie->link_gen == 2) + { + rockchip_pcie_write(rk_pcie, PCIE_CLIENT_GEN_SEL_2, PCIE_CLIENT_CONFIG); + } + else + { + rockchip_pcie_write(rk_pcie, PCIE_CLIENT_GEN_SEL_1, PCIE_CLIENT_CONFIG); + } + + regs = PCIE_CLIENT_LINK_TRAIN_ENABLE | PCIE_CLIENT_ARI_ENABLE | + PCIE_CLIENT_CONF_LANE_NUM(rk_pcie->num_lanes); + + if (rk_pcie->is_rc) + { + regs |= PCIE_CLIENT_CONF_ENABLE | PCIE_CLIENT_MODE_RC; + } + else + { + regs |= PCIE_CLIENT_CONF_DISABLE | PCIE_CLIENT_MODE_EP; + } + + rockchip_pcie_write(rk_pcie, regs, PCIE_CLIENT_CONFIG); + + for (int i = 0; i < MAX_LANE_NUM; ++i) + { + if ((err = rt_phye_power_on(rk_pcie->phys[i]))) + { + LOG_E("Power on PHY(%d) error = %s", i, rt_strerror(err)); + goto _err_power_off_phy; + } + } + + err = readx_poll_timeout(rockchip_pcie_read_addr, + PCIE_CLIENT_SIDE_BAND_STATUS, regs, !(regs & PCIE_CLIENT_PHY_ST), + RK_PHY_PLL_LOCK_SLEEP_US, RK_PHY_PLL_LOCK_TIMEOUT_US); + + if (err) + { + LOG_E("PHY PLLs could not lock, %d", err); + goto _err_power_off_phy; + } + + /* + * Please don't reorder the deassert sequence of the following + * four reset pins. + */ + if ((err = rt_reset_control_deassert(rk_pcie->mgmt_sticky_rstc))) + { + LOG_E("Deassert mgmt_sticky_rstc error = %s", rt_strerror(err)); + goto _err_power_off_phy; + } + + if ((err = rt_reset_control_deassert(rk_pcie->core_rstc))) + { + LOG_E("Deassert core_rstc error = %s", rt_strerror(err)); + goto _err_power_off_phy; + } + + if ((err = rt_reset_control_deassert(rk_pcie->mgmt_rstc))) + { + LOG_E("Deassert mgmt_rstc error = %s", rt_strerror(err)); + goto _err_power_off_phy; + } + + if ((err = rt_reset_control_deassert(rk_pcie->pipe_rstc))) + { + LOG_E("Deassert pipe_rstc error = %s", rt_strerror(err)); + goto _err_power_off_phy; + } + + return RT_EOK; + +_err_power_off_phy: + for (int i = 0; i < MAX_LANE_NUM; ++i) + { + rt_phye_power_off(rk_pcie->phys[i]); + } + +_err_exit_phy: + for (int i = 0; i < MAX_LANE_NUM; ++i) + { + rt_phye_exit(rk_pcie->phys[i]); + } + + return err; +} + +rt_err_t rockchip_pcie_get_phys(struct rockchip_pcie *rk_pcie) +{ + char name[16]; + struct rt_phye *phy; + struct rt_device *dev = rk_pcie->dev; + + phy = rt_phye_get_by_name(dev, "pcie-phy"); + + if (!rt_is_err_or_null(phy)) + { + rk_pcie->legacy_phy = RT_TRUE; + rk_pcie->phys[0] = phy; + + LOG_W("legacy phy model is deprecated"); + return RT_EOK; + } + + for (int i = 0; i < MAX_LANE_NUM; ++i) + { + rt_snprintf(name, sizeof(name), "pcie-phy-%u", i); + + phy = rt_phye_get_by_name(dev, name); + + if (rt_is_err(phy)) + { + LOG_E("Missing phy for lane %u", i); + return rt_ptr_err(phy); + } + + rk_pcie->phys[i] = phy; + } + + return RT_EOK; +} + +void rockchip_pcie_deinit_phys(struct rockchip_pcie *rk_pcie) +{ + for (int i = 0; i < MAX_LANE_NUM; ++i) + { + struct rt_phye *phy = rk_pcie->phys[i]; + + /* Inactive lanes are already powered off */ + if (rk_pcie->lanes_map & RT_BIT(i)) + { + rt_phye_power_off(phy); + } + + rt_phye_exit(phy); + rt_phye_put(phy); + } +} + +rt_err_t rockchip_pcie_enable_clocks(struct rockchip_pcie *rk_pcie) +{ + rt_err_t err; + + if ((err = rt_clk_prepare_enable(rk_pcie->aclk_pcie))) + { + LOG_E("Unable to enable aclk_pcie clock"); + return err; + } + + if ((err = rt_clk_prepare_enable(rk_pcie->aclk_perf_pcie))) + { + LOG_E("Unable to enable aclk_perf_pcie clock"); + goto _err_aclk_perf_pcie; + } + + if ((err = rt_clk_prepare_enable(rk_pcie->hclk_pcie))) + { + LOG_E("Unable to enable hclk_pcie clock"); + goto _err_hclk_pcie; + } + + if ((err = rt_clk_prepare_enable(rk_pcie->clk_pcie_pm))) + { + LOG_E("Unable to enable clk_pcie_pm clock"); + goto _err_clk_pcie_pm; + } + + return 0; + +_err_clk_pcie_pm: + rt_clk_disable_unprepare(rk_pcie->hclk_pcie); +_err_hclk_pcie: + + rt_clk_disable_unprepare(rk_pcie->aclk_perf_pcie); + +_err_aclk_perf_pcie: + rt_clk_disable_unprepare(rk_pcie->aclk_pcie); + + return err; +} + +void rockchip_pcie_disable_clocks(struct rockchip_pcie *rk_pcie) +{ + rt_clk_disable_unprepare(rk_pcie->clk_pcie_pm); + rt_clk_disable_unprepare(rk_pcie->hclk_pcie); + rt_clk_disable_unprepare(rk_pcie->aclk_perf_pcie); + rt_clk_disable_unprepare(rk_pcie->aclk_pcie); +} + +void rockchip_pcie_common_free(struct rockchip_pcie *rk_pcie) +{ + if (!rt_is_err_or_null(rk_pcie->aclk_pcie)) + { + rt_clk_put(rk_pcie->aclk_pcie); + } + + if (!rt_is_err_or_null(rk_pcie->aclk_perf_pcie)) + { + rt_clk_put(rk_pcie->aclk_perf_pcie); + } + + if (!rt_is_err_or_null(rk_pcie->hclk_pcie)) + { + rt_clk_put(rk_pcie->hclk_pcie); + } + + if (!rt_is_err_or_null(rk_pcie->clk_pcie_pm)) + { + rt_clk_put(rk_pcie->clk_pcie_pm); + } + + if (!rt_is_err_or_null(rk_pcie->core_rstc)) + { + rt_reset_control_put(rk_pcie->core_rstc); + } + + if (!rt_is_err_or_null(rk_pcie->mgmt_rstc)) + { + rt_reset_control_put(rk_pcie->mgmt_rstc); + } + + if (!rt_is_err_or_null(rk_pcie->mgmt_sticky_rstc)) + { + rt_reset_control_put(rk_pcie->mgmt_sticky_rstc); + } + + if (!rt_is_err_or_null(rk_pcie->pipe_rstc)) + { + rt_reset_control_put(rk_pcie->pipe_rstc); + } + + if (!rt_is_err_or_null(rk_pcie->pm_rstc)) + { + rt_reset_control_put(rk_pcie->pm_rstc); + } + + if (!rt_is_err_or_null(rk_pcie->pclk_rstc)) + { + rt_reset_control_put(rk_pcie->pclk_rstc); + } + + if (!rt_is_err_or_null(rk_pcie->aclk_rstc)) + { + rt_reset_control_put(rk_pcie->aclk_rstc); + } + + if (rk_pcie->axi_base) + { + rt_iounmap(rk_pcie->apb_base); + } + + if (rk_pcie->apb_base) + { + rt_iounmap(rk_pcie->apb_base); + } +} + +void rockchip_pcie_cfg_configuration_accesses(struct rockchip_pcie *rk_pcie, rt_uint32_t type) +{ + rt_uint32_t ob_desc_0; + + /* Configuration Accesses for region 0 */ + rockchip_pcie_write(rk_pcie, 0x0, PCIE_RC_BAR_CONF); + + rockchip_pcie_write(rk_pcie, + (RC_REGION_0_ADDR_TRANS_L + RC_REGION_0_PASS_BITS), + PCIE_CORE_OB_REGION_ADDR0); + rockchip_pcie_write(rk_pcie, + RC_REGION_0_ADDR_TRANS_H, + PCIE_CORE_OB_REGION_ADDR1); + + ob_desc_0 = rockchip_pcie_read(rk_pcie, PCIE_CORE_OB_REGION_DESC0); + ob_desc_0 &= ~(RC_REGION_0_TYPE_MASK); + ob_desc_0 |= (type | (0x1 << 23)); + + rockchip_pcie_write(rk_pcie, ob_desc_0, PCIE_CORE_OB_REGION_DESC0); + rockchip_pcie_write(rk_pcie, 0x0, PCIE_CORE_OB_REGION_DESC1); +} diff --git a/bsp/rockchip/dm/pci/pcie-rockchip.h b/bsp/rockchip/dm/pci/pcie-rockchip.h new file mode 100755 index 000000000000..b207c8965a4a --- /dev/null +++ b/bsp/rockchip/dm/pci/pcie-rockchip.h @@ -0,0 +1,364 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-09-23 GuEe-GUI first version + */ + +#ifndef __PCIE_ROCKCHIP_H__ +#define __PCIE_ROCKCHIP_H__ + +#include +#include + +#include "ecam.h" +#include "rockchip.h" + +/* + * The upper 16 bits of PCIE_CLIENT_CONFIG are a write mask for the lower 16 + * bits. This allows atomic updates of the register without locking. + */ +#define PCI_HIWORD_UPDATE(mask, val) (((mask) << 16) | (val)) +#define PCI_HIWORD_UPDATE_BIT(val) PCI_HIWORD_UPDATE(val, val) +#define PCI_HIWORD_DISABLE_BIT(val) PCI_HIWORD_UPDATE(val, ~val) + +#define ENCODE_LANES(x) ((((x) >> 1) & 3) << 4) +#define MAX_LANE_NUM 4 +#define MAX_REGION_LIMIT 32 +#define MIN_EP_APERTURE 28 + +#define PCIE_CLIENT_BASE 0x0 +#define PCIE_CLIENT_CONFIG (PCIE_CLIENT_BASE + 0x00) +#define PCIE_CLIENT_CONF_ENABLE PCI_HIWORD_UPDATE_BIT(0x0001) +#define PCIE_CLIENT_CONF_DISABLE PCI_HIWORD_UPDATE(0x0001, 0) +#define PCIE_CLIENT_LINK_TRAIN_ENABLE PCI_HIWORD_UPDATE_BIT(0x0002) +#define PCIE_CLIENT_LINK_TRAIN_DISABLE PCI_HIWORD_UPDATE(0x0002, 0x0000) +#define PCIE_CLIENT_ARI_ENABLE PCI_HIWORD_UPDATE_BIT(0x0008) +#define PCIE_CLIENT_CONF_LANE_NUM(x) PCI_HIWORD_UPDATE(0x0030, ENCODE_LANES(x)) +#define PCIE_CLIENT_MODE_RC PCI_HIWORD_UPDATE_BIT(0x0040) +#define PCIE_CLIENT_MODE_EP PCI_HIWORD_UPDATE(0x0040, 0) +#define PCIE_CLIENT_GEN_SEL_1 PCI_HIWORD_UPDATE(0x0080, 0) +#define PCIE_CLIENT_GEN_SEL_2 PCI_HIWORD_UPDATE_BIT(0x0080) +#define PCIE_CLIENT_LEGACY_INT_CTRL (PCIE_CLIENT_BASE + 0x0c) +#define PCIE_CLIENT_INT_IN_ASSERT PCI_HIWORD_UPDATE_BIT(0x0002) +#define PCIE_CLIENT_INT_IN_DEASSERT PCI_HIWORD_UPDATE(0x0002, 0) +#define PCIE_CLIENT_INT_PEND_ST_PEND PCI_HIWORD_UPDATE_BIT(0x0001) +#define PCIE_CLIENT_INT_PEND_ST_NORMAL PCI_HIWORD_UPDATE(0x0001, 0) +#define PCIE_CLIENT_SIDE_BAND_STATUS (PCIE_CLIENT_BASE + 0x20) +#define PCIE_CLIENT_PHY_ST RT_BIT(12) +#define PCIE_CLIENT_DEBUG_OUT_0 (PCIE_CLIENT_BASE + 0x3c) +#define PCIE_CLIENT_DEBUG_LTSSM_MASK RT_GENMASK(5, 0) +#define PCIE_CLIENT_DEBUG_LTSSM_L0 0x10 +#define PCIE_CLIENT_DEBUG_LTSSM_L1 0x18 +#define PCIE_CLIENT_DEBUG_LTSSM_L2 0x19 +#define PCIE_CLIENT_BASIC_STATUS1 (PCIE_CLIENT_BASE + 0x48) +#define PCIE_CLIENT_LINK_STATUS_UP 0x00300000 +#define PCIE_CLIENT_LINK_STATUS_MASK 0x00300000 +#define PCIE_CLIENT_INT_MASK (PCIE_CLIENT_BASE + 0x4c) +#define PCIE_CLIENT_INT_STATUS (PCIE_CLIENT_BASE + 0x50) +#define PCIE_CLIENT_INTR_MASK RT_GENMASK(8, 5) +#define PCIE_CLIENT_INTR_SHIFT 5 +#define PCIE_CLIENT_INT_LEGACY_DONE RT_BIT(15) +#define PCIE_CLIENT_INT_MSG RT_BIT(14) +#define PCIE_CLIENT_INT_HOT_RST RT_BIT(13) +#define PCIE_CLIENT_INT_DPA RT_BIT(12) +#define PCIE_CLIENT_INT_FATAL_ERR RT_BIT(11) +#define PCIE_CLIENT_INT_NFATAL_ERR RT_BIT(10) +#define PCIE_CLIENT_INT_CORR_ERR RT_BIT(9) +#define PCIE_CLIENT_INT_INTD RT_BIT(8) +#define PCIE_CLIENT_INT_INTC RT_BIT(7) +#define PCIE_CLIENT_INT_INTB RT_BIT(6) +#define PCIE_CLIENT_INT_INTA RT_BIT(5) +#define PCIE_CLIENT_INT_LOCAL RT_BIT(4) +#define PCIE_CLIENT_INT_UDMA RT_BIT(3) +#define PCIE_CLIENT_INT_PHY RT_BIT(2) +#define PCIE_CLIENT_INT_HOT_PLUG RT_BIT(1) +#define PCIE_CLIENT_INT_PWR_STCG RT_BIT(0) + +#define PCIE_CLIENT_INT_LEGACY \ + (PCIE_CLIENT_INT_INTA | PCIE_CLIENT_INT_INTB | \ + PCIE_CLIENT_INT_INTC | PCIE_CLIENT_INT_INTD) + +#define PCIE_CLIENT_INT_CLI \ + (PCIE_CLIENT_INT_CORR_ERR | PCIE_CLIENT_INT_NFATAL_ERR | \ + PCIE_CLIENT_INT_FATAL_ERR | PCIE_CLIENT_INT_DPA | \ + PCIE_CLIENT_INT_HOT_RST | PCIE_CLIENT_INT_MSG | \ + PCIE_CLIENT_INT_LEGACY_DONE | PCIE_CLIENT_INT_LEGACY | \ + PCIE_CLIENT_INT_PHY | PCIE_CLIENT_INT_UDMA) + +#define PCIE_APB_CORE_UDMA_BASE (RT_BIT(23) | RT_BIT(22) | RT_BIT(21)) +#define PCIE_CH0_DONE_ENABLE RT_BIT(0) +#define PCIE_CH1_DONE_ENABLE RT_BIT(1) +#define PCIE_CH0_ERR_ENABLE RT_BIT(8) +#define PCIE_CH1_ERR_ENABLE RT_BIT(9) + +#define PCIE_UDMA_INT_REG 0xa0 +#define PCIE_UDMA_INT_ENABLE_REG 0xa4 + +#define PCIE_UDMA_INT_ENABLE_MASK \ + (PCIE_CH0_DONE_ENABLE | PCIE_CH1_DONE_ENABLE | \ + PCIE_CH0_ERR_ENABLE | PCIE_CH1_ERR_ENABLE) + +#define PCIE_CORE_CTRL_MGMT_BASE 0x900000 +#define PCIE_CORE_CTRL (PCIE_CORE_CTRL_MGMT_BASE + 0x000) +#define PCIE_CORE_PL_CONF_SPEED_5G 0x00000008 +#define PCIE_CORE_PL_CONF_SPEED_MASK 0x00000018 +#define PCIE_CORE_PL_CONF_LANE_MASK 0x00000006 +#define PCIE_CORE_PL_CONF_LANE_SHIFT 1 +#define PCIE_CORE_CTRL_PLC1 (PCIE_CORE_CTRL_MGMT_BASE + 0x004) +#define PCIE_CORE_CTRL_PLC1_FTS_MASK RT_GENMASK(23, 8) +#define PCIE_CORE_CTRL_PLC1_FTS_SHIFT 8 +#define PCIE_CORE_CTRL_PLC1_FTS_CNT 0xffff +#define PCIE_CORE_TXCREDIT_CFG1 (PCIE_CORE_CTRL_MGMT_BASE + 0x020) +#define PCIE_CORE_TXCREDIT_CFG1_MUI_MASK 0xFFFF0000 +#define PCIE_CORE_TXCREDIT_CFG1_MUI_SHIFT 16 +#define PCIE_CORE_TXCREDIT_CFG1_MUI_ENCODE(x) (((x) >> 3) << PCIE_CORE_TXCREDIT_CFG1_MUI_SHIFT) +#define PCIE_CORE_LANE_MAP (PCIE_CORE_CTRL_MGMT_BASE + 0x200) +#define PCIE_CORE_LANE_MAP_MASK 0x0000000f +#define PCIE_CORE_LANE_MAP_REVERSE RT_BIT(16) +#define PCIE_CORE_INT_STATUS (PCIE_CORE_CTRL_MGMT_BASE + 0x20c) +#define PCIE_CORE_INT_PRFPE RT_BIT(0) +#define PCIE_CORE_INT_CRFPE RT_BIT(1) +#define PCIE_CORE_INT_RRPE RT_BIT(2) +#define PCIE_CORE_INT_PRFO RT_BIT(3) +#define PCIE_CORE_INT_CRFO RT_BIT(4) +#define PCIE_CORE_INT_RT RT_BIT(5) +#define PCIE_CORE_INT_RTR RT_BIT(6) +#define PCIE_CORE_INT_PE RT_BIT(7) +#define PCIE_CORE_INT_MTR RT_BIT(8) +#define PCIE_CORE_INT_UCR RT_BIT(9) +#define PCIE_CORE_INT_FCE RT_BIT(10) +#define PCIE_CORE_INT_CT RT_BIT(11) +#define PCIE_CORE_INT_UTC RT_BIT(18) +#define PCIE_CORE_INT_MMVC RT_BIT(19) +#define PCIE_CORE_CONFIG_VENDOR (PCIE_CORE_CTRL_MGMT_BASE + 0x44) +#define PCIE_CORE_INT_MASK (PCIE_CORE_CTRL_MGMT_BASE + 0x210) +#define PCIE_CORE_PHY_FUNC_CFG (PCIE_CORE_CTRL_MGMT_BASE + 0x2c0) +#define PCIE_RC_BAR_CONF (PCIE_CORE_CTRL_MGMT_BASE + 0x300) +#define RK_PCIE_CORE_BAR_CFG_CTRL_DISABLED 0x0 +#define RK_PCIE_CORE_BAR_CFG_CTRL_IO_32BITS 0x1 +#define RK_PCIE_CORE_BAR_CFG_CTRL_MEM_32BITS 0x4 +#define RK_PCIE_CORE_BAR_CFG_CTRL_PREFETCH_MEM_32BITS 0x5 +#define RK_PCIE_CORE_BAR_CFG_CTRL_MEM_64BITS 0x6 +#define RK_PCIE_CORE_BAR_CFG_CTRL_PREFETCH_MEM_64BITS 0x7 + +#define PCIE_CORE_INT \ + (PCIE_CORE_INT_PRFPE | PCIE_CORE_INT_CRFPE | \ + PCIE_CORE_INT_RRPE | PCIE_CORE_INT_CRFO | \ + PCIE_CORE_INT_RT | PCIE_CORE_INT_RTR | \ + PCIE_CORE_INT_PE | PCIE_CORE_INT_MTR | \ + PCIE_CORE_INT_UCR | PCIE_CORE_INT_FCE | \ + PCIE_CORE_INT_CT | PCIE_CORE_INT_UTC | \ + PCIE_CORE_INT_MMVC) + +#define PCIE_RC_RP_ATS_BASE 0x400000 +#define PCIE_RC_CONFIG_NORMAL_BASE 0x800000 +#define PCIE_RC_CONFIG_BASE 0xa00000 +#define PCIE_EP_CONFIG_BASE 0xa00000 +#define PCIE_EP_CONFIG_DID_VID (PCIE_EP_CONFIG_BASE + 0x00) +#define PCIE_RC_CONFIG_RID_CCR (PCIE_RC_CONFIG_BASE + 0x08) +#define PCIE_RC_CONFIG_SCC_SHIFT 16 +#define PCIE_RC_CONFIG_DCR (PCIE_RC_CONFIG_BASE + 0xc4) +#define PCIE_RC_CONFIG_DCR_CSPL_SHIFT 18 +#define PCIE_RC_CONFIG_DCR_CSPL_LIMIT 0xff +#define PCIE_RC_CONFIG_DCR_CPLS_SHIFT 26 +#define PCIE_RC_CONFIG_DCSR (PCIE_RC_CONFIG_BASE + 0xc8) +#define PCIE_RC_CONFIG_DCSR_MPS_MASK RT_GENMASK(7, 5) +#define PCIE_RC_CONFIG_DCSR_MPS_256 (0x1 << 5) +#define PCIE_RC_CONFIG_LINK_CAP (PCIE_RC_CONFIG_BASE + 0xcc) +#define PCIE_RC_CONFIG_LINK_CAP_L0S RT_BIT(10) +#define PCIE_RC_CONFIG_LCS (PCIE_RC_CONFIG_BASE + 0xd0) +#define PCIE_RC_CONFIG_L1_SUBSTATE_CTRL2 (PCIE_RC_CONFIG_BASE + 0x90c) +#define PCIE_RC_CONFIG_THP_CAP (PCIE_RC_CONFIG_BASE + 0x274) +#define PCIE_RC_CONFIG_THP_CAP_NEXT_MASK RT_GENMASK(31, 20) + +#define PCIE_CORE_AXI_CONF_BASE 0xc00000 +#define PCIE_CORE_OB_REGION_ADDR0 (PCIE_CORE_AXI_CONF_BASE + 0x0) +#define PCIE_CORE_OB_REGION_ADDR0_NUM_BITS 0x3f +#define PCIE_CORE_OB_REGION_ADDR0_LO_ADDR 0xffffff00 +#define PCIE_CORE_OB_REGION_ADDR1 (PCIE_CORE_AXI_CONF_BASE + 0x4) +#define PCIE_CORE_OB_REGION_DESC0 (PCIE_CORE_AXI_CONF_BASE + 0x8) +#define PCIE_CORE_OB_REGION_DESC1 (PCIE_CORE_AXI_CONF_BASE + 0xc) + +#define PCIE_CORE_AXI_INBOUND_BASE 0xc00800 +#define PCIE_RP_IB_ADDR0 (PCIE_CORE_AXI_INBOUND_BASE + 0x0) +#define PCIE_CORE_IB_REGION_ADDR0_NUM_BITS 0x3f +#define PCIE_CORE_IB_REGION_ADDR0_LO_ADDR 0xffffff00 +#define PCIE_RP_IB_ADDR1 (PCIE_CORE_AXI_INBOUND_BASE + 0x4) + +/* Size of one AXI Region (not Region 0) */ +#define AXI_REGION_SIZE RT_BIT(20) +/* Size of Region 0, equal to sum of sizes of other regions */ +#define AXI_REGION_0_SIZE (32 * (0x1 << 20)) +#define OB_REG_SIZE_SHIFT 5 +#define IB_ROOT_PORT_REG_SIZE_SHIFT 3 +#define AXI_WRAPPER_IO_WRITE 0x6 +#define AXI_WRAPPER_MEM_WRITE 0x2 +#define AXI_WRAPPER_TYPE0_CFG 0xa +#define AXI_WRAPPER_TYPE1_CFG 0xb +#define AXI_WRAPPER_NOR_MSG 0xc + +#define MAX_AXI_IB_ROOTPORT_REGION_NUM 3 +#define MIN_AXI_ADDR_BITS_PASSED 8 +#define PCIE_RC_SEND_PME_OFF 0x11960 +#define RK_VENDOR_ID 0x1d87 +#undef PCIE_ECAM_BUS +#undef PCIE_ECAM_REG +#define PCIE_ECAM_BUS(x) (((x) & 0xff) << 20) +#define PCIE_ECAM_DEV(x) (((x) & 0x1f) << 15) +#define PCIE_ECAM_FUNC(x) (((x) & 0x7) << 12) +#define PCIE_ECAM_REG(x) (((x) & 0xfff) << 0) +#define PCIE_ECAM_ADDR(bus, dev, func, reg) \ + (PCIE_ECAM_BUS(bus) | PCIE_ECAM_DEV(dev) | PCIE_ECAM_FUNC(func) | PCIE_ECAM_REG(reg)) +#define PCIE_LINK_IS_L0(x) \ + (((x) & PCIE_CLIENT_DEBUG_LTSSM_MASK) == PCIE_CLIENT_DEBUG_LTSSM_L0) +#define PCIE_LINK_IS_L2(x) \ + (((x) & PCIE_CLIENT_DEBUG_LTSSM_MASK) == PCIE_CLIENT_DEBUG_LTSSM_L2) +#define PCIE_LINK_UP(x) \ + (((x) & PCIE_CLIENT_LINK_STATUS_MASK) == PCIE_CLIENT_LINK_STATUS_UP) +#define PCIE_LINK_IS_GEN2(x) \ + (((x) & PCIE_CORE_PL_CONF_SPEED_MASK) == PCIE_CORE_PL_CONF_SPEED_5G) + +#define RC_REGION_0_ADDR_TRANS_H 0x00000000 +#define RC_REGION_0_ADDR_TRANS_L 0x00000000 +#define RC_REGION_0_PASS_BITS (25 - 1) +#define RC_REGION_0_TYPE_MASK RT_GENMASK(3, 0) +#define MAX_AXI_WRAPPER_REGION_NUM 33 + +#define RK_PCIE_MSG_ROUTING_TO_RC 0x0 +#define RK_PCIE_MSG_ROUTING_VIA_ADDR 0x1 +#define RK_PCIE_MSG_ROUTING_VIA_ID 0x2 +#define RK_PCIE_MSG_ROUTING_BROADCAST 0x3 +#define RK_PCIE_MSG_ROUTING_LOCAL_INTX 0x4 +#define RK_PCIE_MSG_ROUTING_PME_ACK 0x5 +#define RK_PCIE_MSG_CODE_ASSERT_INTA 0x20 +#define RK_PCIE_MSG_CODE_ASSERT_INTB 0x21 +#define RK_PCIE_MSG_CODE_ASSERT_INTC 0x22 +#define RK_PCIE_MSG_CODE_ASSERT_INTD 0x23 +#define RK_PCIE_MSG_CODE_DEASSERT_INTA 0x24 +#define RK_PCIE_MSG_CODE_DEASSERT_INTB 0x25 +#define RK_PCIE_MSG_CODE_DEASSERT_INTC 0x26 +#define RK_PCIE_MSG_CODE_DEASSERT_INTD 0x27 +#define RK_PCIE_MSG_ROUTING_MASK RT_GENMASK(7, 5) +#define RK_PCIE_MSG_ROUTING(route) (((route) << 5) & RK_PCIE_MSG_ROUTING_MASK) +#define RK_PCIE_MSG_CODE_MASK RT_GENMASK(15, 8) +#define RK_PCIE_MSG_CODE(code) (((code) << 8) & RK_PCIE_MSG_CODE_MASK) +#define RK_PCIE_MSG_NO_DATA RT_BIT(16) + +#define RK_PCIE_EP_CMD_STATUS 0x4 +#define RK_PCIE_EP_CMD_STATUS_IS RT_BIT(19) +#define RK_PCIE_EP_MSI_CTRL_REG 0x90 +#define RK_PCIE_EP_MSI_FLAGS_OFFSET 16 +#define RK_PCIE_EP_MSI_CTRL_MMC_OFFSET 17 +#define RK_PCIE_EP_MSI_CTRL_MMC_MASK RT_GENMASK(19, 17) +#define RK_PCIE_EP_MSI_CTRL_MME_OFFSET 20 +#define RK_PCIE_EP_MSI_CTRL_MME_MASK RT_GENMASK(22, 20) +#define RK_PCIE_EP_MSI_CTRL_ME RT_BIT(16) +#define RK_PCIE_EP_MSI_CTRL_MASK_MSI_CAP RT_BIT(24) +#define RK_PCIE_EP_DUMMY_IRQ_ADDR 0x1 +#define RK_PCIE_EP_FUNC_BASE(fn) (((fn) << 12) & RT_GENMASK(19, 12)) +#define RK_PCIE_AT_IB_EP_FUNC_BAR_ADDR0(fn, bar) (PCIE_RC_RP_ATS_BASE + 0x0840 + (fn) * 0x0040 + (bar) * 0x0008) +#define RK_PCIE_AT_IB_EP_FUNC_BAR_ADDR1(fn, bar) (PCIE_RC_RP_ATS_BASE + 0x0844 + (fn) * 0x0040 + (bar) * 0x0008) +#define RK_PCIE_AT_OB_REGION_PCI_ADDR0(r) (PCIE_RC_RP_ATS_BASE + 0x0000 + ((r) & 0x1f) * 0x0020) +#define RK_PCIE_AT_OB_REGION_PCI_ADDR0_DEVFN_MASK RT_GENMASK(19, 12) +#define RK_PCIE_AT_OB_REGION_PCI_ADDR0_DEVFN(devfn) (((devfn) << 12) & RK_PCIE_AT_OB_REGION_PCI_ADDR0_DEVFN_MASK) +#define RK_PCIE_AT_OB_REGION_PCI_ADDR0_BUS_MASK RT_GENMASK(27, 20) +#define RK_PCIE_AT_OB_REGION_PCI_ADDR0_BUS(bus) (((bus) << 20) & RK_PCIE_AT_OB_REGION_PCI_ADDR0_BUS_MASK) +#define RK_PCIE_AT_OB_REGION_PCI_ADDR1(r) (PCIE_RC_RP_ATS_BASE + 0x0004 + ((r) & 0x1f) * 0x0020) +#define RK_PCIE_AT_OB_REGION_DESC0_HARDCODED_RID RT_BIT(23) +#define RK_PCIE_AT_OB_REGION_DESC0_DEVFN_MASK RT_GENMASK(31, 24) +#define RK_PCIE_AT_OB_REGION_DESC0_DEVFN(devfn) (((devfn) << 24) & RK_PCIE_AT_OB_REGION_DESC0_DEVFN_MASK) +#define RK_PCIE_AT_OB_REGION_DESC0(r) (PCIE_RC_RP_ATS_BASE + 0x0008 + ((r) & 0x1f) * 0x0020) +#define RK_PCIE_AT_OB_REGION_DESC1(r) (PCIE_RC_RP_ATS_BASE + 0x000c + ((r) & 0x1f) * 0x0020) +#define RK_PCIE_AT_OB_REGION_CPU_ADDR0(r) (PCIE_RC_RP_ATS_BASE + 0x0018 + ((r) & 0x1f) * 0x0020) +#define RK_PCIE_AT_OB_REGION_CPU_ADDR1(r) (PCIE_RC_RP_ATS_BASE + 0x001c + ((r) & 0x1f) * 0x0020) + +#define RK_PCIE_CORE_EP_FUNC_BAR_CFG0(fn) (PCIE_CORE_CTRL_MGMT_BASE + 0x0240 + (fn) * 0x0008) +#define RK_PCIE_CORE_EP_FUNC_BAR_CFG1(fn) (PCIE_CORE_CTRL_MGMT_BASE + 0x0244 + (fn) * 0x0008) +#define RK_PCIE_CORE_EP_FUNC_BAR_CFG_BAR_APERTURE_MASK(b) (RT_GENMASK(4, 0) << ((b) * 8)) +#define RK_PCIE_CORE_EP_FUNC_BAR_CFG_BAR_APERTURE(b, a) (((a) << ((b) * 8)) & RK_PCIE_CORE_EP_FUNC_BAR_CFG_BAR_APERTURE_MASK(b)) +#define RK_PCIE_CORE_EP_FUNC_BAR_CFG_BAR_CTRL_MASK(b) (RT_GENMASK(7, 5) << ((b) * 8)) +#define RK_PCIE_CORE_EP_FUNC_BAR_CFG_BAR_CTRL(b, c) (((c) << ((b) * 8 + 5)) & RK_PCIE_CORE_EP_FUNC_BAR_CFG_BAR_CTRL_MASK(b)) + +#define PCIE_USER_RELINK 0x1 +#define PCIE_USER_UNLINK 0x2 + +struct rockchip_pcie +{ + void *axi_base; + void *apb_base; + + rt_bool_t legacy_phy; + struct rt_phye *phys[MAX_LANE_NUM]; + + struct rt_reset_control *core_rstc; + struct rt_reset_control *mgmt_rstc; + struct rt_reset_control *mgmt_sticky_rstc; + struct rt_reset_control *pipe_rstc; + struct rt_reset_control *pm_rstc; + struct rt_reset_control *aclk_rstc; + struct rt_reset_control *pclk_rstc; + + struct rt_clk *aclk_pcie; + struct rt_clk *aclk_perf_pcie; + struct rt_clk *hclk_pcie; + struct rt_clk *clk_pcie_pm; + + struct rt_regulator *vpcie12v; + struct rt_regulator *vpcie3v3; + struct rt_regulator *vpcie1v8; + struct rt_regulator *vpcie0v9; + + rt_ubase_t ep_pin; + rt_uint8_t active_val; + + rt_uint32_t num_lanes; + rt_uint8_t lanes_map; + rt_uint32_t link_gen; + + int sys_irq; + int legacy_irq; + int client_irq; + struct rt_device *dev; + struct rt_ofw_node *intx_np; + struct rt_pic intx_pic; + + int offset; + void *msg_region; + rt_ubase_t msg_bus_addr; + + rt_uint64_t mem_base_addr; + rt_uint64_t mem_base_size; + + rt_bool_t is_rc; + rt_bool_t wait_ep; + rt_bool_t in_remove; + + struct rt_pci_host_bridge *bridge; +}; + +rt_inline rt_uint32_t rockchip_pcie_read(struct rockchip_pcie *rk_pcie, + rt_uint32_t reg) +{ + return HWREG32(rk_pcie->apb_base + reg); +} + +rt_inline void rockchip_pcie_write(struct rockchip_pcie *rk_pcie, + rt_uint32_t val, rt_uint32_t reg) +{ + HWREG32(rk_pcie->apb_base + reg) = val; +} + +rt_err_t rockchip_pcie_ofw_parse(struct rockchip_pcie *rk_pcie); +rt_err_t rockchip_pcie_init_port(struct rockchip_pcie *rk_pcie); +rt_err_t rockchip_pcie_get_phys(struct rockchip_pcie *rk_pcie); +void rockchip_pcie_deinit_phys(struct rockchip_pcie *rk_pcie); +rt_err_t rockchip_pcie_enable_clocks(struct rockchip_pcie *rk_pcie); +void rockchip_pcie_disable_clocks(struct rockchip_pcie *rk_pcie); +void rockchip_pcie_common_free(struct rockchip_pcie *rk_pcie); +void rockchip_pcie_cfg_configuration_accesses(struct rockchip_pcie *rk_pcie, rt_uint32_t type); + +#endif /* __PCIE_ROCKCHIP_H__ */ diff --git a/bsp/rockchip/dm/phye/Kconfig b/bsp/rockchip/dm/phye/Kconfig index ca7dc5d84c2f..ae7cc7ddc7f5 100755 --- a/bsp/rockchip/dm/phye/Kconfig +++ b/bsp/rockchip/dm/phye/Kconfig @@ -7,3 +7,20 @@ config RT_PHYE_ROCKCHIP_SNPS_PCIE3 bool "Snps PCIe3 PHY Driver" depends on RT_MFD_SYSCON default n + +config RT_PHYE_ROCKCHIP_INNO_USB2 + bool "Rockchip Inno USB2 PHY Driver" + depends on RT_MFD_SYSCON + default n + +config RT_PHYE_ROCKCHIP_MIPI_DCPHY + bool "Rockchip Samsung MIPI DCPHY (rk3576/rk3588 DSI)" + depends on RT_USING_PHYE + depends on RT_USING_CLK + default n + +config RT_PHYE_ROCKCHIP_INNO_DSIDPHY + bool "Rockchip Innosilicon MIPI DSI DPHY (rk3568)" + depends on RT_USING_PHYE + depends on RT_USING_CLK + default n diff --git a/bsp/rockchip/dm/phye/SConscript b/bsp/rockchip/dm/phye/SConscript index 0a1836d4787f..03aaec0eae14 100755 --- a/bsp/rockchip/dm/phye/SConscript +++ b/bsp/rockchip/dm/phye/SConscript @@ -10,6 +10,15 @@ if GetDepend(['RT_PHYE_ROCKCHIP_NANENG_COMBO']): if GetDepend(['RT_PHYE_ROCKCHIP_SNPS_PCIE3']): src += ['phye-snps-pcie3.c'] +if GetDepend(['RT_PHYE_ROCKCHIP_INNO_USB2']): + src += ['phye-rockchip-inno-usb2.c'] + +if GetDepend(['RT_PHYE_ROCKCHIP_MIPI_DCPHY']): + src += ['phye-rockchip-mipi-dcphy.c'] + +if GetDepend(['RT_PHYE_ROCKCHIP_INNO_DSIDPHY']): + src += ['phye-rockchip-inno-dsidphy.c'] + group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) Return('group') diff --git a/bsp/rockchip/dm/phye/phye-rockchip-inno-dsidphy.c b/bsp/rockchip/dm/phye/phye-rockchip-inno-dsidphy.c new file mode 100644 index 000000000000..1451d5ed6368 --- /dev/null +++ b/bsp/rockchip/dm/phye/phye-rockchip-inno-dsidphy.c @@ -0,0 +1,566 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-09-23 GuEe-GUI first version + */ + +#include +#include +#include +#include +#include +#include + +#define DBG_TAG "phye.inno-dsi" +#define DBG_LVL DBG_INFO +#include + +#define UPDATE(v, h, l) (((v) << (l)) & RT_GENMASK((h), (l))) +#define PHY_REG(first, second) (((((first) & 0x7) << 5) | ((second) & 0x1f)) << 2) + +/* Analog reg00. */ +#define BANDGAP_POWER_MASK RT_BIT(7) +#define BANDGAP_POWER_DOWN RT_BIT(7) +#define BANDGAP_POWER_ON 0 +#define LANE_EN_MASK RT_GENMASK(6, 2) +#define LANE_EN_CK RT_BIT(6) +#define LANE_EN_3 RT_BIT(5) +#define LANE_EN_2 RT_BIT(4) +#define LANE_EN_1 RT_BIT(3) +#define LANE_EN_0 RT_BIT(2) +#define POWER_WORK_MASK RT_GENMASK(1, 0) +#define POWER_WORK_ENABLE UPDATE(1, 1, 0) +#define POWER_WORK_DISABLE UPDATE(2, 1, 0) + +/* Analog reg01, reg03, reg04, reg08 and reg0b. */ +#define REG_SYNCRST_MASK RT_BIT(2) +#define REG_SYNCRST_RESET RT_BIT(2) +#define REG_SYNCRST_NORMAL 0 +#define REG_LDOPD_MASK RT_BIT(1) +#define REG_LDOPD_POWER_DOWN RT_BIT(1) +#define REG_LDOPD_POWER_ON 0 +#define REG_PLLPD_MASK RT_BIT(0) +#define REG_PLLPD_POWER_DOWN RT_BIT(0) +#define REG_PLLPD_POWER_ON 0 +#define REG_FBDIV_HI_MASK RT_BIT(5) +#define REG_FBDIV_HI(x) UPDATE((x) >> 8, 5, 5) +#define REG_PREDIV_MASK RT_GENMASK(4, 0) +#define REG_PREDIV(x) UPDATE(x, 4, 0) +#define REG_FBDIV_LO_MASK RT_GENMASK(7, 0) +#define REG_FBDIV_LO(x) UPDATE(x, 7, 0) +#define PLL_POST_DIV_EN_MASK RT_BIT(5) +#define PLL_POST_DIV_ENABLE RT_BIT(5) +#define CLK_LANE_VOD_MASK RT_GENMASK(3, 0) +#define CLK_LANE_VOD(x) UPDATE(x, 3, 0) +#define VOD_MAX_RANGE 0xf + +/* Digital reg00. */ +#define REG_DIG_RSTN_MASK RT_BIT(0) +#define REG_DIG_RSTN_NORMAL RT_BIT(0) +#define REG_DIG_RSTN_RESET 0 + +/* Per-lane timing registers. */ +#define T_LPX_CNT_MASK RT_GENMASK(5, 0) +#define T_LPX_CNT(x) UPDATE(x, 5, 0) +#define T_HS_ZERO_HI_MASK RT_BIT(7) +#define T_HS_ZERO_HI(x) UPDATE((x) >> 6, 7, 7) +#define T_HS_PREPARE_MASK RT_GENMASK(6, 0) +#define T_HS_PREPARE(x) UPDATE(x, 6, 0) +#define T_HS_ZERO_LO_MASK RT_GENMASK(5, 0) +#define T_HS_ZERO_LO(x) UPDATE(x, 5, 0) +#define T_HS_TRAIL_MASK RT_GENMASK(6, 0) +#define T_HS_TRAIL(x) UPDATE(x, 6, 0) +#define T_HS_EXIT_LO_MASK RT_GENMASK(4, 0) +#define T_HS_EXIT_LO(x) UPDATE(x, 4, 0) +#define T_CLK_POST_LO_MASK RT_GENMASK(3, 0) +#define T_CLK_POST_LO(x) UPDATE(x, 3, 0) +#define T_WAKEUP_HI_MASK RT_GENMASK(1, 0) +#define T_WAKEUP_HI(x) UPDATE((x) >> 8, 1, 0) +#define T_WAKEUP_LO_MASK RT_GENMASK(7, 0) +#define T_WAKEUP_LO(x) UPDATE(x, 7, 0) +#define T_CLK_PRE_MASK RT_GENMASK(3, 0) +#define T_CLK_PRE(x) UPDATE(x, 3, 0) +#define T_CLK_POST_HI_MASK RT_GENMASK(7, 6) +#define T_CLK_POST_HI(x) UPDATE((x) >> 4, 7, 6) +#define T_TA_GO_MASK RT_GENMASK(5, 0) +#define T_TA_GO(x) UPDATE(x, 5, 0) +#define T_HS_EXIT_HI_MASK RT_BIT(6) +#define T_HS_EXIT_HI(x) UPDATE((x) >> 5, 6, 6) +#define T_TA_SURE_MASK RT_GENMASK(5, 0) +#define T_TA_SURE(x) UPDATE(x, 5, 0) +#define T_TA_WAIT_MASK RT_GENMASK(5, 0) +#define T_TA_WAIT(x) UPDATE(x, 5, 0) + +/* LVDS register bank reg03 is also the protocol mode selector. */ +#define MODE_ENABLE_MASK RT_GENMASK(2, 0) +#define MIPI_MODE_ENABLE RT_BIT(0) + +#define PSEC_PER_SEC 1000000000000ULL +#define INNO_DPHY_MAX_RATE 2500000000ULL + +enum inno_dphy_part +{ + INNO_PART_ANALOG, + INNO_PART_DIGITAL, + INNO_PART_CLOCK_LANE, + INNO_PART_DATA0_LANE, + INNO_PART_DATA1_LANE, + INNO_PART_DATA2_LANE, + INNO_PART_DATA3_LANE, + INNO_PART_LVDS, +}; + +struct inno_dphy_timing +{ + rt_uint16_t max_lane_mbps; + rt_uint8_t lpx; + rt_uint8_t hs_prepare; + rt_uint8_t clk_hs_zero; + rt_uint8_t data_hs_zero; + rt_uint8_t hs_trail; +}; + +struct inno_dsidphy +{ + struct rt_phye parent; + void *regs; + struct rt_clk *ref_clk; + struct rt_clk *pclk; + struct rt_reset_control *apb_rst; + struct rt_phye_configure_opts_mipi_dphy cfg; + rt_uint32_t lanes; + rt_uint8_t prediv; + rt_uint16_t fbdiv; + rt_uint64_t rate; +}; + +#define phye_to_inno(phye) rt_container_of(phye, struct inno_dsidphy, parent) + +static const struct inno_dphy_timing rk3568_dphy_timings[] = +{ + { 110, 0x02, 0x7f, 0x16, 0x02, 0x02 }, + { 150, 0x02, 0x7f, 0x16, 0x03, 0x02 }, + { 200, 0x02, 0x7f, 0x17, 0x04, 0x02 }, + { 250, 0x02, 0x7f, 0x17, 0x05, 0x04 }, + { 300, 0x02, 0x7f, 0x18, 0x06, 0x04 }, + { 400, 0x03, 0x7e, 0x19, 0x07, 0x04 }, + { 500, 0x03, 0x7c, 0x1b, 0x07, 0x08 }, + { 600, 0x03, 0x70, 0x1d, 0x08, 0x10 }, + { 700, 0x05, 0x40, 0x1e, 0x08, 0x30 }, + { 800, 0x05, 0x02, 0x1f, 0x09, 0x30 }, + { 1000, 0x05, 0x08, 0x20, 0x09, 0x30 }, + { 1200, 0x06, 0x03, 0x32, 0x14, 0x0f }, + { 1400, 0x09, 0x03, 0x32, 0x14, 0x0f }, + { 1600, 0x0d, 0x42, 0x36, 0x0e, 0x0f }, + { 1800, 0x0e, 0x47, 0x7a, 0x0e, 0x0f }, + { 2000, 0x11, 0x64, 0x7a, 0x0e, 0x0b }, + { 2200, 0x13, 0x64, 0x7e, 0x15, 0x0b }, + { 2400, 0x13, 0x33, 0x7f, 0x15, 0x6a }, + { 2500, 0x15, 0x54, 0x7f, 0x15, 0x6a }, +}; + +static void inno_update_bits(struct inno_dsidphy *inno, rt_uint8_t part, + rt_uint8_t second, rt_uint8_t mask, rt_uint8_t val) +{ + volatile rt_uint32_t *reg; + rt_uint32_t tmp; + + reg = (volatile rt_uint32_t *)((rt_uint8_t *)inno->regs + PHY_REG(part, second)); + tmp = *reg; + *reg = (tmp & ~mask) | (val & mask); +} + +static rt_err_t inno_pll_calc(struct inno_dsidphy *inno, rt_uint64_t requested) +{ + rt_uint64_t prate = rt_clk_get_rate(inno->ref_clk); + rt_uint64_t fref, target, best_rate = 0; + rt_uint32_t min_prediv, max_prediv, prediv; + rt_uint64_t best_delta = ~(rt_uint64_t)0; + rt_uint8_t best_prediv = 0; + rt_uint16_t best_fbdiv = 0; + + if (!prate) + { + prate = 24000000; + } + + fref = prate / 2; + target = requested > 1000000000ULL ? 1000000000ULL : requested; + if (!fref || !target) + { + return -RT_EINVAL; + } + + min_prediv = (rt_uint32_t)RT_DIV_ROUND_UP_ULL(fref, 40000000); + max_prediv = (rt_uint32_t)(fref / 5000000); + + for (prediv = min_prediv; prediv <= max_prediv; ++prediv) + { + rt_uint64_t rate, delta; + rt_uint32_t fbdiv; + + if (!prediv) + { + continue; + } + + fbdiv = (rt_uint32_t)((target * prediv) / fref); + if (fbdiv == 15 || fbdiv < 12 || fbdiv > 511) + { + continue; + } + + rate = (fref * fbdiv) / prediv; + delta = target > rate ? target - rate : rate - target; + if (delta < best_delta) + { + best_delta = delta; + best_prediv = (rt_uint8_t)prediv; + best_fbdiv = (rt_uint16_t)fbdiv; + best_rate = rate; + } + if (!delta) + { + break; + } + } + + if (!best_rate) + { + return -RT_EINVAL; + } + + inno->prediv = best_prediv; + inno->fbdiv = best_fbdiv; + inno->rate = best_rate; + + return RT_EOK; +} + +static const struct inno_dphy_timing *inno_get_timing(rt_uint32_t lane_mbps) +{ + rt_size_t i; + + for (i = 0; i < RT_ARRAY_SIZE(rk3568_dphy_timings); ++i) + { + if (lane_mbps <= rk3568_dphy_timings[i].max_lane_mbps) + { + return &rk3568_dphy_timings[i]; + } + } + + return &rk3568_dphy_timings[RT_ARRAY_SIZE(rk3568_dphy_timings) - 1]; +} + +static void inno_pll_enable(struct inno_dsidphy *inno) +{ + inno_update_bits(inno, INNO_PART_ANALOG, 0x03, + REG_PREDIV_MASK, REG_PREDIV(inno->prediv)); + inno_update_bits(inno, INNO_PART_ANALOG, 0x03, + REG_FBDIV_HI_MASK, REG_FBDIV_HI(inno->fbdiv)); + inno_update_bits(inno, INNO_PART_ANALOG, 0x04, + REG_FBDIV_LO_MASK, REG_FBDIV_LO(inno->fbdiv)); + inno_update_bits(inno, INNO_PART_ANALOG, 0x08, + PLL_POST_DIV_EN_MASK, PLL_POST_DIV_ENABLE); + inno_update_bits(inno, INNO_PART_ANALOG, 0x0b, + CLK_LANE_VOD_MASK, CLK_LANE_VOD(VOD_MAX_RANGE)); + inno_update_bits(inno, INNO_PART_ANALOG, 0x01, + REG_LDOPD_MASK | REG_PLLPD_MASK, + REG_LDOPD_POWER_ON | REG_PLLPD_POWER_ON); +} + +static void inno_reset(struct inno_dsidphy *inno) +{ + inno_update_bits(inno, INNO_PART_ANALOG, 0x01, + REG_SYNCRST_MASK, REG_SYNCRST_RESET); + rt_hw_us_delay(1); + inno_update_bits(inno, INNO_PART_ANALOG, 0x01, + REG_SYNCRST_MASK, REG_SYNCRST_NORMAL); + + inno_update_bits(inno, INNO_PART_DIGITAL, 0x00, + REG_DIG_RSTN_MASK, REG_DIG_RSTN_RESET); + rt_hw_us_delay(1); + inno_update_bits(inno, INNO_PART_DIGITAL, 0x00, + REG_DIG_RSTN_MASK, REG_DIG_RSTN_NORMAL); +} + +static void inno_timing_init(struct inno_dsidphy *inno) +{ + const struct rt_phye_configure_opts_mipi_dphy *cfg = &inno->cfg; + const struct inno_dphy_timing *timing; + rt_uint32_t byteclk, esc_div, esc_clk; + rt_uint32_t byte_period, esc_period; + rt_uint32_t hs_exit, clk_post, clk_pre; + rt_uint32_t ta_go, ta_sure, ta_wait; + rt_uint32_t part, hs_zero; + + byteclk = (rt_uint32_t)(inno->rate / 8); + esc_div = RT_DIV_ROUND_UP(byteclk, 20000000); + if (!esc_div) + { + esc_div = 1; + } + esc_clk = byteclk / esc_div; + byte_period = (rt_uint32_t)(PSEC_PER_SEC / byteclk); + esc_period = (rt_uint32_t)(PSEC_PER_SEC / esc_clk); + + hs_exit = RT_DIV_ROUND_UP(cfg->hs_exit, byte_period); + clk_post = RT_DIV_ROUND_UP(cfg->clk_post, byte_period); + clk_pre = RT_DIV_ROUND_UP(cfg->clk_pre, byte_period); + ta_go = RT_DIV_ROUND_UP(cfg->lpx * 4, esc_period); + ta_sure = RT_DIV_ROUND_UP(cfg->lpx, esc_period); + ta_wait = RT_DIV_ROUND_UP(cfg->lpx * 5, esc_period); + timing = inno_get_timing((rt_uint32_t)(inno->rate / 1000000)); + + for (part = INNO_PART_CLOCK_LANE; part <= INNO_PART_DATA3_LANE; ++part) + { + hs_zero = part == INNO_PART_CLOCK_LANE ? + timing->clk_hs_zero : timing->data_hs_zero; + + inno_update_bits(inno, part, 0x05, T_LPX_CNT_MASK, T_LPX_CNT(timing->lpx)); + inno_update_bits(inno, part, 0x06, T_HS_PREPARE_MASK, + T_HS_PREPARE(timing->hs_prepare)); + inno_update_bits(inno, part, 0x06, T_HS_ZERO_HI_MASK, T_HS_ZERO_HI(hs_zero)); + inno_update_bits(inno, part, 0x07, T_HS_ZERO_LO_MASK, T_HS_ZERO_LO(hs_zero)); + inno_update_bits(inno, part, 0x08, T_HS_TRAIL_MASK, T_HS_TRAIL(timing->hs_trail)); + inno_update_bits(inno, part, 0x11, T_HS_EXIT_HI_MASK, T_HS_EXIT_HI(hs_exit)); + inno_update_bits(inno, part, 0x09, T_HS_EXIT_LO_MASK, T_HS_EXIT_LO(hs_exit)); + inno_update_bits(inno, part, 0x10, T_CLK_POST_HI_MASK, T_CLK_POST_HI(clk_post)); + inno_update_bits(inno, part, 0x0a, T_CLK_POST_LO_MASK, T_CLK_POST_LO(clk_post)); + inno_update_bits(inno, part, 0x0e, T_CLK_PRE_MASK, T_CLK_PRE(clk_pre)); + inno_update_bits(inno, part, 0x0c, T_WAKEUP_HI_MASK, T_WAKEUP_HI(0x3ff)); + inno_update_bits(inno, part, 0x0d, T_WAKEUP_LO_MASK, T_WAKEUP_LO(0x3ff)); + inno_update_bits(inno, part, 0x10, T_TA_GO_MASK, T_TA_GO(ta_go)); + inno_update_bits(inno, part, 0x11, T_TA_SURE_MASK, T_TA_SURE(ta_sure)); + inno_update_bits(inno, part, 0x12, T_TA_WAIT_MASK, T_TA_WAIT(ta_wait)); + } +} + +static void inno_lane_enable(struct inno_dsidphy *inno) +{ + rt_uint8_t val = LANE_EN_CK | LANE_EN_0; + + if (inno->lanes >= 2) + { + val |= LANE_EN_1; + } + if (inno->lanes >= 3) + { + val |= LANE_EN_2; + } + if (inno->lanes >= 4) + { + val |= LANE_EN_3; + } + + inno_update_bits(inno, INNO_PART_ANALOG, 0x00, LANE_EN_MASK, val); +} + +static rt_err_t inno_dsidphy_init(struct rt_phye *phye) +{ + struct inno_dsidphy *inno = phye_to_inno(phye); + rt_err_t err; + + if ((err = rt_clk_prepare_enable(inno->pclk))) + { + return err; + } + if ((err = rt_clk_prepare_enable(inno->ref_clk))) + { + rt_clk_disable_unprepare(inno->pclk); + return err; + } + + if (!rt_is_err_or_null(inno->apb_rst)) + { + rt_reset_control_deassert(inno->apb_rst); + } + + return RT_EOK; +} + +static rt_err_t inno_dsidphy_exit(struct rt_phye *phye) +{ + struct inno_dsidphy *inno = phye_to_inno(phye); + + rt_clk_disable_unprepare(inno->ref_clk); + rt_clk_disable_unprepare(inno->pclk); + + return RT_EOK; +} + +static rt_err_t inno_dsidphy_set_mode(struct rt_phye *phye, + enum rt_phye_mode mode, int submode) +{ + RT_UNUSED(phye); + RT_UNUSED(submode); + + return mode == RT_PHYE_MODE_MIPI_DPHY ? RT_EOK : -RT_ENOSYS; +} + +static rt_err_t inno_dsidphy_configure(struct rt_phye *phye, + union rt_phye_configure_opts *opts) +{ + struct inno_dsidphy *inno = phye_to_inno(phye); + rt_err_t err; + + if (phye->mode != RT_PHYE_MODE_MIPI_DPHY || + !opts->mipi_dphy.hs_clk_rate || !opts->mipi_dphy.lanes || + opts->mipi_dphy.lanes > 4 || + opts->mipi_dphy.hs_clk_rate > INNO_DPHY_MAX_RATE) + { + return -RT_EINVAL; + } + + inno->cfg = opts->mipi_dphy; + if ((err = inno_pll_calc(inno, inno->cfg.hs_clk_rate))) + { + return err; + } + + inno->cfg.hs_clk_rate = inno->rate; + opts->mipi_dphy.hs_clk_rate = inno->rate; + + return RT_EOK; +} + +static rt_err_t inno_dsidphy_power_on(struct rt_phye *phye) +{ + struct inno_dsidphy *inno = phye_to_inno(phye); + + if (phye->mode != RT_PHYE_MODE_MIPI_DPHY || !inno->rate) + { + return -RT_EINVAL; + } + + inno_update_bits(inno, INNO_PART_ANALOG, 0x00, + BANDGAP_POWER_MASK, BANDGAP_POWER_ON); + inno_update_bits(inno, INNO_PART_ANALOG, 0x00, + POWER_WORK_MASK, POWER_WORK_ENABLE); + inno_update_bits(inno, INNO_PART_LVDS, 0x03, + MODE_ENABLE_MASK, MIPI_MODE_ENABLE); + + inno_pll_enable(inno); + inno_reset(inno); + inno_timing_init(inno); + inno_lane_enable(inno); + rt_hw_us_delay(1000); + + LOG_I("powered on: host=%u phy=%u lane(s), %u Mbps, prediv=%u fbdiv=%u", + inno->cfg.lanes, inno->lanes, (rt_uint32_t)(inno->rate / 1000000), + inno->prediv, inno->fbdiv); + + return RT_EOK; +} + +static rt_err_t inno_dsidphy_power_off(struct rt_phye *phye) +{ + struct inno_dsidphy *inno = phye_to_inno(phye); + + inno_update_bits(inno, INNO_PART_ANALOG, 0x00, LANE_EN_MASK, 0); + inno_update_bits(inno, INNO_PART_ANALOG, 0x01, + REG_LDOPD_MASK | REG_PLLPD_MASK, + REG_LDOPD_POWER_DOWN | REG_PLLPD_POWER_DOWN); + inno_update_bits(inno, INNO_PART_ANALOG, 0x00, + POWER_WORK_MASK, POWER_WORK_DISABLE); + inno_update_bits(inno, INNO_PART_ANALOG, 0x00, + BANDGAP_POWER_MASK, BANDGAP_POWER_DOWN); + + return RT_EOK; +} + +static const struct rt_phye_ops inno_dsidphy_ops = +{ + .init = inno_dsidphy_init, + .exit = inno_dsidphy_exit, + .power_on = inno_dsidphy_power_on, + .power_off = inno_dsidphy_power_off, + .set_mode = inno_dsidphy_set_mode, + .configure = inno_dsidphy_configure, +}; + +static rt_err_t inno_dsidphy_probe(struct rt_platform_device *pdev) +{ + struct rt_device *dev = &pdev->parent; + struct rt_ofw_node *np = dev->ofw_node; + struct inno_dsidphy *inno; + rt_err_t err; + + inno = rt_calloc(1, sizeof(*inno)); + if (!inno) + { + return -RT_ENOMEM; + } + + inno->regs = rt_ofw_iomap(np, 0); + if (!inno->regs) + { + err = -RT_EIO; + goto _fail; + } + + inno->ref_clk = rt_clk_get_by_name(dev, "ref"); + inno->pclk = rt_clk_get_by_name(dev, "pclk"); + if (rt_is_err_or_null(inno->ref_clk) || rt_is_err_or_null(inno->pclk)) + { + err = -RT_EIO; + goto _fail_clks; + } + + inno->apb_rst = rt_reset_control_get_by_name(dev, "apb"); + inno->lanes = 4; + rt_ofw_prop_read_u32(np, "inno,lanes", &inno->lanes); + if (!inno->lanes || inno->lanes > 4) + { + inno->lanes = 4; + } + inno->parent.dev = dev; + inno->parent.ops = &inno_dsidphy_ops; + + if ((err = rt_phye_register(&inno->parent))) + { + goto _fail_resources; + } + + dev->user_data = inno; + LOG_I("RK3568 DSI DPHY %s probed", rt_ofw_node_full_name(np)); + + return RT_EOK; + +_fail_resources: + if (!rt_is_err_or_null(inno->apb_rst)) + { + rt_reset_control_put(inno->apb_rst); + } +_fail_clks: + if (!rt_is_err_or_null(inno->pclk)) + { + rt_clk_put(inno->pclk); + } + if (!rt_is_err_or_null(inno->ref_clk)) + { + rt_clk_put(inno->ref_clk); + } + rt_iounmap(inno->regs); +_fail: + rt_free(inno); + return err; +} + +static const struct rt_ofw_node_id inno_dsidphy_ids[] = +{ + { .compatible = "rockchip,rk3568-dsi-dphy" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver inno_dsidphy_driver = +{ + .name = "rockchip-inno-dsidphy", + .ids = inno_dsidphy_ids, + .probe = inno_dsidphy_probe, +}; +RT_PLATFORM_DRIVER_EXPORT(inno_dsidphy_driver); diff --git a/bsp/rockchip/dm/phye/phye-rockchip-inno-usb2.c b/bsp/rockchip/dm/phye/phye-rockchip-inno-usb2.c new file mode 100644 index 000000000000..2e7e9171afe9 --- /dev/null +++ b/bsp/rockchip/dm/phye/phye-rockchip-inno-usb2.c @@ -0,0 +1,677 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-09-23 GuEe-GUI first version + */ + +#include +#include + +#include +#include + +#define DBG_TAG "phye.rockchip.inno-usb2" +#define DBG_LVL DBG_INFO +#include + +#define U2PHY_BIT_WRITEABLE_SHIFT 16 +#define U2PHY_CLK480M_RATE 480000000UL + +enum rockchip_u2phy_port_id +{ + ROCKCHIP_U2PHY_PORT_OTG = 0, + ROCKCHIP_U2PHY_PORT_HOST = 1, + ROCKCHIP_U2PHY_PORT_NUM = 2, +}; + +struct rockchip_u2phy_reg +{ + rt_uint32_t offset; + rt_uint16_t bitend; + rt_uint16_t bitstart; + rt_uint16_t disable; + rt_uint16_t enable; +}; + +struct rockchip_u2phy_port_cfg +{ + struct rockchip_u2phy_reg phy_sus; + struct rockchip_u2phy_reg bvalid_det_en; + struct rockchip_u2phy_reg bvalid_det_st; + struct rockchip_u2phy_reg bvalid_det_clr; + struct rockchip_u2phy_reg ls_det_en; + struct rockchip_u2phy_reg ls_det_st; + struct rockchip_u2phy_reg ls_det_clr; + struct rockchip_u2phy_reg iddig_output; + struct rockchip_u2phy_reg iddig_en; + struct rockchip_u2phy_reg idfall_det_en; + struct rockchip_u2phy_reg idfall_det_st; + struct rockchip_u2phy_reg idfall_det_clr; + struct rockchip_u2phy_reg idrise_det_en; + struct rockchip_u2phy_reg idrise_det_st; + struct rockchip_u2phy_reg idrise_det_clr; + struct rockchip_u2phy_reg utmi_avalid; + struct rockchip_u2phy_reg utmi_bvalid; + struct rockchip_u2phy_reg utmi_iddig; + struct rockchip_u2phy_reg utmi_ls; + struct rockchip_u2phy_reg utmi_hstdet; + struct rockchip_u2phy_reg vbus_det_en; +}; + +struct rockchip_u2phy_cfg +{ + rt_uint32_t reg; + rt_uint32_t num_ports; + struct rockchip_u2phy_reg clkout_ctl; + const struct rockchip_u2phy_port_cfg port_cfgs[ROCKCHIP_U2PHY_PORT_NUM]; +}; + +struct rockchip_u2phy_port +{ + struct rt_phye phye; + struct rt_device port_dev; + enum rockchip_u2phy_port_id id; + rt_bool_t registered; + struct rt_regulator *supply; + struct rockchip_inno_usb2phy *parent; +}; + +struct rockchip_inno_usb2phy +{ + struct rt_device *dev; + struct rt_syscon *usbgrf; + struct rt_clk *phyclk; + struct rt_reset_control *phy_rst; + const struct rockchip_u2phy_cfg *cfg; + struct rt_clk_node clk_np; + struct rt_clk_cell clk480m; + struct rt_clk_cell *clk_cells[1]; + struct rockchip_u2phy_port ports[ROCKCHIP_U2PHY_PORT_NUM]; +}; + +#define phye_to_u2phy_port(phye) rt_container_of(phye, struct rockchip_u2phy_port, phye) + +static rt_uint32_t rockchip_u2phy_genmask(rt_uint32_t hi, rt_uint32_t lo) +{ + return ((1u << (hi - lo + 1)) - 1) << lo; +} + +static struct rt_syscon *rockchip_u2phy_get_syscon(struct rockchip_inno_usb2phy *rphy) +{ + return rphy->usbgrf; +} + +static rt_err_t rockchip_u2phy_property_enable(struct rt_syscon *syscon, + const struct rockchip_u2phy_reg *reg, rt_bool_t en) +{ + rt_uint32_t mask, val, tmp; + + if (!syscon || !reg) + { + return -RT_EINVAL; + } + + tmp = en ? reg->enable : reg->disable; + mask = rockchip_u2phy_genmask(reg->bitend, reg->bitstart); + val = (tmp << reg->bitstart) | (mask << U2PHY_BIT_WRITEABLE_SHIFT); + + return rt_syscon_write(syscon, reg->offset, val); +} + +static rt_bool_t rockchip_u2phy_property_enabled(struct rt_syscon *syscon, + const struct rockchip_u2phy_reg *reg) +{ + rt_uint32_t val, mask; + + if (!syscon || !reg) + { + return RT_FALSE; + } + + if (rt_syscon_read(syscon, reg->offset, &val)) + { + return RT_FALSE; + } + + mask = rockchip_u2phy_genmask(reg->bitend, reg->bitstart); + val = (val & mask) >> reg->bitstart; + + return val != reg->disable; +} + +static rt_err_t rockchip_u2phy_reset(struct rockchip_inno_usb2phy *rphy) +{ + rt_err_t err; + + if (!rphy->phy_rst) + { + return RT_EOK; + } + + if ((err = rt_reset_control_assert(rphy->phy_rst))) + { + return err; + } + + rt_hw_us_delay(20); + + if ((err = rt_reset_control_deassert(rphy->phy_rst))) + { + return err; + } + + rt_hw_us_delay(100); + + return RT_EOK; +} + +static const struct rockchip_u2phy_port_cfg *rockchip_u2phy_port_cfg( + struct rockchip_u2phy_port *port) +{ + return &port->parent->cfg->port_cfgs[port->id]; +} + +static rt_err_t rockchip_u2phy_port_power_on(struct rt_phye *phye) +{ + struct rockchip_u2phy_port *port = phye_to_u2phy_port(phye); + + if (port->supply) + { + return rt_regulator_enable(port->supply); + } + + return RT_EOK; +} + +static rt_err_t rockchip_u2phy_port_power_off(struct rt_phye *phye) +{ + struct rockchip_u2phy_port *port = phye_to_u2phy_port(phye); + + if (port->supply) + { + return rt_regulator_disable(port->supply); + } + + return RT_EOK; +} + +static rt_err_t rockchip_u2phy_port_init(struct rt_phye *phye) +{ + struct rockchip_u2phy_port *port = phye_to_u2phy_port(phye); + struct rockchip_inno_usb2phy *rphy = port->parent; + struct rt_syscon *syscon = rockchip_u2phy_get_syscon(rphy); + const struct rockchip_u2phy_port_cfg *port_cfg = rockchip_u2phy_port_cfg(port); + + rockchip_u2phy_property_enable(syscon, &port_cfg->phy_sus, RT_FALSE); + rt_hw_us_delay(2000); + + return RT_EOK; +} + +static rt_err_t rockchip_u2phy_port_exit(struct rt_phye *phye) +{ + struct rockchip_u2phy_port *port = phye_to_u2phy_port(phye); + struct rockchip_inno_usb2phy *rphy = port->parent; + struct rt_syscon *syscon = rockchip_u2phy_get_syscon(rphy); + const struct rockchip_u2phy_port_cfg *port_cfg = rockchip_u2phy_port_cfg(port); + + return rockchip_u2phy_property_enable(syscon, &port_cfg->phy_sus, RT_TRUE); +} + +static rt_err_t rockchip_u2phy_clk480m_prepare(struct rt_clk_cell *cell) +{ + rt_err_t err; + struct rockchip_inno_usb2phy *rphy = rt_container_of(cell->clk_np, + struct rockchip_inno_usb2phy, clk_np); + + if (rockchip_u2phy_property_enabled(rphy->usbgrf, &rphy->cfg->clkout_ctl)) + { + return RT_EOK; + } + + if ((err = rockchip_u2phy_property_enable(rphy->usbgrf, &rphy->cfg->clkout_ctl, RT_TRUE))) + { + return err; + } + + rt_hw_us_delay(1300); + + return RT_EOK; +} + +static void rockchip_u2phy_clk480m_unprepare(struct rt_clk_cell *cell) +{ + struct rockchip_inno_usb2phy *rphy = rt_container_of(cell->clk_np, + struct rockchip_inno_usb2phy, clk_np); + + rockchip_u2phy_property_enable(rphy->usbgrf, &rphy->cfg->clkout_ctl, RT_FALSE); +} + +static rt_bool_t rockchip_u2phy_clk480m_is_prepared(struct rt_clk_cell *cell) +{ + struct rockchip_inno_usb2phy *rphy = rt_container_of(cell->clk_np, + struct rockchip_inno_usb2phy, clk_np); + + return rockchip_u2phy_property_enabled(rphy->usbgrf, &rphy->cfg->clkout_ctl); +} + +static rt_ubase_t rockchip_u2phy_clk480m_recalc_rate(struct rt_clk_cell *cell, + rt_ubase_t parent_rate) +{ + RT_UNUSED(cell); + RT_UNUSED(parent_rate); + + return U2PHY_CLK480M_RATE; +} + +static const struct rt_clk_ops rockchip_u2phy_clk480m_ops = +{ + .prepare = rockchip_u2phy_clk480m_prepare, + .unprepare = rockchip_u2phy_clk480m_unprepare, + .is_prepared = rockchip_u2phy_clk480m_is_prepared, + .recalc_rate = rockchip_u2phy_clk480m_recalc_rate, +}; + +static const struct rt_phye_ops rockchip_u2phy_port_ops = +{ + .init = rockchip_u2phy_port_init, + .exit = rockchip_u2phy_port_exit, + .power_on = rockchip_u2phy_port_power_on, + .power_off = rockchip_u2phy_port_power_off, +}; + +static rt_err_t rockchip_u2phy_register_clk480m(struct rockchip_inno_usb2phy *rphy) +{ + rt_err_t err; + const char *clk_name = rt_dm_dev_get_name(rphy->dev); + + rphy->clk_cells[0] = &rphy->clk480m; + + rphy->clk480m.name = clk_name; + rphy->clk480m.ops = &rockchip_u2phy_clk480m_ops; + rphy->clk480m.parents_nr = 1; + rphy->clk480m.parent = rphy->phyclk; + + if (rphy->phyclk && rphy->phyclk->cell) + { + rphy->clk480m.parent_name = rphy->phyclk->cell->name; + } + + rt_dm_dev_prop_read_string(rphy->dev, "clock-output-names", &rphy->clk480m.name); + + rphy->clk_np.dev = rphy->dev; + rphy->clk_np.cells_nr = RT_ARRAY_SIZE(rphy->clk_cells); + rphy->clk_np.cells = rphy->clk_cells; + rt_list_init(&rphy->clk_np.parent.list); + + if ((err = rt_clk_register(&rphy->clk_np))) + { + return err; + } + + return RT_EOK; +} + +static rt_err_t rockchip_u2phy_register_port(struct rockchip_inno_usb2phy *rphy, + struct rt_ofw_node *port_np, enum rockchip_u2phy_port_id id) +{ + rt_err_t err; + const char *log_name = rt_ofw_node_full_name(port_np); + struct rockchip_u2phy_port *port = &rphy->ports[id]; + + port->parent = rphy; + port->id = id; + port->port_dev.ofw_node = port_np; + port->phye.dev = &port->port_dev; + port->phye.ops = &rockchip_u2phy_port_ops; + port->registered = RT_FALSE; + port->supply = rt_regulator_get(&port->port_dev, "phy"); + + if (rt_is_err(port->supply)) + { + if (id == ROCKCHIP_U2PHY_PORT_OTG) + { + port->supply = rt_regulator_get(&port->port_dev, "vbus"); + } + + if (rt_is_err(port->supply)) + { + port->supply = RT_NULL; + } + } + + if ((err = rt_phye_register(&port->phye))) + { + LOG_E("%s: register phy for %s failed: %s", + rt_dm_dev_get_name(rphy->dev), log_name, rt_strerror(err)); + return err; + } + + port->registered = RT_TRUE; + LOG_I("%s: registered %s as %s phy supply=%s", + rt_dm_dev_get_name(rphy->dev), + log_name, + id == ROCKCHIP_U2PHY_PORT_HOST ? "host" : "otg", + port->supply ? "yes" : "no"); + + return RT_EOK; +} + +static void rockchip_u2phy_unregister_ports(struct rockchip_inno_usb2phy *rphy) +{ + int i; + + for (i = 0; i < ROCKCHIP_U2PHY_PORT_NUM; ++i) + { + struct rockchip_u2phy_port *port = &rphy->ports[i]; + + if (!port->registered) + { + continue; + } + + rt_phye_unregister(&port->phye); + + if (port->port_dev.ofw_node) + { + rt_ofw_data(port->port_dev.ofw_node) = RT_NULL; + } + + port->registered = RT_FALSE; + } +} + +static const struct rockchip_u2phy_cfg rk3568_phy_cfgs[] = +{ + { + .reg = 0xfe8a0000, + .num_ports = 2, + .clkout_ctl = { 0x0008, 4, 4, 1, 0 }, + .port_cfgs = + { + [ROCKCHIP_U2PHY_PORT_OTG] = + { + .phy_sus = { 0x0000, 8, 0, 0x052, 0x1d1 }, + .bvalid_det_en = { 0x0080, 2, 2, 0, 1 }, + .bvalid_det_st = { 0x0084, 2, 2, 0, 1 }, + .bvalid_det_clr = { 0x0088, 2, 2, 0, 1 }, + .iddig_output = { 0x0000, 10, 10, 0, 1 }, + .iddig_en = { 0x0000, 9, 9, 0, 1 }, + .idfall_det_en = { 0x0080, 5, 5, 0, 1 }, + .idfall_det_st = { 0x0084, 5, 5, 0, 1 }, + .idfall_det_clr = { 0x0088, 5, 5, 0, 1 }, + .idrise_det_en = { 0x0080, 4, 4, 0, 1 }, + .idrise_det_st = { 0x0084, 4, 4, 0, 1 }, + .idrise_det_clr = { 0x0088, 4, 4, 0, 1 }, + .ls_det_en = { 0x0080, 0, 0, 0, 1 }, + .ls_det_st = { 0x0084, 0, 0, 0, 1 }, + .ls_det_clr = { 0x0088, 0, 0, 0, 1 }, + .utmi_avalid = { 0x00c0, 10, 10, 0, 1 }, + .utmi_bvalid = { 0x00c0, 9, 9, 0, 1 }, + .utmi_iddig = { 0x00c0, 6, 6, 0, 1 }, + .utmi_ls = { 0x00c0, 5, 4, 0, 1 }, + }, + [ROCKCHIP_U2PHY_PORT_HOST] = + { + .phy_sus = { 0x0004, 8, 0, 0x1d2, 0x1d1 }, + .ls_det_en = { 0x0080, 1, 1, 0, 1 }, + .ls_det_st = { 0x0084, 1, 1, 0, 1 }, + .ls_det_clr = { 0x0088, 1, 1, 0, 1 }, + .utmi_ls = { 0x00c0, 17, 16, 0, 1 }, + .utmi_hstdet = { 0x00c0, 19, 19, 0, 1 }, + }, + }, + }, + { + .reg = 0xfe8b0000, + .num_ports = 2, + .clkout_ctl = { 0x0008, 4, 4, 1, 0 }, + .port_cfgs = + { + [ROCKCHIP_U2PHY_PORT_OTG] = + { + .phy_sus = { 0x0000, 8, 0, 0x1d2, 0x1d1 }, + .ls_det_en = { 0x0080, 0, 0, 0, 1 }, + .ls_det_st = { 0x0084, 0, 0, 0, 1 }, + .ls_det_clr = { 0x0088, 0, 0, 0, 1 }, + .utmi_ls = { 0x00c0, 5, 4, 0, 1 }, + .utmi_hstdet = { 0x00c0, 7, 7, 0, 1 }, + }, + [ROCKCHIP_U2PHY_PORT_HOST] = + { + .phy_sus = { 0x0004, 8, 0, 0x1d2, 0x1d1 }, + .ls_det_en = { 0x0080, 1, 1, 0, 1 }, + .ls_det_st = { 0x0084, 1, 1, 0, 1 }, + .ls_det_clr = { 0x0088, 1, 1, 0, 1 }, + .utmi_ls = { 0x00c0, 17, 16, 0, 1 }, + .utmi_hstdet = { 0x00c0, 19, 19, 0, 1 }, + }, + }, + }, + { /* sentinel */ }, +}; + +static const struct rockchip_u2phy_cfg *rockchip_u2phy_match_cfg( + const struct rockchip_u2phy_cfg *cfgs, rt_uint64_t addr) +{ + for (int i = 0; cfgs[i].reg; ++i) + { + if (cfgs[i].reg == (rt_uint32_t)addr) + { + return &cfgs[i]; + } + } + + return RT_NULL; +} + +static rt_err_t rockchip_inno_usb2phy_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + rt_uint64_t addr; + int port_count = 0; + struct rt_device *dev = &pdev->parent; + const char *dev_name = rt_dm_dev_get_name(dev); + struct rt_ofw_node *port_np; + struct rockchip_inno_usb2phy *rphy = rt_calloc(1, sizeof(*rphy)); + const struct rockchip_u2phy_cfg *cfgs = pdev->id->data; + + if (!rphy) + { + LOG_E("%s: no memory for usb2phy", dev_name); + return -RT_ENOMEM; + } + + rphy->dev = dev; + dev->user_data = rphy; + LOG_I("%s: probe start", dev_name); + + if ((err = rt_dm_dev_get_address(dev, 0, &addr, RT_NULL))) + { + LOG_E("%s: get address failed: %s", dev_name, rt_strerror(err)); + goto _fail; + } + LOG_I("%s: addr=0x%08x", dev_name, (rt_uint32_t)addr); + + rphy->cfg = rockchip_u2phy_match_cfg(cfgs, addr); + + if (!rphy->cfg) + { + LOG_E("%s: no phy config for 0x%08x", dev_name, (rt_uint32_t)addr); + err = -RT_EINVAL; + goto _fail; + } + LOG_I("%s: matched phy cfg for 0x%08x", dev_name, (rt_uint32_t)addr); + + rphy->usbgrf = rt_syscon_find_by_ofw_phandle(dev->ofw_node, "rockchip,usbgrf"); + + if (!rphy->usbgrf) + { + LOG_E("%s: failed to get usbgrf", dev_name); + err = -RT_EIO; + goto _fail; + } + LOG_I("%s: usbgrf acquired", dev_name); + + rphy->phyclk = rt_clk_get_by_name(dev, "phyclk"); + + if (rt_is_err(rphy->phyclk)) + { + err = rt_ptr_err(rphy->phyclk); + LOG_E("%s: get phyclk failed: %s", dev_name, rt_strerror(err)); + goto _fail; + } + LOG_I("%s: phyclk acquired", dev_name); + + rphy->phy_rst = rt_reset_control_get_by_name(dev, "phy"); + + if (rt_is_err(rphy->phy_rst)) + { + rphy->phy_rst = RT_NULL; + LOG_W("%s: reset 'phy' not found", dev_name); + } + else + { + LOG_I("%s: reset 'phy' acquired", dev_name); + } + + if ((err = rt_clk_prepare_enable(rphy->phyclk))) + { + LOG_E("%s: enable phyclk failed: %s", dev_name, rt_strerror(err)); + goto _fail_clk; + } + LOG_I("%s: phyclk enabled", dev_name); + + if ((err = rockchip_u2phy_reset(rphy))) + { + LOG_E("%s: phy reset failed: %s", dev_name, rt_strerror(err)); + goto _fail_clk_en; + } + LOG_I("%s: phy reset done", dev_name); + + if ((err = rockchip_u2phy_register_clk480m(rphy))) + { + LOG_E("%s: register 480m clk failed: %s", dev_name, rt_strerror(err)); + goto _fail_clk_en; + } + LOG_I("%s: 480m output clock registered as %s", dev_name, rphy->clk480m.name); + + if (rphy->cfg->clkout_ctl.disable) + { + rockchip_u2phy_property_enable(rphy->usbgrf, &rphy->cfg->clkout_ctl, RT_TRUE); + LOG_I("%s: clkout enabled", dev_name); + } + + rt_ofw_foreach_available_child_node(dev->ofw_node, port_np) + { + const char *log_name = rt_ofw_node_full_name(port_np); + + LOG_I("%s: found child port %s", dev_name, log_name); + + if (rt_ofw_node_tag_equ(port_np, "host-port")) + { + err = rockchip_u2phy_register_port(rphy, port_np, ROCKCHIP_U2PHY_PORT_HOST); + } + else if (rt_ofw_node_tag_equ(port_np, "otg-port")) + { + err = rockchip_u2phy_register_port(rphy, port_np, ROCKCHIP_U2PHY_PORT_OTG); + } + else + { + LOG_W("%s: skip unknown child node %s", dev_name, log_name); + continue; + } + + if (err) + { + rt_ofw_node_put(port_np); + LOG_E("%s: register port %s failed: %s", dev_name, log_name, rt_strerror(err)); + goto _fail_ports; + } + + ++port_count; + } + + if (!port_count) + { + LOG_W("%s: no available child ports registered", dev_name); + } + + LOG_I("%s: probe success with %d port(s)", dev_name, port_count); + + return RT_EOK; + +_fail_ports: + rockchip_u2phy_unregister_ports(rphy); + +_fail_clk_en: + rt_clk_disable_unprepare(rphy->phyclk); + rt_clk_unregister(&rphy->clk_np); + +_fail_clk: + if (!rt_is_err_or_null(rphy->phyclk)) + { + rt_clk_put(rphy->phyclk); + } + +_fail: + rt_free(rphy); + + return err; +} + +static rt_err_t rockchip_inno_usb2phy_remove(struct rt_platform_device *pdev) +{ + struct rockchip_inno_usb2phy *rphy = pdev->parent.user_data; + const char *dev_name = rt_dm_dev_get_name(&pdev->parent); + + if (!rphy) + { + LOG_W("%s: remove with empty context", dev_name); + return RT_EOK; + } + + LOG_I("%s: remove", dev_name); + pdev->parent.user_data = RT_NULL; + + rockchip_u2phy_unregister_ports(rphy); + + if (rt_clk_unregister(&rphy->clk_np)) + { + LOG_W("%s: unregister 480m clk failed", dev_name); + } + + rt_clk_disable_unprepare(rphy->phyclk); + rt_clk_put(rphy->phyclk); + + if (!rt_is_err_or_null(rphy->phy_rst)) + { + rt_reset_control_put(rphy->phy_rst); + } + + rt_free(rphy); + + LOG_I("%s: remove done", dev_name); + + return RT_EOK; +} + +static const struct rt_ofw_node_id rockchip_inno_usb2phy_ids[] = +{ + { .compatible = "rockchip,rk3568-usb2phy", .data = (void *)&rk3568_phy_cfgs }, + { /* sentinel */ }, +}; + +static struct rt_platform_driver rockchip_inno_usb2phy_driver = +{ + .name = "phye-rockchip-inno-usb2", + .ids = rockchip_inno_usb2phy_ids, + + .probe = rockchip_inno_usb2phy_probe, + .remove = rockchip_inno_usb2phy_remove, +}; +RT_PLATFORM_DRIVER_EXPORT(rockchip_inno_usb2phy_driver); diff --git a/bsp/rockchip/dm/phye/phye-rockchip-mipi-dcphy.c b/bsp/rockchip/dm/phye/phye-rockchip-mipi-dcphy.c new file mode 100644 index 000000000000..7f634821343d --- /dev/null +++ b/bsp/rockchip/dm/phye/phye-rockchip-mipi-dcphy.c @@ -0,0 +1,495 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-09-23 GuEe-GUI first version + */ + +#include +#include +#include +#include +#include +#include +#include + +#define DBG_TAG "phye.dcphy" +#define DBG_LVL DBG_INFO +#include + +#define UPDATE(v, h, l) (((v) << (l)) & (((2U << (h)) - 1U) & ~((1U << (l)) - 1U))) + +#define BIAS_CON0 0x0000 +#define BIAS_CON1 0x0004 +#define BIAS_CON2 0x0008 +#define PLL_CON0 0x0100 +#define PLL_CON1 0x0104 +#define PLL_CON2 0x0108 +#define PLL_CON5 0x0114 +#define PLL_CON7 0x011c +#define PLL_CON8 0x0120 +#define PLL_STAT0 0x0140 +#define DPHY_MC_GNR_CON0 0x0300 +#define DPHY_MC_GNR_CON1 0x0304 +#define DPHY_MC_ANA_CON0 0x0308 +#define DPHY_MC_TIME_CON0 0x0330 +#define DPHY_MC_TIME_CON1 0x0334 +#define DPHY_MC_TIME_CON2 0x0338 +#define DPHY_MC_TIME_CON3 0x033c +#define DPHY_MC_TIME_CON4 0x0340 +#define COMBO_MD0_GNR_CON0 0x0400 +#define COMBO_MD0_GNR_CON1 0x0404 +#define COMBO_MD0_ANA_CON0 0x0408 +#define COMBO_MD0_TIME_CON0 0x0430 +#define COMBO_MD0_TIME_CON1 0x0434 +#define COMBO_MD0_TIME_CON2 0x0438 +#define COMBO_MD1_GNR_CON0 0x0500 +#define COMBO_MD1_GNR_CON1 0x0504 +#define COMBO_MD1_TIME_CON0 0x0530 +#define COMBO_MD1_TIME_CON1 0x0534 +#define COMBO_MD1_TIME_CON2 0x0538 +#define COMBO_MD2_GNR_CON0 0x0600 +#define COMBO_MD2_GNR_CON1 0x0604 +#define COMBO_MD2_TIME_CON0 0x0630 +#define COMBO_MD2_TIME_CON1 0x0634 +#define COMBO_MD2_TIME_CON2 0x0638 +#define DPHY_MD3_GNR_CON0 0x0700 +#define DPHY_MD3_GNR_CON1 0x0704 + +#define PLL_EN RT_BIT(12) +#define PLL_LOCK RT_BIT(0) +#define PHY_ENABLE RT_BIT(0) +#define RESET_N_SEL RT_BIT(10) +#define PLL_ENABLE_SEL RT_BIT(8) +#define HSTX_CLK_SEL RT_BIT(12) +#define EDGE_CON_EN RT_BIT(8) +#define EDGE_CON(x) UPDATE(x, 14, 12) + +struct rk_dcphy_timing +{ + rt_uint16_t max_lane_mbps; + rt_uint8_t lpx; + rt_uint8_t clk_prepare; + rt_uint8_t clk_zero; + rt_uint8_t clk_pre; + rt_uint8_t clk_post; + rt_uint8_t clk_trail_eot; + rt_uint8_t hs_exit; + rt_uint8_t prepare_3; + rt_uint8_t trail_3; + rt_uint8_t zero_3; +}; + +struct rk_mipi_dcphy_pll +{ + rt_uint8_t prediv; + rt_uint16_t fbdiv; + rt_uint16_t dsm; + rt_uint8_t scaler; + rt_uint64_t rate; +}; + +struct rk_mipi_dcphy +{ + struct rt_phye parent; + + void *regs; + struct rt_clk *pclk; + struct rt_clk *ref_clk; + struct rt_reset_control *m_phy_rst; + struct rt_reset_control *apb_rst; + + rt_uint32_t lane_mbps; + rt_uint32_t lanes; + enum rt_phye_mode mode; + + struct rk_mipi_dcphy_pll pll; +}; + +static const struct rk_dcphy_timing rk_dcphy_timings[] = +{ + { 2500, 31, 114, 30, 27, 30, 54, 26, 23, 43, 36 }, + { 1500, 30, 110, 29, 26, 29, 52, 25, 22, 42, 35 }, + { 1000, 31, 113, 30, 27, 30, 54, 26, 23, 43, 36 }, + { 800, 30, 108, 29, 26, 28, 51, 25, 22, 41, 34 }, + { 600, 29, 106, 28, 25, 27, 50, 24, 21, 40, 33 }, + { 500, 28, 104, 27, 25, 27, 49, 24, 21, 39, 32 }, +}; + +#define raw_to_rk_mipi_dcphy(raw) rt_container_of(raw, struct rk_mipi_dcphy, parent) + +rt_inline void dcphy_write(struct rk_mipi_dcphy *dcphy, rt_uint32_t reg, rt_uint32_t val) +{ + HWREG32((rt_uint8_t *)dcphy->regs + reg) = val; +} + +rt_inline void dcphy_set_bits(struct rk_mipi_dcphy *dcphy, rt_uint32_t reg, + rt_uint32_t mask, rt_uint32_t val) +{ + rt_uint32_t v = HWREG32((rt_uint8_t *)dcphy->regs + reg); + + dcphy_write(dcphy, reg, (v & ~mask) | (val & mask)); +} + +static const struct rk_dcphy_timing *dcphy_get_timing(rt_uint32_t lane_mbps) +{ + rt_size_t i; + + for (i = 0; i < RT_ARRAY_SIZE(rk_dcphy_timings); ++i) + { + if (lane_mbps <= rk_dcphy_timings[i].max_lane_mbps) + { + return &rk_dcphy_timings[i]; + } + } + + return &rk_dcphy_timings[RT_ARRAY_SIZE(rk_dcphy_timings) - 1]; +} + +static void dcphy_pll_calc(struct rk_mipi_dcphy *dcphy, rt_uint64_t rate_hz) +{ + rt_ubase_t prate = rt_clk_get_rate(dcphy->ref_clk); + rt_uint16_t fbdiv; + + if (!prate) + { + prate = 24000000; + } + + dcphy->pll.prediv = 1; + dcphy->pll.scaler = 0; + dcphy->pll.dsm = 0; + + fbdiv = (rt_uint16_t)(rate_hz / prate); + if (fbdiv < 16) + { + fbdiv = 16; + } + if (fbdiv > 1023) + { + fbdiv = 1023; + } + + dcphy->pll.fbdiv = fbdiv; + dcphy->pll.rate = (prate / dcphy->pll.prediv) * fbdiv; +} + +static void dcphy_pll_program(struct rk_mipi_dcphy *dcphy) +{ + dcphy_set_bits(dcphy, PLL_CON0, UPDATE(0x7, 10, 8) | UPDATE(0x3f, 5, 0), + UPDATE(0, 10, 8) | UPDATE(dcphy->pll.prediv, 5, 0)); + dcphy_write(dcphy, PLL_CON1, dcphy->pll.dsm); + dcphy_set_bits(dcphy, PLL_CON2, UPDATE(0x3ff, 9, 0), UPDATE(dcphy->pll.fbdiv, 9, 0)); + dcphy_write(dcphy, PLL_CON5, RESET_N_SEL | PLL_ENABLE_SEL); + dcphy_write(dcphy, PLL_CON7, UPDATE(0xf000, 15, 0)); + dcphy_write(dcphy, PLL_CON8, UPDATE(0xf000, 15, 0)); +} + +static rt_err_t dcphy_pll_enable(struct rk_mipi_dcphy *dcphy) +{ + rt_int32_t i; + + dcphy_set_bits(dcphy, PLL_CON0, PLL_EN, PLL_EN); + + for (i = 0; i < 20000; ++i) + { + if (HWREG32((rt_uint8_t *)dcphy->regs + PLL_STAT0) & PLL_LOCK) + { + return RT_EOK; + } + + rt_hw_us_delay(1); + } + + LOG_W("DCPHY PLL lock timeout"); + + return -RT_ETIMEOUT; +} + +static void dcphy_bias_enable(struct rk_mipi_dcphy *dcphy) +{ + RT_UNUSED(dcphy); + + dcphy_write(dcphy, BIAS_CON0, 0x0010); + dcphy_write(dcphy, BIAS_CON1, 0x0110); + dcphy_write(dcphy, BIAS_CON2, 0x0007); +} + +static void dcphy_dphy_clk_timing(struct rk_mipi_dcphy *dcphy, const struct rk_dcphy_timing *t) +{ + rt_uint32_t val; + + dcphy_write(dcphy, DPHY_MC_GNR_CON0, 0xf000); + dcphy_write(dcphy, DPHY_MC_ANA_CON0, EDGE_CON(7) | EDGE_CON_EN | UPDATE(0x5, 7, 4) | UPDATE(0x5, 3, 0)); + + val = (dcphy->lane_mbps < 1500) ? HSTX_CLK_SEL : 0; + val |= UPDATE(t->lpx, 11, 4); + dcphy_write(dcphy, DPHY_MC_TIME_CON0, val); + dcphy_write(dcphy, DPHY_MC_TIME_CON1, UPDATE(t->clk_zero, 15, 8) | UPDATE(t->clk_prepare, 7, 0)); + dcphy_write(dcphy, DPHY_MC_TIME_CON2, UPDATE(t->hs_exit, 15, 8) | UPDATE(t->clk_trail_eot, 7, 0)); + dcphy_write(dcphy, DPHY_MC_TIME_CON3, UPDATE(t->clk_post, 7, 0)); + dcphy_write(dcphy, DPHY_MC_TIME_CON4, 0x1f4); +} + +static void dcphy_dphy_data_timing(struct rk_mipi_dcphy *dcphy, const struct rk_dcphy_timing *t) +{ + rt_uint32_t val = UPDATE(t->zero_3, 15, 8) | UPDATE(t->prepare_3, 7, 0); + rt_uint32_t val2 = UPDATE(t->hs_exit, 15, 8) | UPDATE(t->trail_3, 7, 0); + + dcphy_write(dcphy, COMBO_MD0_ANA_CON0, UPDATE(0x5, 7, 4) | UPDATE(0x5, 3, 0)); + dcphy_write(dcphy, COMBO_MD0_TIME_CON0, UPDATE(t->lpx, 11, 4)); + dcphy_write(dcphy, COMBO_MD0_TIME_CON1, val); + dcphy_write(dcphy, COMBO_MD0_TIME_CON2, val2); + + dcphy_write(dcphy, COMBO_MD1_TIME_CON0, UPDATE(t->lpx, 11, 4)); + dcphy_write(dcphy, COMBO_MD1_TIME_CON1, val); + dcphy_write(dcphy, COMBO_MD1_TIME_CON2, val2); + + dcphy_write(dcphy, COMBO_MD2_TIME_CON0, UPDATE(t->lpx, 11, 4)); + dcphy_write(dcphy, COMBO_MD2_TIME_CON1, val); + dcphy_write(dcphy, COMBO_MD2_TIME_CON2, val2); +} + +static void dcphy_dphy_lane_enable(struct rk_mipi_dcphy *dcphy) +{ + dcphy_write(dcphy, DPHY_MC_GNR_CON1, UPDATE(0x2000, 15, 0)); + dcphy_set_bits(dcphy, DPHY_MC_GNR_CON0, PHY_ENABLE, PHY_ENABLE); + + if (dcphy->lanes >= 4) + { + dcphy_write(dcphy, DPHY_MD3_GNR_CON1, UPDATE(0x2000, 15, 0)); + dcphy_set_bits(dcphy, DPHY_MD3_GNR_CON0, PHY_ENABLE, PHY_ENABLE); + } + + if (dcphy->lanes >= 3) + { + dcphy_write(dcphy, COMBO_MD2_GNR_CON1, UPDATE(0x2000, 15, 0)); + dcphy_set_bits(dcphy, COMBO_MD2_GNR_CON0, PHY_ENABLE, PHY_ENABLE); + } + + if (dcphy->lanes >= 2) + { + dcphy_write(dcphy, COMBO_MD1_GNR_CON1, UPDATE(0x2000, 15, 0)); + dcphy_set_bits(dcphy, COMBO_MD1_GNR_CON0, PHY_ENABLE, PHY_ENABLE); + } + + dcphy_write(dcphy, COMBO_MD0_GNR_CON1, UPDATE(0x2000, 15, 0)); + dcphy_set_bits(dcphy, COMBO_MD0_GNR_CON0, PHY_ENABLE, PHY_ENABLE); +} + +static void dcphy_dphy_lane_disable(struct rk_mipi_dcphy *dcphy) +{ + dcphy_set_bits(dcphy, DPHY_MC_GNR_CON0, PHY_ENABLE, 0); + dcphy_set_bits(dcphy, COMBO_MD0_GNR_CON0, PHY_ENABLE, 0); + dcphy_set_bits(dcphy, COMBO_MD1_GNR_CON0, PHY_ENABLE, 0); + dcphy_set_bits(dcphy, COMBO_MD2_GNR_CON0, PHY_ENABLE, 0); + dcphy_set_bits(dcphy, DPHY_MD3_GNR_CON0, PHY_ENABLE, 0); +} + +static rt_err_t rk_mipi_dcphy_configure(struct rt_phye *phye, union rt_phye_configure_opts *opts) +{ + struct rk_mipi_dcphy *dcphy = raw_to_rk_mipi_dcphy(phye); + rt_uint64_t target_rate = opts->mipi_dphy.hs_clk_rate; + rt_uint32_t lanes = opts->mipi_dphy.lanes; + + if (dcphy->mode != RT_PHYE_MODE_MIPI_DPHY) + { + return -RT_ENOSYS; + } + + if (lanes > 4) + { + lanes = 4; + } + if (!lanes) + { + lanes = 4; + } + + dcphy->lanes = lanes; + dcphy_pll_calc(dcphy, target_rate); + + dcphy->lane_mbps = (rt_uint32_t)(dcphy->pll.rate / 1000000ULL); + if (dcphy->lane_mbps < 200) + { + dcphy->lane_mbps = 500; + dcphy_pll_calc(dcphy, 500000000ULL); + } + + opts->mipi_dphy.hs_clk_rate = dcphy->pll.rate; + opts->mipi_dphy.lanes = dcphy->lanes; + + return RT_EOK; +} + +static rt_err_t rk_mipi_dcphy_init(struct rt_phye *phye) +{ + struct rk_mipi_dcphy *dcphy = raw_to_rk_mipi_dcphy(phye); + + rt_clk_prepare_enable(dcphy->pclk); + rt_clk_prepare_enable(dcphy->ref_clk); + + if (!rt_is_err_or_null(dcphy->apb_rst)) + { + rt_reset_control_deassert(dcphy->apb_rst); + } + + return RT_EOK; +} + +static rt_err_t rk_mipi_dcphy_exit(struct rt_phye *phye) +{ + struct rk_mipi_dcphy *dcphy = raw_to_rk_mipi_dcphy(phye); + + rt_clk_disable_unprepare(dcphy->ref_clk); + rt_clk_disable_unprepare(dcphy->pclk); + + return RT_EOK; +} + +static rt_err_t rk_mipi_dcphy_power_on(struct rt_phye *phye) +{ + struct rk_mipi_dcphy *dcphy = raw_to_rk_mipi_dcphy(phye); + const struct rk_dcphy_timing *timing; + + if (dcphy->mode != RT_PHYE_MODE_MIPI_DPHY) + { + return -RT_ENOSYS; + } + + if (!dcphy->lane_mbps) + { + dcphy->lane_mbps = 500; + dcphy->lanes = 4; + dcphy_pll_calc(dcphy, 500000000ULL); + } + + timing = dcphy_get_timing(dcphy->lane_mbps); + + if (!rt_is_err_or_null(dcphy->m_phy_rst)) + { + rt_reset_control_assert(dcphy->m_phy_rst); + } + + dcphy_bias_enable(dcphy); + dcphy_pll_program(dcphy); + dcphy_dphy_clk_timing(dcphy, timing); + dcphy_dphy_data_timing(dcphy, timing); + dcphy_pll_enable(dcphy); + dcphy_dphy_lane_enable(dcphy); + + if (!rt_is_err_or_null(dcphy->m_phy_rst)) + { + rt_reset_control_deassert(dcphy->m_phy_rst); + } + + rt_thread_mdelay(1); + + return RT_EOK; +} + +static rt_err_t rk_mipi_dcphy_power_off(struct rt_phye *phye) +{ + struct rk_mipi_dcphy *dcphy = raw_to_rk_mipi_dcphy(phye); + + dcphy_dphy_lane_disable(dcphy); + dcphy_set_bits(dcphy, PLL_CON0, PLL_EN, 0); + + return RT_EOK; +} + +static rt_err_t rk_mipi_dcphy_set_mode(struct rt_phye *phye, enum rt_phye_mode mode, int submode) +{ + struct rk_mipi_dcphy *dcphy = raw_to_rk_mipi_dcphy(phye); + + RT_UNUSED(submode); + + dcphy->mode = mode; + + return RT_EOK; +} + +static const struct rt_phye_ops rk_mipi_dcphy_ops = +{ + .init = rk_mipi_dcphy_init, + .exit = rk_mipi_dcphy_exit, + .power_on = rk_mipi_dcphy_power_on, + .power_off = rk_mipi_dcphy_power_off, + .set_mode = rk_mipi_dcphy_set_mode, + .configure = rk_mipi_dcphy_configure, +}; + +static rt_err_t rk_mipi_dcphy_probe(struct rt_platform_device *pdev) +{ + struct rt_device *dev = &pdev->parent; + struct rt_ofw_node *np = dev->ofw_node; + struct rk_mipi_dcphy *dcphy = rt_calloc(1, sizeof(*dcphy)); + rt_err_t err; + + if (!dcphy) + { + return -RT_ENOMEM; + } + + dcphy->regs = rt_ofw_iomap(np, 0); + + if (!dcphy->regs) + { + err = -RT_EIO; + goto _fail; + } + + dcphy->pclk = rt_clk_get_by_name(dev, "pclk"); + dcphy->ref_clk = rt_clk_get_by_name(dev, "ref"); + + if (rt_is_err_or_null(dcphy->pclk) || rt_is_err_or_null(dcphy->ref_clk)) + { + err = -RT_EIO; + goto _fail_unmap; + } + + dcphy->m_phy_rst = rt_reset_control_get_by_name(dev, "m_phy"); + dcphy->apb_rst = rt_reset_control_get_by_name(dev, "apb"); + + dcphy->lanes = 4; + dcphy->mode = RT_PHYE_MODE_MIPI_DPHY; + + dcphy->parent.dev = dev; + dcphy->parent.ops = &rk_mipi_dcphy_ops; + + if ((err = rt_phye_register(&dcphy->parent))) + { + goto _fail_unmap; + } + + dev->user_data = dcphy; + + LOG_I("MIPI DCPHY %s probed", np->name); + + return RT_EOK; + +_fail_unmap: + rt_iounmap(dcphy->regs); +_fail: + rt_free(dcphy); + + return err; +} + +static const struct rt_ofw_node_id rk_mipi_dcphy_ids[] = +{ + { .compatible = "rockchip,rk3576-mipi-dcphy" }, + { .compatible = "rockchip,rk3588-mipi-dcphy" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver rk_mipi_dcphy_driver = +{ + .name = "phy-rockchip-mipi-dcphy", + .ids = rk_mipi_dcphy_ids, + .probe = rk_mipi_dcphy_probe, +}; +RT_PLATFORM_DRIVER_EXPORT(rk_mipi_dcphy_driver); diff --git a/bsp/rockchip/dm/pin/pin-rockchip.c b/bsp/rockchip/dm/pin/pin-rockchip.c index a2f12e11c490..c5450d4313ba 100755 --- a/bsp/rockchip/dm/pin/pin-rockchip.c +++ b/bsp/rockchip/dm/pin/pin-rockchip.c @@ -465,14 +465,41 @@ static rt_err_t rockchip_gpio_probe(struct rt_platform_device *pdev) rt_err_t err; int id, version; const char *name; - struct rockchip_pin_bank *pin_bank; + struct rockchip_pin_bank *pin_bank = RT_NULL; struct rt_ofw_node *np = pdev->parent.ofw_node; - struct rt_ofw_node *npp = rt_ofw_get_parent(np); - struct rockchip_pinctrl_device *pinctrl_dev = rt_ofw_data(npp); - struct rockchip_pin_ctrl *pinctrl = pinctrl_dev->pinctrl; + struct rt_ofw_node *npp; + struct rockchip_pinctrl_device *pinctrl_dev; + struct rockchip_pin_ctrl *pinctrl; + + if (!np || !(npp = rt_ofw_get_parent(np))) + { + return -RT_EINVAL; + } + + pinctrl_dev = rt_ofw_data(npp); + + if (!pinctrl_dev) + { + err = rt_platform_ofw_request(npp); + pinctrl_dev = rt_ofw_data(npp); + + if (err || !pinctrl_dev) + { + rt_ofw_node_put(npp); + + return err ? err : -RT_EIO; + } + } + + pinctrl = pinctrl_dev->pinctrl; rt_ofw_node_put(npp); + if (!pinctrl || !pinctrl->pin_banks || !pinctrl->banks_nr) + { + return -RT_EIO; + } + if ((id = pdev->dev_id) < 0) { static int gpio_uid = 0; @@ -480,6 +507,11 @@ static rt_err_t rockchip_gpio_probe(struct rt_platform_device *pdev) id = gpio_uid++; } + if (id >= pinctrl->banks_nr) + { + return -RT_EINVAL; + } + pin_bank = &pinctrl->pin_banks[id]; pin_bank->reg_base = rt_ofw_iomap(np, 0); @@ -558,13 +590,13 @@ static rt_err_t rockchip_gpio_probe(struct rt_platform_device *pdev) rt_iounmap(pin_bank->reg_base); } - if (rt_is_err_or_null(pin_bank->clk)) + if (!rt_is_err_or_null(pin_bank->clk)) { rt_clk_disable_unprepare(pin_bank->clk); rt_clk_put(pin_bank->clk); } - if (rt_is_err_or_null(pin_bank->db_clk)) + if (!rt_is_err_or_null(pin_bank->db_clk)) { rt_clk_disable_unprepare(pin_bank->db_clk); rt_clk_put(pin_bank->db_clk); diff --git a/bsp/rockchip/dm/sdio/Kconfig b/bsp/rockchip/dm/sdio/Kconfig index 85905c77e626..3d55f9444b46 100755 --- a/bsp/rockchip/dm/sdio/Kconfig +++ b/bsp/rockchip/dm/sdio/Kconfig @@ -1,5 +1,11 @@ config RT_SDIO_DW_MMC_ROCKCHIP - bool "Rockchip" + bool "Rockchip DesignWare MMC" depends on RT_SDIO_DW_MMC depends on RT_USING_OFW default n + +config RT_SDIO_SDHCI_DWCMSHC_ROCKCHIP + bool "Rockchip DWC MSHC SDHCI" + depends on RT_SDIO_SDHCI_DWCMSHC + depends on RT_USING_OFW + default n diff --git a/bsp/rockchip/dm/sdio/SConscript b/bsp/rockchip/dm/sdio/SConscript index 968b4d3bafc4..d888688156d0 100755 --- a/bsp/rockchip/dm/sdio/SConscript +++ b/bsp/rockchip/dm/sdio/SConscript @@ -7,6 +7,9 @@ CPPPATH = [cwd + '/../include', cwd + '/../../../../components/drivers/sdio/host if GetDepend(['RT_SDIO_DW_MMC_ROCKCHIP']): src += ['sdio-dw_rockchip.c'] +if GetDepend(['RT_SDIO_SDHCI_DWCMSHC_ROCKCHIP']): + src += ['sdhci-dwcmshc_rockchip.c'] + group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) Return('group') diff --git a/bsp/rockchip/dm/sdio/sdhci-dwcmshc_rockchip.c b/bsp/rockchip/dm/sdio/sdhci-dwcmshc_rockchip.c new file mode 100644 index 000000000000..8009572df563 --- /dev/null +++ b/bsp/rockchip/dm/sdio/sdhci-dwcmshc_rockchip.c @@ -0,0 +1,629 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-01-30 RT-Thread first version + */ + +#include "rockchip.h" +#include "sdhci-dwcmshc-platform.h" + +#include + +#define DBG_TAG "sdhci.dw.rockchip" +#define DBG_LVL DBG_INFO +#include + +/* Rockchip specific Registers */ +#define DWCMSHC_EMMC_DLL_CTRL 0x800 +#define DWCMSHC_EMMC_DLL_RXCLK 0x804 +#define DWCMSHC_EMMC_DLL_TXCLK 0x808 +#define DWCMSHC_EMMC_DLL_STRBIN 0x80c +#define DECMSHC_EMMC_DLL_CMDOUT 0x810 +#define DECMSHC_EMMC_MISC_CON 0x81C +#define MISC_INTCLK_EN RT_BIT(1) +#define DWCMSHC_EMMC_DLL_STATUS0 0x840 +#define DWCMSHC_EMMC_DLL_START RT_BIT(0) +#define DWCMSHC_EMMC_DLL_LOCKED RT_BIT(8) +#define DWCMSHC_EMMC_DLL_TIMEOUT RT_BIT(9) +#define DWCMSHC_EMMC_DLL_RXCLK_SRCSEL 29 +#define DWCMSHC_EMMC_DLL_START_POINT 16 +#define DWCMSHC_EMMC_DLL_INC 8 +#define DWCMSHC_EMMC_DLL_BYPASS RT_BIT(24) +#define DWCMSHC_EMMC_DLL_DLYENA RT_BIT(27) +#define DLL_TAP_VALUE_SEL RT_BIT(25) +#define DLL_TAP_VALUE_OFFSET 8 +#define DLL_TXCLK_TAPNUM_DEFAULT 0x10 +#define DLL_TXCLK_TAPNUM_FROM_SW RT_BIT(24) +#define DLL_STRBIN_TAPNUM_FROM_SW RT_BIT(24) +#define DLL_STRBIN_DELAY_NUM_SEL RT_BIT(26) +#define DLL_STRBIN_DELAY_NUM_OFFSET 16 +#define DLL_RXCLK_NO_INVERTER 1 +#define DLL_CMDOUT_TAPNUM_FROM_SW RT_BIT(24) +#define DLL_RXCLK_ORI_GATE RT_BIT(31) +#define DLL_CMDOUT_SRC_CLK_NEG RT_BIT(28) +#define DLL_CMDOUT_BOTH_CLK_EDGE RT_BIT(30) + +#define RK35XX_MAX_CLKS 3 +#define USEC_PER_MSEC 1000L + +#define DLL_LOCK_WO_TMOUT(x) ((((x) & DWCMSHC_EMMC_DLL_LOCKED) == DWCMSHC_EMMC_DLL_LOCKED) && (((x) & DWCMSHC_EMMC_DLL_TIMEOUT) == 0)) + +#define RK_DLL_CMD_OUT RT_BIT(1) +#define RK_RXCLK_NO_INVERTER RT_BIT(2) +#define RK_TAP_VALUE_SEL RT_BIT(3) + +enum sdhci_dwcmshc_rk_soc_type +{ + RK_SOC_TYPE_RK3568, + RK_SOC_TYPE_RK3588, +}; + +struct sdhci_dwcmshc_rk_soc_data +{ + rt_uint32_t flags; + rt_uint8_t hs200_tx_tap; + rt_uint8_t hs400_tx_tap; + rt_uint8_t hs400_cmd_tap; + rt_uint8_t ddr50_strbin_delay_num; + rt_uint8_t hs400_strbin_tap; +}; + +struct sdhci_dwcmshc_rk35xx +{ + struct rt_clk *clks[RK35XX_MAX_CLKS]; + struct rt_reset_control *rstc; + + enum sdhci_dwcmshc_rk_soc_type soc_type; + rt_uint8_t txclk_tapnum; + + const struct sdhci_dwcmshc_rk_soc_data *soc_data; +}; + +static rt_bool_t sdhci_dwcmshc_rk_mux_is_better_rate(rt_ubase_t rate, rt_ubase_t now, rt_ubase_t best) +{ + return now <= rate && now > best; +} + +static rt_err_t sdhci_dwcmshc_rk_mux_identify_rate(struct rt_device *dev, struct rt_clk *clk) +{ + struct rt_clk *clk_750k, *clk_375k; + rt_err_t err; + + clk_750k = rt_clk_get_by_name(dev, "clk_osc0_div_750k"); + if (rt_is_err_or_null(clk_750k)) + { + return rt_is_err(clk_750k) ? rt_ptr_err(clk_750k) : -RT_EINVAL; + } + + err = rt_clk_prepare_enable(clk_750k); + if (err) + { + return err; + } + + err = rt_clk_set_rate(clk_750k, 750000); + if (err) + { + return err; + } + + clk_375k = rt_clk_get_by_name(dev, "clk_osc0_div_375k"); + if (rt_is_err_or_null(clk_375k)) + { + return rt_is_err(clk_375k) ? rt_ptr_err(clk_375k) : -RT_EINVAL; + } + + if (rt_clk_get_rate(clk_375k) == 0) + { + return -RT_EINVAL; + } + + clk->cell->parent = RT_NULL; + err = rt_clk_set_parent(clk, clk_375k); + if (err) + { + return err; + } + + return RT_EOK; +} + +static rt_err_t sdhci_dwcmshc_rk_mux_set_rate(struct rt_device *dev, struct rt_clk *clk, rt_ubase_t rate) +{ + struct rt_clk_cell *cell = clk->cell; + struct rt_clk *best_parent = RT_NULL; + rt_ubase_t best = 0; + rt_bool_t has_candidate = RT_FALSE; + + if (rate <= 400000) + { + return sdhci_dwcmshc_rk_mux_identify_rate(dev, clk); + } + + for (rt_uint8_t i = 0; i < cell->parents_nr; ++i) + { + struct rt_clk_cell *parent_cell = rt_clk_cell_get_parent_by_index(cell, i); + struct rt_clk *parent_clk; + rt_ubase_t parent_rate; + + if (!parent_cell) + { + continue; + } + + parent_clk = rt_clk_cell_get_clk(parent_cell, RT_NULL); + if (!parent_clk) + { + continue; + } + + parent_rate = rt_clk_get_rate(parent_clk); + if (parent_rate == 0) + { + continue; + } + + if (!has_candidate || sdhci_dwcmshc_rk_mux_is_better_rate(rate, parent_rate, best)) + { + best_parent = parent_clk; + best = parent_rate; + has_candidate = RT_TRUE; + } + } + + if (!has_candidate) + { + return -RT_EINVAL; + } + + return rt_clk_set_parent(clk, best_parent); +} + +static rt_err_t sdhci_dwcmshc_rk_set_core_clk_rate(struct rt_device *dev, struct rt_clk *clk, rt_ubase_t rate) +{ + struct rt_clk_cell *cell; + + if (!clk) + { + return -RT_EINVAL; + } + + cell = clk->cell; + + if (cell->ops && !cell->ops->set_rate && cell->parents_nr > 1 && cell->ops->set_parent) + { + return sdhci_dwcmshc_rk_mux_set_rate(dev, clk, rate); + } + + return rt_clk_set_rate(clk, rate); +} + +static void sdhci_dwcmshc_rk3568_set_clock(struct rt_sdhci_host *host, unsigned int clock) +{ + int err; + rt_uint32_t extra, reg, dll_lock_value; + rt_uint8_t txclk_tapnum = DLL_TXCLK_TAPNUM_DEFAULT; + struct rt_sdhci_pltfm_host *pltfm_host = rt_sdhci_priv(host); + struct sdhci_dwcmshc *dwc_priv = rt_sdhci_pltfm_priv(pltfm_host); + struct sdhci_dwcmshc_rk35xx *rk_priv = dwc_priv->vendor_priv; + const struct sdhci_dwcmshc_rk_soc_data *soc_data = rk_priv->soc_data; + + host->mmc->actual_clock = 0; + + if (clock == 0) + { + rt_sdhci_set_clock(host, clock); + return; + } + + if (clock <= 400000) + { + clock = 375000; + } + + if ((err = sdhci_dwcmshc_rk_set_core_clk_rate(rt_mmc_dev(host->mmc), pltfm_host->clk, clock))) + { + LOG_E("Fail to set clock %d", clock); + } + + if (pltfm_host->clk) + { + rt_ubase_t core_rate = rt_clk_get_rate(pltfm_host->clk); + + if (core_rate) + { + host->max_clk = core_rate; + } + } + + rt_sdhci_set_clock(host, clock); + + reg = dwc_priv->vendor_specific_area1 + DWCMSHC_HOST_CTRL3; + extra = rt_sdhci_readl(host, reg); + extra &= ~RT_BIT(0); + rt_sdhci_writel(host, extra, reg); + + rt_sdhci_writew(host, 0, RT_SDHCI_CLOCK_CONTROL); + + if (clock <= 52000000) + { + rt_sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_CTRL); + rt_sdhci_writel(host, DWCMSHC_EMMC_DLL_BYPASS | DWCMSHC_EMMC_DLL_START, DWCMSHC_EMMC_DLL_CTRL); + rt_sdhci_writel(host, DLL_RXCLK_ORI_GATE, DWCMSHC_EMMC_DLL_RXCLK); + rt_sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_TXCLK); + rt_sdhci_writel(host, 0, DECMSHC_EMMC_DLL_CMDOUT); + extra = DWCMSHC_EMMC_DLL_DLYENA | + DLL_STRBIN_DELAY_NUM_SEL | + soc_data->ddr50_strbin_delay_num << DLL_STRBIN_DELAY_NUM_OFFSET; + rt_sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_STRBIN); + goto _exit; + } + + rt_sdhci_writel(host, RT_BIT(1), DWCMSHC_EMMC_DLL_CTRL); + rt_hw_us_delay(1); + rt_sdhci_writel(host, 0x0, DWCMSHC_EMMC_DLL_CTRL); + + extra = 0x5 << DWCMSHC_EMMC_DLL_START_POINT | + 0x2 << DWCMSHC_EMMC_DLL_INC | + DWCMSHC_EMMC_DLL_START; + rt_sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_CTRL); + err = readl_poll_timeout(host->ioaddr + DWCMSHC_EMMC_DLL_STATUS0, + extra, DLL_LOCK_WO_TMOUT(extra), 1, 500 * USEC_PER_MSEC); + if (err) + { + LOG_E("DLL lock timeout"); + goto _exit; + } + + dll_lock_value = ((rt_sdhci_readl(host, DWCMSHC_EMMC_DLL_STATUS0) & 0xff) * 2) & 0xff; + + extra = 0x1 << 16 | + 0x3 << 17 | + 0x3 << 19; + rt_sdhci_writel(host, extra, dwc_priv->vendor_specific_area1 + DWCMSHC_EMMC_ATCTRL); + + extra = DWCMSHC_EMMC_DLL_DLYENA | DLL_RXCLK_ORI_GATE; + if (soc_data->flags & RK_RXCLK_NO_INVERTER) + { + extra |= DLL_RXCLK_NO_INVERTER << DWCMSHC_EMMC_DLL_RXCLK_SRCSEL; + } + if (soc_data->flags & RK_TAP_VALUE_SEL) + { + extra |= DLL_TAP_VALUE_SEL | dll_lock_value << DLL_TAP_VALUE_OFFSET; + } + rt_sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_RXCLK); + + txclk_tapnum = soc_data->hs200_tx_tap; + if (host->mmc->ios.timing == MMC_TIMING_MMC_HS400) + { + txclk_tapnum = soc_data->hs400_tx_tap; + + if (soc_data->flags & RK_DLL_CMD_OUT) + { + extra = DLL_CMDOUT_SRC_CLK_NEG | + DLL_CMDOUT_BOTH_CLK_EDGE | + DWCMSHC_EMMC_DLL_DLYENA | + soc_data->hs400_cmd_tap | + DLL_CMDOUT_TAPNUM_FROM_SW; + if (soc_data->flags & RK_TAP_VALUE_SEL) + { + extra |= DLL_TAP_VALUE_SEL | dll_lock_value << DLL_TAP_VALUE_OFFSET; + } + rt_sdhci_writel(host, extra, DECMSHC_EMMC_DLL_CMDOUT); + } + } + extra = DWCMSHC_EMMC_DLL_DLYENA | + DLL_TXCLK_TAPNUM_FROM_SW | + DLL_RXCLK_NO_INVERTER << DWCMSHC_EMMC_DLL_RXCLK_SRCSEL | + txclk_tapnum; + if (soc_data->flags & RK_TAP_VALUE_SEL) + { + extra |= DLL_TAP_VALUE_SEL | dll_lock_value << DLL_TAP_VALUE_OFFSET; + } + rt_sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_TXCLK); + + extra = DWCMSHC_EMMC_DLL_DLYENA | + soc_data->hs400_strbin_tap | + DLL_STRBIN_TAPNUM_FROM_SW; + if (soc_data->flags & RK_TAP_VALUE_SEL) + { + extra |= DLL_TAP_VALUE_SEL | dll_lock_value << DLL_TAP_VALUE_OFFSET; + } + rt_sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_STRBIN); + +_exit: + rt_sdhci_clk_enable(host, 0); + host->mmc->actual_clock = clock; +} + +static unsigned int sdhci_dwcmshc_rk35xx_get_min_clock(struct rt_sdhci_host *host) +{ + return 375000; +} + +static void sdhci_dwcmshc_rk35xx_reset(struct rt_sdhci_host *host, rt_uint8_t mask) +{ + rt_uint32_t extra; + struct rt_sdhci_pltfm_host *pltfm_host = rt_sdhci_priv(host); + struct sdhci_dwcmshc *dwc_priv = rt_sdhci_pltfm_priv(pltfm_host); + struct sdhci_dwcmshc_rk35xx *rk_priv = dwc_priv->vendor_priv; + + extra = rt_sdhci_readl(host, DECMSHC_EMMC_MISC_CON); + + if (mask & RT_SDHCI_RESET_ALL && rk_priv->rstc) + { + rt_reset_control_assert(rk_priv->rstc); + rt_hw_us_delay(1); + rt_reset_control_deassert(rk_priv->rstc); + } + + rt_sdhci_reset(host, mask); + + rt_sdhci_writel(host, MISC_INTCLK_EN | extra, DECMSHC_EMMC_MISC_CON); +} + +static const struct rt_sdhci_ops sdhci_dwcmshc_rk35xx_ops = +{ + .set_clock = sdhci_dwcmshc_rk3568_set_clock, + .set_bus_width = rt_sdhci_set_bus_width, + .set_uhs_signaling = sdhci_dwcmshc_set_uhs_signaling, + .get_max_clock = rt_sdhci_pltfm_clk_get_max_clock, + .get_min_clock = sdhci_dwcmshc_rk35xx_get_min_clock, + .reset = sdhci_dwcmshc_rk35xx_reset, +}; + +static const struct rt_sdhci_pltfm_data sdhci_dwcmshc_rk35xx_pdata = +{ + .ops = &sdhci_dwcmshc_rk35xx_ops, + .quirks = RT_SDHCI_QUIRK_BROKEN_TIMEOUT_VAL, + .quirks2 = RT_SDHCI_QUIRK2_PRESET_VALUE_BROKEN | + RT_SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN, +}; + +static rt_err_t sdhci_dwcmshc_rk35xx_init(struct rt_sdhci_host *host, struct sdhci_dwcmshc *priv) +{ + int err; + struct sdhci_dwcmshc_rk35xx *rk_priv; + struct rt_device *dev = rt_mmc_dev(host->mmc); + const struct sdhci_dwcmshc_drv_data *drv_data = priv->drv_data; + + rk_priv = rt_calloc(1, sizeof(*rk_priv)); + if (!rk_priv) + { + return -RT_ENOMEM; + } + + rk_priv->soc_data = drv_data->vendor_priv; + priv->vendor_priv = rk_priv; + + if (rt_ofw_node_is_compatible(dev->ofw_node, "rockchip,rk3588-dwcmshc")) + { + rk_priv->soc_type = RK_SOC_TYPE_RK3588; + } + else + { + rk_priv->soc_type = RK_SOC_TYPE_RK3568; + } + + rk_priv->rstc = rt_reset_control_get_array(dev); + + if (rt_is_err(rk_priv->rstc)) + { + err = rt_ptr_err(rk_priv->rstc); + LOG_E("Failed to get reset control %s", rt_strerror(err)); + goto _err; + } + + rk_priv->clks[0] = rt_clk_get_by_name(dev, "axi"); + rk_priv->clks[1] = rt_clk_get_by_name(dev, "block"); + rk_priv->clks[2] = rt_clk_get_by_name(dev, "timer"); + + if (rt_is_err(rk_priv->clks[0])) + { + err = rt_ptr_err(rk_priv->clks[0]); + LOG_E("Failed to get clocks %s", rt_strerror(err)); + goto _err; + } + + if (rt_is_err(rk_priv->clks[1])) + { + err = rt_ptr_err(rk_priv->clks[1]); + LOG_E("Failed to get clocks %s", rt_strerror(err)); + goto _err; + } + + if (rt_is_err(rk_priv->clks[2])) + { + err = rt_ptr_err(rk_priv->clks[2]); + LOG_E("Failed to get clocks %s", rt_strerror(err)); + goto _err; + } + + err = rt_clk_prepare_enable(rk_priv->clks[0]); + if (err) + { + LOG_E("Failed to enable %s clocks %s", "axi", rt_strerror(err)); + goto _err; + } + + err = rt_clk_prepare_enable(rk_priv->clks[1]); + if (err) + { + LOG_E("Failed to enable %s clocks %s", "block", rt_strerror(err)); + goto _err; + } + + err = rt_clk_prepare_enable(rk_priv->clks[2]); + if (err) + { + LOG_E("Failed to enable %s clocks %s", "timer", rt_strerror(err)); + goto _err; + } + + rt_clk_set_rate(rk_priv->clks[1], 200000000); + rt_clk_set_rate(rk_priv->clks[2], 24000000); + + if (rt_dm_dev_prop_read_u8(dev, "rockchip,txclk-tapnum", &rk_priv->txclk_tapnum)) + { + rk_priv->txclk_tapnum = DLL_TXCLK_TAPNUM_DEFAULT; + } + + rt_sdhci_writel(host, 0x0, priv->vendor_specific_area1 + DWCMSHC_HOST_CTRL3); + rt_sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_TXCLK); + rt_sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_STRBIN); + + return RT_EOK; + +_err: + rt_free(rk_priv); + priv->vendor_priv = RT_NULL; + + return err; +} + +static void sdhci_dwcmshc_rk35xx_postinit(struct rt_sdhci_host *host, struct sdhci_dwcmshc *priv) +{ + struct rt_mmc_host *mmc = host->mmc; + + RT_UNUSED(priv); + + if (rt_is_err_or_null(mmc->rthost.supply.vqmmc)) + { + host->quirks2 |= RT_SDHCI_QUIRK2_NO_1_8_V; + host->caps1 &= ~(RT_SDHCI_SUPPORT_SDR104 | RT_SDHCI_SUPPORT_SDR50 | + RT_SDHCI_SUPPORT_DDR50); + mmc->caps2 &= ~(MMC_CAP2_HS200 | MMC_CAP2_HS400 | MMC_CAP2_HSX00_1_8V | + MMC_CAP2_HS400_ES); + mmc->caps &= ~(MMC_CAP_1_8V_DDR | MMC_CAP_UHS); + } + + if (mmc->f_max <= 52000000) + { + mmc->caps2 &= ~(MMC_CAP2_HS200 | MMC_CAP2_HS400); + mmc->caps &= ~(MMC_CAP_3_3V_DDR | MMC_CAP_1_8V_DDR); + } +} + +static void sdhci_dwcmshc_rk35xx_remove(struct rt_sdhci_host *host, struct sdhci_dwcmshc *priv) +{ + struct sdhci_dwcmshc_rk35xx *rk_priv = priv->vendor_priv; + + RT_UNUSED(host); + + if (!rk_priv) + { + return; + } + + rt_clk_disable_unprepare(rk_priv->clks[2]); + rt_clk_disable_unprepare(rk_priv->clks[1]); + rt_clk_disable_unprepare(rk_priv->clks[0]); + rt_free(rk_priv); + priv->vendor_priv = RT_NULL; +} + +static const struct sdhci_dwcmshc_rk_soc_data sdhci_dwcmshc_rk3528_soc_data = +{ + .flags = RK_DLL_CMD_OUT | RK_TAP_VALUE_SEL, + .hs200_tx_tap = 12, + .hs400_tx_tap = 6, + .hs400_cmd_tap = 6, + .hs400_strbin_tap = 3, + .ddr50_strbin_delay_num = 10, +}; + +static const struct sdhci_dwcmshc_rk_soc_data sdhci_dwcmshc_rk3562_soc_data = +{ + .flags = RK_DLL_CMD_OUT | RK_TAP_VALUE_SEL, + .hs200_tx_tap = 12, + .hs400_tx_tap = 6, + .hs400_cmd_tap = 6, + .hs400_strbin_tap = 3, + .ddr50_strbin_delay_num = 10, +}; + +static const struct sdhci_dwcmshc_rk_soc_data sdhci_dwcmshc_rk3568_soc_data = +{ + .flags = RK_RXCLK_NO_INVERTER | RK_TAP_VALUE_SEL, + .hs200_tx_tap = 16, + .hs400_tx_tap = 8, + .hs400_cmd_tap = 8, + .hs400_strbin_tap = 4, + .ddr50_strbin_delay_num = 16, +}; + +static const struct sdhci_dwcmshc_rk_soc_data sdhci_dwcmshc_rk3576_soc_data = +{ + .flags = RK_DLL_CMD_OUT | RK_TAP_VALUE_SEL, + .hs200_tx_tap = 16, + .hs400_tx_tap = 7, + .hs400_cmd_tap = 7, + .hs400_strbin_tap = 5, + .ddr50_strbin_delay_num = 10, +}; + +static const struct sdhci_dwcmshc_rk_soc_data sdhci_dwcmshc_rk3588_soc_data = +{ + .flags = RK_DLL_CMD_OUT | RK_TAP_VALUE_SEL, + .hs200_tx_tap = 16, + .hs400_tx_tap = 9, + .hs400_cmd_tap = 8, + .hs400_strbin_tap = 4, + .ddr50_strbin_delay_num = 16, +}; + +#define SDHCI_DWCMSHC_RK_DRV_DATA(_soc) \ +{ \ + .pdata = &sdhci_dwcmshc_rk35xx_pdata, \ + .init = sdhci_dwcmshc_rk35xx_init, \ + .postinit = sdhci_dwcmshc_rk35xx_postinit, \ + .remove = sdhci_dwcmshc_rk35xx_remove, \ + .vendor_priv = (void *)&sdhci_dwcmshc_##_soc##_soc_data, \ +} + +static const struct sdhci_dwcmshc_drv_data sdhci_dwcmshc_rk3528_drv_data = + SDHCI_DWCMSHC_RK_DRV_DATA(rk3528); +static const struct sdhci_dwcmshc_drv_data sdhci_dwcmshc_rk3562_drv_data = + SDHCI_DWCMSHC_RK_DRV_DATA(rk3562); +static const struct sdhci_dwcmshc_drv_data sdhci_dwcmshc_rk3568_drv_data = + SDHCI_DWCMSHC_RK_DRV_DATA(rk3568); +static const struct sdhci_dwcmshc_drv_data sdhci_dwcmshc_rk3576_drv_data = + SDHCI_DWCMSHC_RK_DRV_DATA(rk3576); +static const struct sdhci_dwcmshc_drv_data sdhci_dwcmshc_rk3588_drv_data = + SDHCI_DWCMSHC_RK_DRV_DATA(rk3588); + +static rt_err_t sdhci_dwcmshc_rockchip_probe(struct rt_platform_device *pdev) +{ + const struct sdhci_dwcmshc_drv_data *drv_data = pdev->id->data; + + return sdhci_dwcmshc_platform_register(pdev, drv_data); +} + +static rt_err_t sdhci_dwcmshc_rockchip_remove(struct rt_platform_device *pdev) +{ + return sdhci_dwcmshc_remove(pdev); +} + +static const struct rt_ofw_node_id sdhci_dwcmshc_rockchip_ofw_ids[] = +{ + { .compatible = "rockchip,rk3588-dwcmshc", .data = &sdhci_dwcmshc_rk3588_drv_data, }, + { .compatible = "rockchip,rk3576-dwcmshc", .data = &sdhci_dwcmshc_rk3576_drv_data, }, + { .compatible = "rockchip,rk3568-dwcmshc", .data = &sdhci_dwcmshc_rk3568_drv_data, }, + { .compatible = "rockchip,rk3528-dwcmshc", .data = &sdhci_dwcmshc_rk3528_drv_data, }, + { .compatible = "rockchip,rk3562-dwcmshc", .data = &sdhci_dwcmshc_rk3562_drv_data, }, + { /* sentinel */ } +}; + +static struct rt_platform_driver sdhci_dwcmshc_rockchip_driver = +{ + .name = "sdhci-dwcmshc-rockchip", + .ids = sdhci_dwcmshc_rockchip_ofw_ids, + + .probe = sdhci_dwcmshc_rockchip_probe, + .remove = sdhci_dwcmshc_rockchip_remove, +}; +RT_PLATFORM_DRIVER_EXPORT(sdhci_dwcmshc_rockchip_driver); diff --git a/bsp/rockchip/dm/soc/Kconfig b/bsp/rockchip/dm/soc/Kconfig index 29229f874226..9d341e03f65c 100755 --- a/bsp/rockchip/dm/soc/Kconfig +++ b/bsp/rockchip/dm/soc/Kconfig @@ -12,6 +12,15 @@ config RT_SOC_ROCKCHIP_HW_DECOMPRESS bool "HardWare Decompress (LZ4, GZIP, ZLIB)" default n +config RT_ROCKCHIP_JPEG_DEC + bool "JPEG decoder" + default n + +config RT_ROCKCHIP_RGA2 + bool "RGA2 graphics accelerator" + depends on RT_USING_OFW + default n + config RT_SOC_ROCKCHIP_IODOMAIN bool "IO domain support" depends on RT_MFD_SYSCON diff --git a/bsp/rockchip/dm/soc/SConscript b/bsp/rockchip/dm/soc/SConscript index 59dfb3e198b8..d4ae333d84a3 100755 --- a/bsp/rockchip/dm/soc/SConscript +++ b/bsp/rockchip/dm/soc/SConscript @@ -14,6 +14,9 @@ if GetDepend(['RT_SOC_ROCKCHIP_GRF']): if GetDepend(['RT_SOC_ROCKCHIP_HW_DECOMPRESS']): src += ['hw-decompress.c'] +if GetDepend(['RT_ROCKCHIP_JPEG_DEC']): + src += ['jpegd.c'] + if GetDepend(['RT_SOC_ROCKCHIP_IODOMAIN']): src += ['io-domain.c'] @@ -22,4 +25,10 @@ if GetDepend(['RT_DVFS_ROCKCHIP_CPUFREQ']): group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) +if GetDepend(['RT_ROCKCHIP_RGA2']): + group += SConscript('rga2/SConscript') + +if GetDepend(['RT_ROCKCHIP_RKNPU']): + group += SConscript('npu/SConscript') + Return('group') diff --git a/bsp/rockchip/dm/soc/io-domain.c b/bsp/rockchip/dm/soc/io-domain.c index 67176535166d..061ef32e606d 100755 --- a/bsp/rockchip/dm/soc/io-domain.c +++ b/bsp/rockchip/dm/soc/io-domain.c @@ -587,6 +587,18 @@ static rt_err_t rockchip_iodomain_probe(struct rt_platform_device *pdev) if (!reg) { + char prop_name[64]; + rt_phandle phandle; + + rt_snprintf(prop_name, sizeof(prop_name), "%s-supply", supply_name); + if (!rt_ofw_prop_read_u32(np, prop_name, &phandle)) + { + /* The referenced provider is registered later (for example, + * an I2C PMIC). Keep this device unbound so it can be retried. */ + err = -RT_EBUSY; + goto _fail; + } + continue; } @@ -695,4 +707,5 @@ static int rockchip_iodomain_register(void) return 0; } -INIT_PREV_EXPORT(rockchip_iodomain_register); +/* PMIC-backed regulators are registered at INIT_DEVICE (level 3). */ +INIT_EXPORT(rockchip_iodomain_register, "3.9"); diff --git a/bsp/rockchip/dm/soc/jpegd.c b/bsp/rockchip/dm/soc/jpegd.c new file mode 100644 index 000000000000..4ef8194933ad --- /dev/null +++ b/bsp/rockchip/dm/soc/jpegd.c @@ -0,0 +1,412 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-11-21 GuEe-GUI first version + */ + +#include +#include +#include + +#define DBG_TAG "soc.rockchip.jpegd" +#define DBG_LVL DBG_INFO +#include + +#include +#include + +#ifdef RT_USING_IOMMU +#include +#endif + +#define JPGDEC_REG_NUM JPEGD_REG_NUM +#define JPGDEC_REG_INT_EN_INDEX 1 +#define JPGDEC_REG_SYS_INDEX 2 + +#define JPGDEC_FORCE_SOFTRESET_VALID RT_BIT(17) + +#define JPGDEC_SOFT_RSET_READY RT_BIT(14) +#define JPGDEC_BUF_EMPTY_STA RT_BIT(13) +#define JPGDEC_TIMEOUT_STA RT_BIT(12) +#define JPGDEC_ERROR_STA RT_BIT(11) +#define JPGDEC_BUS_STA RT_BIT(10) +#define JPGDEC_IRQ_RAW RT_BIT(6) +#define JPGDEC_SOFT_REST_EN RT_BIT(5) +#define JPGDEC_START_EN RT_BIT(0) + +#define JPGDEC_ERROR_MASK (JPGDEC_BUS_STA | JPGDEC_ERROR_STA | JPGDEC_TIMEOUT_STA | JPGDEC_BUF_EMPTY_STA) + +#define JPGDEC_TIMEOUT_MS 500 + +struct rockchip_jpegd +{ + struct rt_device parent; + + struct rt_device *dev; + void *regs; + int irq; + + struct rt_clk_array *clk_arr; + struct rt_reset_control *rst_a; + struct rt_reset_control *rst_h; + + rt_uint32_t hw_id; + rt_uint32_t irq_status; + rt_err_t error; + rt_bool_t done; + struct rt_mutex lock; +}; + +#define raw_to_rockchip_jpegd(raw) rt_container_of(raw, struct rockchip_jpegd, parent) + +rt_inline rt_uint32_t rockchip_jpegd_read(struct rockchip_jpegd *jpegd, int index) +{ + return HWREG32(jpegd->regs + index * sizeof(rt_uint32_t)); +} + +rt_inline void rockchip_jpegd_write(struct rockchip_jpegd *jpegd, int index, rt_uint32_t val) +{ + HWREG32(jpegd->regs + index * sizeof(rt_uint32_t)) = val; +} + +static rt_err_t rockchip_jpegd_soft_reset(struct rockchip_jpegd *jpegd) +{ + rt_uint32_t int_status = rockchip_jpegd_read(jpegd, JPGDEC_REG_INT_EN_INDEX); + rt_uint32_t dec_en = int_status & JPGDEC_START_EN; + int timeout = 1000; + + if (!dec_en) + { + rockchip_jpegd_write(jpegd, JPGDEC_REG_SYS_INDEX, JPGDEC_FORCE_SOFTRESET_VALID); + } + + rockchip_jpegd_write(jpegd, JPGDEC_REG_INT_EN_INDEX, int_status | JPGDEC_SOFT_REST_EN); + + while (timeout-- > 0) + { + int_status = rockchip_jpegd_read(jpegd, JPGDEC_REG_INT_EN_INDEX); + if (int_status & JPGDEC_SOFT_RSET_READY) + { + return RT_EOK; + } + + rt_hw_us_delay(1); + } + + LOG_E("soft reset timeout"); + + return -RT_ETIMEOUT; +} + +static void rockchip_jpegd_hard_reset(struct rockchip_jpegd *jpegd) +{ + if (jpegd->rst_a && jpegd->rst_h) + { + rt_reset_control_assert(jpegd->rst_a); + rt_reset_control_assert(jpegd->rst_h); + rt_hw_us_delay(5); + rt_reset_control_deassert(jpegd->rst_a); + rt_reset_control_deassert(jpegd->rst_h); + } + + rockchip_jpegd_write(jpegd, JPGDEC_REG_INT_EN_INDEX, 0); +} + +static rt_err_t rockchip_jpegd_submit(struct rockchip_jpegd *jpegd, struct jpegd_req *req) +{ + int i; + rt_uint32_t int_status; + rt_tick_t deadline = rt_tick_get() + rt_tick_from_millisecond(JPGDEC_TIMEOUT_MS); + + int_status = rockchip_jpegd_read(jpegd, JPGDEC_REG_INT_EN_INDEX); + if (int_status & JPGDEC_START_EN) + { + LOG_E("JPEG decoder busy"); + return -RT_EBUSY; + } + + if (rockchip_jpegd_soft_reset(jpegd) != RT_EOK) + { + rockchip_jpegd_hard_reset(jpegd); + } + + for (i = 0; i < JPGDEC_REG_NUM; ++i) + { + if (i != JPGDEC_REG_INT_EN_INDEX) + { + rockchip_jpegd_write(jpegd, i, req->reg[i]); + } + } + +#ifdef RT_USING_IOMMU + if (jpegd->dev->iommu_domain) + { + rt_iommu_iotlb_flush(jpegd->dev); + } +#endif + + rt_hw_dsb(); + + jpegd->done = RT_FALSE; + jpegd->error = RT_EOK; + jpegd->irq_status = 0; + + rockchip_jpegd_write(jpegd, JPGDEC_REG_INT_EN_INDEX, + req->reg[JPGDEC_REG_INT_EN_INDEX] | JPGDEC_START_EN); + + while (!jpegd->done && rt_tick_get() < deadline) + { + rt_hw_cpu_relax(); + } + + if (!jpegd->done) + { + LOG_E("JPEG decode timeout"); + rockchip_jpegd_hard_reset(jpegd); + return -RT_ETIMEOUT; + } + + req->irq_status = jpegd->irq_status; + + for (i = 0; i < JPGDEC_REG_NUM; ++i) + { + req->reg[i] = rockchip_jpegd_read(jpegd, i); + } + + if (jpegd->error != RT_EOK) + { + if (rockchip_jpegd_soft_reset(jpegd) != RT_EOK) + { + rockchip_jpegd_hard_reset(jpegd); + } + } + + return jpegd->error; +} + +static rt_err_t rockchip_jpegd_control(rt_device_t dev, int cmd, void *args) +{ + rt_err_t err = RT_EOK; + struct rockchip_jpegd *jpegd = raw_to_rockchip_jpegd(dev); + + rt_mutex_take(&jpegd->lock, RT_WAITING_FOREVER); + + switch (cmd) + { + case JPEGD_RUN: + { + struct jpegd_req *req = args; + + if (!req) + { + err = -RT_EINVAL; + break; + } + + err = rockchip_jpegd_submit(jpegd, req); + break; + } + case JPEGD_GET_HW_ID: + { + rt_uint32_t *hw_id = args; + + if (!hw_id) + { + err = -RT_EINVAL; + break; + } + + *hw_id = jpegd->hw_id; + break; + } + default: + err = -RT_ENOSYS; + break; + } + + rt_mutex_release(&jpegd->lock); + + return err; +} + +#ifdef RT_USING_DEVICE_OPS +static const struct rt_device_ops rockchip_jpegd_ops = +{ + .control = rockchip_jpegd_control, +}; +#endif + +static void rockchip_jpegd_isr(int irqno, void *param) +{ + rt_uint32_t irq_status; + struct rockchip_jpegd *jpegd = param; + + irq_status = rockchip_jpegd_read(jpegd, JPGDEC_REG_INT_EN_INDEX); + + if (!(irq_status & JPGDEC_IRQ_RAW)) + { + return; + } + + rockchip_jpegd_write(jpegd, JPGDEC_REG_INT_EN_INDEX, 0); + + jpegd->irq_status = irq_status; + + if (irq_status & JPGDEC_ERROR_MASK) + { + LOG_E("JPEG decode error, irq_status = 0x%08x", irq_status); + jpegd->error = -RT_EIO; + } + + jpegd->done = RT_TRUE; +} + +static void rockchip_jpegd_free(struct rockchip_jpegd *jpegd) +{ + if (jpegd->regs) + { + rt_iounmap(jpegd->regs); + } + + if (!rt_is_err_or_null(jpegd->clk_arr)) + { + rt_clk_array_disable_unprepare(jpegd->clk_arr); + rt_clk_array_put(jpegd->clk_arr); + } + + if (!rt_is_err_or_null(jpegd->rst_a)) + { + rt_reset_control_put(jpegd->rst_a); + } + + if (!rt_is_err_or_null(jpegd->rst_h)) + { + rt_reset_control_put(jpegd->rst_h); + } + + rt_free(jpegd); +} + +static rt_err_t rockchip_jpegd_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + const char *dev_name; + struct rt_device *dev = &pdev->parent; + struct rockchip_jpegd *jpegd = rt_calloc(1, sizeof(*jpegd)); + + if (!jpegd) + { + return -RT_ENOMEM; + } + + jpegd->dev = dev; + + jpegd->regs = rt_dm_dev_iomap(dev, 0); + if (!jpegd->regs) + { + err = -RT_EIO; + goto _fail; + } + + jpegd->clk_arr = rt_clk_get_array(dev); + if (rt_is_err(jpegd->clk_arr)) + { + err = rt_ptr_err(jpegd->clk_arr); + goto _fail; + } + + if ((err = rt_clk_array_prepare_enable(jpegd->clk_arr))) + { + goto _fail; + } + + jpegd->rst_a = rt_reset_control_get_by_name(dev, "video_a"); + if (rt_is_err(jpegd->rst_a)) + { + LOG_W("no video_a reset, err = %d", rt_ptr_err(jpegd->rst_a)); + jpegd->rst_a = RT_NULL; + } + + jpegd->rst_h = rt_reset_control_get_by_name(dev, "video_h"); + if (rt_is_err(jpegd->rst_h)) + { + LOG_W("no video_h reset, err = %d", rt_ptr_err(jpegd->rst_h)); + jpegd->rst_h = RT_NULL; + } + + jpegd->irq = rt_dm_dev_get_irq(dev, 0); + if (jpegd->irq < 0) + { + err = jpegd->irq; + goto _fail; + } + + jpegd->hw_id = rockchip_jpegd_read(jpegd, 0); + LOG_D("Hardware ID = 0x%08x", jpegd->hw_id); + + dev->user_data = jpegd; + + rt_dm_dev_set_name_auto(&jpegd->parent, "jpegd"); + dev_name = rt_dm_dev_get_name(&jpegd->parent); + + jpegd->parent.type = RT_Device_Class_Char; + /* Let clients allocate buffers in the JPEG decoder's DMA/IOMMU domain. */ + jpegd->parent.bus = dev->bus; + jpegd->parent.ofw_node = dev->ofw_node; +#ifdef RT_USING_DEVICE_OPS + jpegd->parent.ops = &rockchip_jpegd_ops; +#else + jpegd->parent.control = rockchip_jpegd_control; +#endif + + if ((err = rt_device_register(&jpegd->parent, dev_name, RT_DEVICE_FLAG_DEACTIVATE))) + { + goto _fail; + } + + rt_mutex_init(&jpegd->lock, dev_name, RT_IPC_FLAG_PRIO); + + rt_hw_interrupt_install(jpegd->irq, rockchip_jpegd_isr, jpegd, "jpegd"); + rt_hw_interrupt_umask(jpegd->irq); + + return RT_EOK; + +_fail: + rockchip_jpegd_free(jpegd); + + return err; +} + +static rt_err_t rockchip_jpegd_remove(struct rt_platform_device *pdev) +{ + struct rockchip_jpegd *jpegd = pdev->parent.user_data; + + rt_hw_interrupt_mask(jpegd->irq); + rt_pic_detach_irq(jpegd->irq, jpegd); + + rt_device_unregister(&jpegd->parent); + + rockchip_jpegd_free(jpegd); + + return RT_EOK; +} + +static const struct rt_ofw_node_id rockchip_jpegd_ofw_ids[] = +{ + { .compatible = "rockchip,rkv-jpeg-decoder-v1" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver rockchip_jpegd_driver = +{ + .name = "rockchip-jpegd", + .ids = rockchip_jpegd_ofw_ids, + + .probe = rockchip_jpegd_probe, + .remove = rockchip_jpegd_remove, +}; +RT_PLATFORM_DRIVER_EXPORT(rockchip_jpegd_driver); diff --git a/bsp/rockchip/dm/soc/rga2/SConscript b/bsp/rockchip/dm/soc/rga2/SConscript new file mode 100644 index 000000000000..4e8f54659556 --- /dev/null +++ b/bsp/rockchip/dm/soc/rga2/SConscript @@ -0,0 +1,10 @@ +from building import * + +cwd = GetCurrentDir() +src = ['rga2_drv.c', 'rga2_hw.c'] +CPPPATH = [cwd, cwd + '/../../include'] + +group = DefineGroup('DeviceDrivers', src, depend = ['RT_ROCKCHIP_RGA2'], + CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/rockchip/dm/soc/rga2/rga2_drv.c b/bsp/rockchip/dm/soc/rga2/rga2_drv.c new file mode 100644 index 000000000000..594e6429b409 --- /dev/null +++ b/bsp/rockchip/dm/soc/rga2/rga2_drv.c @@ -0,0 +1,498 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-11-21 GuEe-GUI first version + */ + +#include +#include +#include + +#define DBG_TAG "soc.rockchip.rga2" +#define DBG_LVL DBG_INFO +#include + +#include "rga2_internal.h" +#include "rga2_reg.h" + +#define RGA2_TIMEOUT_MS 500 +#define RGA2_MAX_WIDTH 8192 +#define RGA2_MAX_HEIGHT 8192 +#define RGA2_MAX_OUTPUT 4096 + +struct rockchip_rga2_buffer +{ + rt_list_t list; + struct rga2_buffer buffer; +}; + +struct rockchip_rga2 +{ + struct rt_device parent; + struct rt_device *dev; + void *regs; + int irq; + struct rt_clk_array *clocks; + + struct rt_mutex lock; + struct rt_completion completion; + rt_list_t buffers; + rt_uint32_t version; + rt_uint32_t irq_status; + rt_err_t error; + rt_bool_t clocks_enabled; + rt_bool_t lock_initialized; + rt_bool_t device_registered; +}; + +#define raw_to_rockchip_rga2(raw) \ + rt_container_of(raw, struct rockchip_rga2, parent) + +static rt_uint32_t rga2_read(struct rockchip_rga2 *rga2, rt_uint32_t offset) +{ + return HWREG32(rga2->regs + offset); +} + +static void rga2_write(struct rockchip_rga2 *rga2, rt_uint32_t offset, + rt_uint32_t value) +{ + HWREG32(rga2->regs + offset) = value; +} + +static void rockchip_rga2_reset(struct rockchip_rga2 *rga2) +{ + int timeout = 1000; + + rga2_write(rga2, RGA2_INT, RGA2_INT_CLEAR_MASK); + rga2_write(rga2, RGA2_SYS_CTRL, + RGA2_SYS_SOFT_RESET | RGA2_SYS_RESET_PROTECT); + while ((rga2_read(rga2, RGA2_SYS_CTRL) & RGA2_SYS_START) && timeout--) + { + rt_hw_us_delay(1); + } + if (timeout < 0) + { + LOG_E("soft reset timeout"); + } +} + +static int rga2_format_bpp(rt_uint16_t format) +{ + switch (format) + { + case RGA2_FORMAT_RGBA8888: + case RGA2_FORMAT_BGRA8888: + case RGA2_FORMAT_RGBX8888: + case RGA2_FORMAT_BGRX8888: + return 4; + case RGA2_FORMAT_RGB888: + case RGA2_FORMAT_BGR888: + return 3; + case RGA2_FORMAT_RGB565: + case RGA2_FORMAT_BGR565: + return 2; + default: + return 0; + } +} + +static rt_bool_t rga2_range_allocated(struct rockchip_rga2 *rga2, + rt_uint64_t address, rt_uint64_t size) +{ + struct rockchip_rga2_buffer *entry; + + if (!address || !size || address > UINT32_MAX || + size - 1 > UINT32_MAX - address) + { + return RT_FALSE; + } + + rt_list_for_each_entry(entry, &rga2->buffers, list) + { + rt_uint64_t start = entry->buffer.phys_addr; + + if (address >= start && address + size <= start + entry->buffer.size) + { + return RT_TRUE; + } + } + + return RT_FALSE; +} + +static rt_err_t rga2_validate_image(struct rockchip_rga2 *rga2, + const struct rga2_image *image) +{ + const struct rga2_rect *rect = &image->rect; + rt_uint64_t size; + int bpp = rga2_format_bpp(image->format); + + if (!bpp || !image->width || !image->height || + image->width > RGA2_MAX_WIDTH || image->height > RGA2_MAX_HEIGHT || + image->stride < image->width * bpp || (image->stride & 3) || + !rect->width || !rect->height || rect->x >= image->width || + rect->y >= image->height || rect->width > image->width - rect->x || + rect->height > image->height - rect->y) + { + return -RT_EINVAL; + } + + size = (rt_uint64_t)(image->height - 1) * image->stride + + (rt_uint64_t)image->width * bpp; + return rga2_range_allocated(rga2, image->address, size) ? + RT_EOK : -RT_EINVAL; +} + +static rt_err_t rga2_validate_request(struct rockchip_rga2 *rga2, + const struct rga2_req *req) +{ + rt_err_t err; + + if (!req || req->rotate > RGA2_ROTATE_270 || req->mirror > 3 || + (req->render_mode != RGA2_MODE_BITBLT && + req->render_mode != RGA2_MODE_COLOR_FILL)) + { + return -RT_EINVAL; + } + + if ((err = rga2_validate_image(rga2, &req->dst)) != RT_EOK) + { + return err; + } + if (req->dst.rect.width > RGA2_MAX_OUTPUT || + req->dst.rect.height > RGA2_MAX_OUTPUT) + { + return -RT_EINVAL; + } + if (req->render_mode == RGA2_MODE_COLOR_FILL) + { + return RT_EOK; + } + if ((err = rga2_validate_image(rga2, &req->src)) != RT_EOK) + { + return err; + } + + if (req->src.rect.width > + ((req->rotate & 1) ? req->dst.rect.height : req->dst.rect.width) * 16U || + ((req->rotate & 1) ? req->dst.rect.height : req->dst.rect.width) > + req->src.rect.width * 16U || + req->src.rect.height > + ((req->rotate & 1) ? req->dst.rect.width : req->dst.rect.height) * 16U || + ((req->rotate & 1) ? req->dst.rect.width : req->dst.rect.height) > + req->src.rect.height * 16U) + { + return -RT_EINVAL; + } + + return RT_EOK; +} + +static rt_err_t rga2_alloc_buffer(struct rockchip_rga2 *rga2, + struct rga2_buffer *buffer) +{ + struct rockchip_rga2_buffer *entry; + rt_ubase_t physical; + + if (!buffer || !buffer->size || buffer->size > RGA2_BUFFER_MAX_SIZE) + { + return -RT_EINVAL; + } + entry = rt_calloc(1, sizeof(*entry)); + if (!entry) + { + return -RT_ENOMEM; + } + + buffer->virt_addr = rt_dma_alloc_coherent(rga2->dev, buffer->size, + &physical); + if (!buffer->virt_addr) + { + rt_free(entry); + return -RT_ENOMEM; + } + if (physical > UINT32_MAX) + { + rt_dma_free_coherent(rga2->dev, buffer->size, buffer->virt_addr, + physical); + buffer->virt_addr = RT_NULL; + rt_free(entry); + return -RT_EINVAL; + } + + buffer->phys_addr = physical; + entry->buffer = *buffer; + rt_list_insert_before(&rga2->buffers, &entry->list); + return RT_EOK; +} + +static rt_err_t rga2_free_buffer(struct rockchip_rga2 *rga2, + struct rga2_buffer *buffer) +{ + struct rockchip_rga2_buffer *entry; + + if (!buffer) + { + return -RT_EINVAL; + } + rt_list_for_each_entry(entry, &rga2->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(rga2->dev, entry->buffer.size, + entry->buffer.virt_addr, entry->buffer.phys_addr); + rt_free(entry); + rt_memset(buffer, 0, sizeof(*buffer)); + return RT_EOK; + } + } + return -RT_EINVAL; +} + +static rt_err_t rga2_submit(struct rockchip_rga2 *rga2, + struct rga2_req *req) +{ + rt_uint32_t command[RGA2_COMMAND_WORDS]; + rt_err_t err; + int i; + + if ((err = rga2_validate_request(rga2, req)) != RT_EOK || + (err = rockchip_rga2_build_command(req, command)) != RT_EOK) + { + return err; + } + + rockchip_rga2_reset(rga2); + rga2->irq_status = 0; + rga2->error = RT_EOK; + rt_completion_init(&rga2->completion); + + for (i = 0; i < RGA2_COMMAND_WORDS; ++i) + { + rga2_write(rga2, RGA2_CMD_REG_BASE + i * 4, command[i]); + } + rga2_write(rga2, RGA2_INT, RGA2_INT_ENABLE_MASK | RGA2_INT_CLEAR_MASK); + rt_hw_dsb(); + rga2_write(rga2, RGA2_SYS_CTRL, RGA2_SYS_AUTO_RESET | + RGA2_SYS_AUTO_CLOCK | RGA2_SYS_START); + + if (rt_completion_wait(&rga2->completion, + rt_tick_from_millisecond(RGA2_TIMEOUT_MS)) != RT_EOK) + { + LOG_E("job timeout, status1=%08x status2=%08x", + rga2_read(rga2, RGA2_STATUS1), + rga2_read(rga2, RGA2_STATUS2)); + rockchip_rga2_reset(rga2); + return -RT_ETIMEOUT; + } + + req->irq_status = rga2->irq_status; + return rga2->error; +} + +static rt_err_t rockchip_rga2_control(rt_device_t dev, int cmd, void *args) +{ + struct rockchip_rga2 *rga2 = raw_to_rockchip_rga2(dev); + rt_err_t err; + + rt_mutex_take(&rga2->lock, RT_WAITING_FOREVER); + switch (cmd) + { + case RGA2_SUBMIT: + err = rga2_submit(rga2, args); + break; + case RGA2_ALLOC_BUFFER: + err = rga2_alloc_buffer(rga2, args); + break; + case RGA2_FREE_BUFFER: + err = rga2_free_buffer(rga2, args); + break; + case RGA2_GET_VERSION: + if (!args) + { + err = -RT_EINVAL; + } + else + { + *(rt_uint32_t *)args = rga2->version; + err = RT_EOK; + } + break; + case RGA2_RESET: + rockchip_rga2_reset(rga2); + err = RT_EOK; + break; + default: + err = -RT_ENOSYS; + break; + } + rt_mutex_release(&rga2->lock); + return err; +} + +#ifdef RT_USING_DEVICE_OPS +static const struct rt_device_ops rockchip_rga2_ops = +{ + .control = rockchip_rga2_control, +}; +#endif + +static void rockchip_rga2_isr(int irqno, void *param) +{ + struct rockchip_rga2 *rga2 = param; + rt_uint32_t status = rga2_read(rga2, RGA2_INT); + + RT_UNUSED(irqno); + if (!(status & (RGA2_INT_ALL_DONE | RGA2_INT_ERROR_MASK))) + { + return; + } + + rga2->irq_status |= status; + if (status & RGA2_INT_ERROR_MASK) + { + rga2->error = -RT_EIO; + } + rga2_write(rga2, RGA2_INT, RGA2_INT_ENABLE_MASK | RGA2_INT_CLEAR_MASK); + rt_completion_done(&rga2->completion); +} + +static void rockchip_rga2_free(struct rockchip_rga2 *rga2) +{ + struct rockchip_rga2_buffer *entry, *next; + + rt_list_for_each_entry_safe(entry, next, &rga2->buffers, list) + { + rt_list_remove(&entry->list); + rt_dma_free_coherent(rga2->dev, entry->buffer.size, + entry->buffer.virt_addr, entry->buffer.phys_addr); + rt_free(entry); + } + if (rga2->device_registered) + { + rt_device_unregister(&rga2->parent); + } + if (rga2->lock_initialized) + { + rt_mutex_detach(&rga2->lock); + } + if (rga2->clocks_enabled) + { + rt_clk_array_disable_unprepare(rga2->clocks); + } + if (!rt_is_err_or_null(rga2->clocks)) + { + rt_clk_array_put(rga2->clocks); + } + if (rga2->regs) + { + rt_iounmap(rga2->regs); + } + rt_free(rga2); +} + +static rt_err_t rockchip_rga2_probe(struct rt_platform_device *pdev) +{ + struct rt_device *dev = &pdev->parent; + struct rockchip_rga2 *rga2; + const char *name; + rt_err_t err; + + rga2 = rt_calloc(1, sizeof(*rga2)); + if (!rga2) + { + return -RT_ENOMEM; + } + rga2->dev = dev; + rt_list_init(&rga2->buffers); + + rga2->regs = rt_dm_dev_iomap(dev, 0); + if (!rga2->regs) + { + err = -RT_EIO; + goto _fail; + } + rga2->clocks = rt_clk_get_array(dev); + if (rt_is_err(rga2->clocks)) + { + err = rt_ptr_err(rga2->clocks); + goto _fail; + } + if ((err = rt_clk_array_prepare_enable(rga2->clocks)) != RT_EOK) + { + goto _fail; + } + rga2->clocks_enabled = RT_TRUE; + rga2->irq = rt_dm_dev_get_irq(dev, 0); + if (rga2->irq < 0) + { + err = rga2->irq; + goto _fail; + } + + rga2->version = rga2_read(rga2, RGA2_VERSION_NUM); + rockchip_rga2_reset(rga2); + rt_dm_dev_set_name_auto(&rga2->parent, RGA2_NAME); + name = rt_dm_dev_get_name(&rga2->parent); + rga2->parent.type = RT_Device_Class_Char; +#ifdef RT_USING_DEVICE_OPS + rga2->parent.ops = &rockchip_rga2_ops; +#else + rga2->parent.control = rockchip_rga2_control; +#endif + dev->user_data = rga2; + + if ((err = rt_mutex_init(&rga2->lock, name, RT_IPC_FLAG_PRIO)) != RT_EOK) + { + goto _fail; + } + rga2->lock_initialized = RT_TRUE; + rt_completion_init(&rga2->completion); + if ((err = rt_device_register(&rga2->parent, name, + RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_STANDALONE)) != RT_EOK) + { + goto _fail; + } + rga2->device_registered = RT_TRUE; + + rt_hw_interrupt_install(rga2->irq, rockchip_rga2_isr, rga2, name); + rt_hw_interrupt_umask(rga2->irq); + LOG_I("RGA2 registered as %s, version %08x", name, rga2->version); + return RT_EOK; + +_fail: + rockchip_rga2_free(rga2); + return err; +} + +static rt_err_t rockchip_rga2_remove(struct rt_platform_device *pdev) +{ + struct rockchip_rga2 *rga2 = pdev->parent.user_data; + + rt_hw_interrupt_mask(rga2->irq); + rt_pic_detach_irq(rga2->irq, rga2); + rockchip_rga2_free(rga2); + return RT_EOK; +} + +static const struct rt_ofw_node_id rockchip_rga2_ofw_ids[] = +{ + { .compatible = "rockchip,rga2" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver rockchip_rga2_driver = +{ + .name = "rockchip-rga2", + .ids = rockchip_rga2_ofw_ids, + .probe = rockchip_rga2_probe, + .remove = rockchip_rga2_remove, +}; +RT_PLATFORM_DRIVER_EXPORT(rockchip_rga2_driver); diff --git a/bsp/rockchip/dm/soc/rga2/rga2_hw.c b/bsp/rockchip/dm/soc/rga2/rga2_hw.c new file mode 100644 index 000000000000..57513c9b1341 --- /dev/null +++ b/bsp/rockchip/dm/soc/rga2/rga2_hw.c @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-11-21 GuEe-GUI first version + */ + +#include "rga2_internal.h" +#include "rga2_reg.h" + +struct rga2_format_info +{ + rt_uint8_t hw_format; + rt_uint8_t bytes_per_pixel; + rt_uint8_t rb_swap; +}; + +static rt_err_t rga2_get_format(rt_uint16_t format, + struct rga2_format_info *info) +{ + static const struct rga2_format_info formats[] = + { + [RGA2_FORMAT_RGBA8888] = { 0, 4, 0 }, + [RGA2_FORMAT_BGRA8888] = { 0, 4, 1 }, + [RGA2_FORMAT_RGBX8888] = { 1, 4, 0 }, + [RGA2_FORMAT_BGRX8888] = { 1, 4, 1 }, + [RGA2_FORMAT_RGB888] = { 2, 3, 0 }, + [RGA2_FORMAT_BGR888] = { 2, 3, 1 }, + [RGA2_FORMAT_RGB565] = { 4, 2, 0 }, + [RGA2_FORMAT_BGR565] = { 4, 2, 1 }, + }; + + if (format >= sizeof(formats) / sizeof(formats[0])) + { + return -RT_EINVAL; + } + + *info = formats[format]; + return RT_EOK; +} + +static rt_uint32_t rga2_scale_factor(rt_uint16_t source, + rt_uint16_t destination) +{ + if (source == destination) + { + return 0; + } + + if (source > destination) + { + /* Average down-scaling uses a 16.16 destination/source ratio. */ + return ((rt_uint32_t)destination << 16) / source; + } + + /* Up-scaling uses a 16.16 source/destination ratio in the high half. */ + return (((rt_uint32_t)source << 16) / destination) << 16; +} + +static rt_uint32_t rga2_destination_address(const struct rga2_req *req, + rt_uint32_t stride, rt_uint8_t bytes_per_pixel) +{ + const struct rga2_rect *rect = &req->dst.rect; + rt_uint32_t left_top = (rt_uint32_t)req->dst.address + + rect->y * stride + rect->x * bytes_per_pixel; + rt_uint32_t right_top = left_top + + (rect->width - 1) * bytes_per_pixel; + rt_uint32_t left_bottom = left_top + + (rect->height - 1) * stride; + rt_uint32_t right_bottom = left_bottom + + (rect->width - 1) * bytes_per_pixel; + rt_uint32_t mirror_x = req->rotate >= RGA2_ROTATE_180; + rt_uint32_t mirror_y = mirror_x; + + mirror_x ^= !!(req->mirror & RGA2_MIRROR_X); + mirror_y ^= !!(req->mirror & RGA2_MIRROR_Y); + + if (!(req->rotate & 1)) + { + return mirror_y ? (mirror_x ? right_bottom : left_bottom) : + (mirror_x ? right_top : left_top); + } + + return mirror_y ? (mirror_x ? left_bottom : right_bottom) : + (mirror_x ? left_top : right_top); +} + +rt_err_t rockchip_rga2_build_command(const struct rga2_req *req, + rt_uint32_t command[RGA2_COMMAND_WORDS]) +{ + struct rga2_format_info src_format = { 0 }; + struct rga2_format_info dst_format; + rt_uint16_t scale_width; + rt_uint16_t scale_height; + rt_uint32_t src_stride = 0; + rt_uint32_t dst_stride; + rt_uint32_t src_info = 0; + + rt_memset(command, 0, RGA2_COMMAND_WORDS * sizeof(*command)); + + if (rga2_get_format(req->dst.format, &dst_format) != RT_EOK) + { + return -RT_EINVAL; + } + + dst_stride = RT_ALIGN(req->dst.stride, 4); + command[RGA2_MODE_CTRL / 4] = req->render_mode; + command[RGA2_DST_INFO / 4] = dst_format.hw_format | + ((rt_uint32_t)dst_format.rb_swap << 4); + command[RGA2_DST_BASE0 / 4] = rga2_destination_address(req, + dst_stride, dst_format.bytes_per_pixel); + command[RGA2_DST_VIR_INFO / 4] = dst_stride >> 2; + command[RGA2_DST_ACT_INFO / 4] = (req->dst.rect.width - 1) | + ((rt_uint32_t)(req->dst.rect.height - 1) << 16); + + if (req->render_mode == RGA2_MODE_COLOR_FILL) + { + command[RGA2_SRC_BG_COLOR / 4] = req->color; + return RT_EOK; + } + + if (rga2_get_format(req->src.format, &src_format) != RT_EOK) + { + return -RT_EINVAL; + } + + src_stride = RT_ALIGN(req->src.stride, 4); + scale_width = (req->rotate & 1) ? req->dst.rect.height : + req->dst.rect.width; + scale_height = (req->rotate & 1) ? req->dst.rect.width : + req->dst.rect.height; + + src_info = src_format.hw_format | + ((rt_uint32_t)src_format.rb_swap << 4) | + ((rt_uint32_t)req->rotate << 10) | + ((rt_uint32_t)(req->mirror & 3) << 12); + if (req->src.rect.width > scale_width) + { + src_info |= 1U << 14; + } + else if (req->src.rect.width < scale_width) + { + src_info |= 2U << 14; + } + if (req->src.rect.height > scale_height) + { + src_info |= 1U << 16; + } + else if (req->src.rect.height < scale_height) + { + src_info |= 2U << 16; + } + + command[RGA2_SRC_INFO / 4] = src_info; + command[RGA2_SRC_BASE0 / 4] = (rt_uint32_t)req->src.address + + req->src.rect.y * src_stride + + req->src.rect.x * src_format.bytes_per_pixel; + command[RGA2_SRC_VIR_INFO / 4] = src_stride >> 2; + command[RGA2_SRC_ACT_INFO / 4] = (req->src.rect.width - 1) | + ((rt_uint32_t)(req->src.rect.height - 1) << 16); + command[RGA2_SRC_X_FACTOR / 4] = rga2_scale_factor( + req->src.rect.width, scale_width); + command[RGA2_SRC_Y_FACTOR / 4] = rga2_scale_factor( + req->src.rect.height, scale_height); + + return RT_EOK; +} diff --git a/bsp/rockchip/dm/soc/rga2/rga2_internal.h b/bsp/rockchip/dm/soc/rga2/rga2_internal.h new file mode 100644 index 000000000000..2d24e3e895d9 --- /dev/null +++ b/bsp/rockchip/dm/soc/rga2/rga2_internal.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-11-21 GuEe-GUI first version + */ + +#ifndef __ROCKCHIP_RGA2_INTERNAL_H__ +#define __ROCKCHIP_RGA2_INTERNAL_H__ + +#include +#include + +#define RGA2_COMMAND_WORDS 32 + +rt_err_t rockchip_rga2_build_command(const struct rga2_req *req, + rt_uint32_t command[RGA2_COMMAND_WORDS]); + +#endif /* __ROCKCHIP_RGA2_INTERNAL_H__ */ diff --git a/bsp/rockchip/dm/soc/rga2/rga2_reg.h b/bsp/rockchip/dm/soc/rga2/rga2_reg.h new file mode 100644 index 000000000000..a582fe5ba261 --- /dev/null +++ b/bsp/rockchip/dm/soc/rga2/rga2_reg.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-11-21 GuEe-GUI first version + */ + +#ifndef __ROCKCHIP_RGA2_REG_H__ +#define __ROCKCHIP_RGA2_REG_H__ + +#define RGA2_SYS_CTRL 0x000 +#define RGA2_STATUS1 0x00c +#define RGA2_INT 0x010 +#define RGA2_STATUS2 0x01c +#define RGA2_VERSION_NUM 0x028 +#define RGA2_CMD_REG_BASE 0x100 + +#define RGA2_MODE_CTRL 0x00 +#define RGA2_SRC_INFO 0x04 +#define RGA2_SRC_BASE0 0x08 +#define RGA2_SRC_VIR_INFO 0x18 +#define RGA2_SRC_ACT_INFO 0x1c +#define RGA2_SRC_X_FACTOR 0x20 +#define RGA2_SRC_Y_FACTOR 0x24 +#define RGA2_SRC_BG_COLOR 0x28 +#define RGA2_DST_INFO 0x38 +#define RGA2_DST_BASE0 0x3c +#define RGA2_DST_VIR_INFO 0x48 +#define RGA2_DST_ACT_INFO 0x4c + +#define RGA2_SYS_AUTO_RESET (1U << 5) +#define RGA2_SYS_AUTO_CLOCK (1U << 2) +#define RGA2_SYS_START (1U << 0) +#define RGA2_SYS_SOFT_RESET ((1U << 4) | (1U << 3)) +#define RGA2_SYS_RESET_PROTECT (1U << 6) + +#define RGA2_INT_ALL_DONE_ENABLE (1U << 10) +#define RGA2_INT_MMU_ERROR_ENABLE (1U << 9) +#define RGA2_INT_BUS_ERROR_ENABLE (1U << 8) +#define RGA2_INT_ALL_DONE_CLEAR (1U << 6) +#define RGA2_INT_MMU_ERROR_CLEAR (1U << 5) +#define RGA2_INT_BUS_ERROR_CLEAR (1U << 4) +#define RGA2_INT_CURRENT_DONE_CLEAR (1U << 7) +#define RGA2_INT_ALL_DONE (1U << 2) +#define RGA2_INT_MMU_ERROR (1U << 1) +#define RGA2_INT_BUS_ERROR (1U << 0) +#define RGA2_INT_SCALE_ERROR_ENABLE (1U << 18) +#define RGA2_INT_SCALE_ERROR_CLEAR (1U << 19) +#define RGA2_INT_SCALE_ERROR (1U << 17) + +#define RGA2_INT_ERROR_MASK (RGA2_INT_MMU_ERROR | \ + RGA2_INT_BUS_ERROR | \ + RGA2_INT_SCALE_ERROR) +#define RGA2_INT_ENABLE_MASK (RGA2_INT_ALL_DONE_ENABLE | \ + RGA2_INT_MMU_ERROR_ENABLE | \ + RGA2_INT_BUS_ERROR_ENABLE | \ + RGA2_INT_SCALE_ERROR_ENABLE) +#define RGA2_INT_CLEAR_MASK (RGA2_INT_ALL_DONE_CLEAR | \ + RGA2_INT_CURRENT_DONE_CLEAR | \ + RGA2_INT_MMU_ERROR_CLEAR | \ + RGA2_INT_BUS_ERROR_CLEAR | \ + RGA2_INT_SCALE_ERROR_CLEAR) + +#endif /* __ROCKCHIP_RGA2_REG_H__ */ diff --git a/bsp/rockchip/dm/ufs/Kconfig b/bsp/rockchip/dm/ufs/Kconfig new file mode 100755 index 000000000000..f2a9fbe2efce --- /dev/null +++ b/bsp/rockchip/dm/ufs/Kconfig @@ -0,0 +1,4 @@ +config RT_UFS_ROCKCHIP + bool "Rockchip UFS" + depends on RT_USING_UFS + default n diff --git a/bsp/rockchip/dm/ufs/SConscript b/bsp/rockchip/dm/ufs/SConscript new file mode 100755 index 000000000000..656c604672b2 --- /dev/null +++ b/bsp/rockchip/dm/ufs/SConscript @@ -0,0 +1,13 @@ +from building import * + +group = [] +src = [] +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../include'] + +if GetDepend(['RT_UFS_ROCKCHIP']): + src += ['ufs-rockchip.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/rockchip/dm/ufs/ufs-rockchip.c b/bsp/rockchip/dm/ufs/ufs-rockchip.c new file mode 100755 index 000000000000..9a89c2336509 --- /dev/null +++ b/bsp/rockchip/dm/ufs/ufs-rockchip.c @@ -0,0 +1,451 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-07-07 GuEe-GUI the first version + */ + +#include +#include +#include + +#include + +#define DBG_TAG "ufs.rockchip" +#define DBG_LVL DBG_INFO +#include + +#define SEL_TX_LANE0 0x0 +#define SEL_TX_LANE1 0x1 +#define SEL_RX_LANE0 0x4 +#define SEL_RX_LANE1 0x5 + +#define MPHY_CFG 0x200 +#define MPHY_CFG_ENABLE 0x40 +#define MPHY_CFG_DISABLE 0x0 + +#define MIB_T_DBG_CPORT_TX_ENDIAN 0xc022 +#define MIB_T_DBG_CPORT_RX_ENDIAN 0xc023 + +#define PA_LOCAL_TX_LCC_ENABLE 0x155e +#define N_DEVICEID 0x1560 +#define N_DEVICEID_VALID 0x1561 +#define T_PEERDEVICEID 0x4021 +#define T_CONNECTIONSTATE 0x4020 + +#define CMN_REG23 0x08c +#define CMN_REG25 0x094 +#define TRSV0_REG08 0x0e0 +#define TRSV1_REG08 0x220 +#define TRSV0_REG14 0x110 +#define TRSV1_REG14 0x250 +#define TRSV0_REG15 0x134 +#define TRSV1_REG15 0x274 +#define TRSV0_REG16 0x128 +#define TRSV1_REG16 0x268 +#define TRSV0_REG17 0x12c +#define TRSV1_REG17 0x26c +#define TRSV0_REG18 0x120 +#define TRSV1_REG18 0x260 +#define TRSV0_REG29 0x164 +#define TRSV1_REG29 0x2a4 +#define TRSV0_REG2E 0x178 +#define TRSV1_REG2E 0x2b8 +#define TRSV0_REG3C 0x1b0 +#define TRSV1_REG3C 0x2f0 +#define TRSV0_REG3D 0x1b4 +#define TRSV1_REG3D 0x2f4 + +#define UIC_ARG_MIB_SEL(attr, sel) ((((rt_uint32_t)(attr)) & 0xffffu) << 16 | (((rt_uint32_t)(sel)) & 0xffffu)) + +struct rockchip_ufs_host +{ + struct rt_ufs_host parent; + + void *mphy_base; + + rt_base_t rst_pin; + rt_uint8_t rst_active_val; + + struct rt_reset_control *rstc; + struct rt_clk *ref_out_clk; + struct rt_clk_array *clk_arr; + + rt_uint32_t phy_config_mode; +}; + +#define ufs_sys_writel(base, val, reg) HWREG32((base) + (reg)) = (val) + +static const rt_uint8_t rk3576_phy_value[15][4] = +{ + { 0x03, 0x38, 0x50, 0x80 }, + { 0x03, 0x14, 0x58, 0x80 }, + { 0x03, 0x26, 0x58, 0x80 }, + { 0x03, 0x49, 0x58, 0x80 }, + { 0x03, 0x5a, 0x58, 0x80 }, + { 0xc3, 0x38, 0x50, 0xc0 }, + { 0xc3, 0x14, 0x58, 0xc0 }, + { 0xc3, 0x26, 0x58, 0xc0 }, + { 0xc3, 0x49, 0x58, 0xc0 }, + { 0xc3, 0x5a, 0x58, 0xc0 }, + { 0x43, 0x38, 0x50, 0xc0 }, + { 0x43, 0x14, 0x58, 0xc0 }, + { 0x43, 0x26, 0x58, 0xc0 }, + { 0x43, 0x49, 0x58, 0xc0 }, + { 0x43, 0x5a, 0x58, 0xc0 } +}; + +static void rk3576_controller_reset(struct rockchip_ufs_host *rkufs) +{ + if (rkufs->rstc && !rt_is_err(rkufs->rstc)) + { + rt_reset_control_assert(rkufs->rstc); + rt_hw_us_delay(1); + rt_reset_control_deassert(rkufs->rstc); + } +} + +static rt_err_t rk3576_phy_parameter_init(struct rockchip_ufs_host *rkufs) +{ + rt_uint32_t try_case = rkufs->phy_config_mode; + rt_uint32_t value; + + if (!rkufs->mphy_base) + { + return -RT_EIO; + } + + if (try_case >= RT_ARRAY_SIZE(rk3576_phy_value)) + { + try_case = 0; + } + + ufs_sys_writel(rkufs->mphy_base, 0x80, CMN_REG23); + ufs_sys_writel(rkufs->mphy_base, 0xb5, TRSV0_REG14); + ufs_sys_writel(rkufs->mphy_base, 0xb5, TRSV1_REG14); + + value = rk3576_phy_value[try_case][0]; + ufs_sys_writel(rkufs->mphy_base, value, TRSV0_REG15); + ufs_sys_writel(rkufs->mphy_base, value, TRSV1_REG15); + + value = rk3576_phy_value[try_case][1]; + ufs_sys_writel(rkufs->mphy_base, value, TRSV0_REG08); + ufs_sys_writel(rkufs->mphy_base, value, TRSV1_REG08); + + value = rk3576_phy_value[try_case][2]; + ufs_sys_writel(rkufs->mphy_base, value, TRSV0_REG29); + ufs_sys_writel(rkufs->mphy_base, value, TRSV1_REG29); + + value = rk3576_phy_value[try_case][3]; + ufs_sys_writel(rkufs->mphy_base, value, TRSV0_REG2E); + ufs_sys_writel(rkufs->mphy_base, value, TRSV1_REG2E); + + ufs_sys_writel(rkufs->mphy_base, 0x18, TRSV0_REG3C); + ufs_sys_writel(rkufs->mphy_base, 0x18, TRSV1_REG3C); + + ufs_sys_writel(rkufs->mphy_base, 0x03, TRSV0_REG16); + ufs_sys_writel(rkufs->mphy_base, 0x03, TRSV1_REG16); + + ufs_sys_writel(rkufs->mphy_base, 0x20, TRSV0_REG17); + ufs_sys_writel(rkufs->mphy_base, 0x20, TRSV1_REG17); + + ufs_sys_writel(rkufs->mphy_base, 0xc0, TRSV0_REG18); + ufs_sys_writel(rkufs->mphy_base, 0xc0, TRSV1_REG18); + + ufs_sys_writel(rkufs->mphy_base, 0x03, CMN_REG25); + ufs_sys_writel(rkufs->mphy_base, 0x03, TRSV0_REG3D); + ufs_sys_writel(rkufs->mphy_base, 0x03, TRSV1_REG3D); + + ufs_sys_writel(rkufs->mphy_base, 0xc0, CMN_REG23); + rt_hw_us_delay(1); + ufs_sys_writel(rkufs->mphy_base, 0x00, CMN_REG23); + rt_hw_us_delay(200); + + return RT_EOK; +} + +static rt_err_t rk3576_phy_init(struct rockchip_ufs_host *rkufs) +{ + rt_err_t err; + struct rt_ufs_host *ufs = &rkufs->parent; + + if ((err = rt_ufs_dme_set(ufs, UIC_ARG_MIB_SEL(PA_LOCAL_TX_LCC_ENABLE, 0), 0))) + { + return err; + } + + if ((err = rt_ufs_dme_set(ufs, UIC_ARG_MIB_SEL(MPHY_CFG, 0), MPHY_CFG_ENABLE))) + { + return err; + } + + for (int i = 0; i < 2; ++i) + { + if ((err = rt_ufs_dme_set(ufs, UIC_ARG_MIB_SEL(0xaa, SEL_TX_LANE0 + i), 0x06)) || + (err = rt_ufs_dme_set(ufs, UIC_ARG_MIB_SEL(0xa9, SEL_TX_LANE0 + i), 0x02)) || + (err = rt_ufs_dme_set(ufs, UIC_ARG_MIB_SEL(0xad, SEL_TX_LANE0 + i), 0x44)) || + (err = rt_ufs_dme_set(ufs, UIC_ARG_MIB_SEL(0xac, SEL_TX_LANE0 + i), 0xe6)) || + (err = rt_ufs_dme_set(ufs, UIC_ARG_MIB_SEL(0xab, SEL_TX_LANE0 + i), 0x07)) || + (err = rt_ufs_dme_set(ufs, UIC_ARG_MIB_SEL(0x94, SEL_TX_LANE0 + i), 0x93)) || + (err = rt_ufs_dme_set(ufs, UIC_ARG_MIB_SEL(0x93, SEL_TX_LANE0 + i), 0xc9)) || + (err = rt_ufs_dme_set(ufs, UIC_ARG_MIB_SEL(0x7f, SEL_TX_LANE0 + i), 0x00)) || + (err = rt_ufs_dme_set(ufs, UIC_ARG_MIB_SEL(0x12, SEL_RX_LANE0 + i), 0x06)) || + (err = rt_ufs_dme_set(ufs, UIC_ARG_MIB_SEL(0x11, SEL_RX_LANE0 + i), 0x00)) || + (err = rt_ufs_dme_set(ufs, UIC_ARG_MIB_SEL(0x1d, SEL_RX_LANE0 + i), 0x58)) || + (err = rt_ufs_dme_set(ufs, UIC_ARG_MIB_SEL(0x1c, SEL_RX_LANE0 + i), 0x8c)) || + (err = rt_ufs_dme_set(ufs, UIC_ARG_MIB_SEL(0x1b, SEL_RX_LANE0 + i), 0x02)) || + (err = rt_ufs_dme_set(ufs, UIC_ARG_MIB_SEL(0x25, SEL_RX_LANE0 + i), 0xf6)) || + (err = rt_ufs_dme_set(ufs, UIC_ARG_MIB_SEL(0x2f, SEL_RX_LANE0 + i), 0x69))) + { + return err; + } + } + + if ((err = rt_ufs_dme_set(ufs, UIC_ARG_MIB_SEL(MPHY_CFG, 0), MPHY_CFG_DISABLE))) + { + return err; + } + + if ((err = rk3576_phy_parameter_init(rkufs))) + { + return err; + } + + if ((err = rt_ufs_dme_set(ufs, UIC_ARG_MIB_SEL(MIB_T_DBG_CPORT_TX_ENDIAN, 0), 0)) || + (err = rt_ufs_dme_set(ufs, UIC_ARG_MIB_SEL(MIB_T_DBG_CPORT_RX_ENDIAN, 0), 0)) || + (err = rt_ufs_dme_set(ufs, UIC_ARG_MIB_SEL(N_DEVICEID, 0), 0)) || + (err = rt_ufs_dme_set(ufs, UIC_ARG_MIB_SEL(N_DEVICEID_VALID, 0), 1)) || + (err = rt_ufs_dme_set(ufs, UIC_ARG_MIB_SEL(T_PEERDEVICEID, 0), 1)) || + (err = rt_ufs_dme_set(ufs, UIC_ARG_MIB_SEL(T_CONNECTIONSTATE, 0), 1))) + { + return err; + } + + return RT_EOK; +} + +static rt_err_t rk3576_ufs_init(struct rt_ufs_host *ufs) +{ + rt_err_t err; + struct rt_device *dev = ufs->parent.dev; + struct rockchip_ufs_host *rkufs = rt_container_of(ufs, struct rockchip_ufs_host, parent); + + rkufs->clk_arr = rt_clk_get_array(dev); + if (rt_is_err(rkufs->clk_arr)) + { + return rt_ptr_err(rkufs->clk_arr); + } + + if ((err = rt_clk_array_prepare_enable(rkufs->clk_arr))) + { + return err; + } + + rkufs->ref_out_clk = rt_clk_get_by_name(dev, "ref_out"); + if (rt_is_err(rkufs->ref_out_clk)) + { + return rt_ptr_err(rkufs->ref_out_clk); + } + + rt_clk_prepare_enable(rkufs->ref_out_clk); + + rkufs->rstc = rt_reset_control_get_array(dev); + if (rt_is_err(rkufs->rstc)) + { + return rt_ptr_err(rkufs->rstc); + } + + rk3576_controller_reset(rkufs); + + rkufs->rst_pin = rt_pin_get_named_pin(dev, "reset", 0, RT_NULL, &rkufs->rst_active_val); + if (rkufs->rst_pin >= 0) + { + rt_pin_write(rkufs->rst_pin, !rkufs->rst_active_val); + rt_pin_mode(rkufs->rst_pin, PIN_MODE_OUTPUT); + } + + if (rt_dm_dev_prop_read_u32(dev, "ufs-phy-config-mode", &rkufs->phy_config_mode)) + { + rkufs->phy_config_mode = 0; + } + + return RT_EOK; +} + +static rt_err_t rk3576_ufs_exit(struct rt_ufs_host *ufs) +{ + struct rockchip_ufs_host *rkufs = rt_container_of(ufs, struct rockchip_ufs_host, parent); + + if (rkufs->rstc && !rt_is_err(rkufs->rstc)) + { + rt_reset_control_assert(rkufs->rstc); + rt_reset_control_put(rkufs->rstc); + rkufs->rstc = RT_NULL; + } + + if (rkufs->ref_out_clk && !rt_is_err(rkufs->ref_out_clk)) + { + rt_clk_disable_unprepare(rkufs->ref_out_clk); + rkufs->ref_out_clk = RT_NULL; + } + + if (rkufs->clk_arr && !rt_is_err(rkufs->clk_arr)) + { + rt_clk_array_disable_unprepare(rkufs->clk_arr); + rt_clk_array_put(rkufs->clk_arr); + rkufs->clk_arr = RT_NULL; + } + + return RT_EOK; +} + +static rt_err_t rk3576_ufs_reset(struct rt_ufs_host *ufs) +{ + struct rockchip_ufs_host *rkufs = rt_container_of(ufs, struct rockchip_ufs_host, parent); + + if (rkufs->rst_pin >= 0) + { + rt_pin_write(rkufs->rst_pin, rkufs->rst_active_val); + rt_hw_us_delay(20); + rt_pin_write(rkufs->rst_pin, !rkufs->rst_active_val); + rt_hw_us_delay(20); + } + + rk3576_controller_reset(rkufs); + + return RT_EOK; +} + +static rt_err_t rk3576_hce_enable_notify(struct rt_ufs_host *ufs, enum rt_ufs_notify_change_status status) +{ + struct rockchip_ufs_host *rkufs = rt_container_of(ufs, struct rockchip_ufs_host, parent); + rt_err_t err; + + if (status == RT_UFS_NOTIFY_CHANGE_STATUS_PRE) + { + rk3576_controller_reset(rkufs); + return RT_EOK; + } + + if ((err = rt_ufs_dme_reset(ufs))) + { + return err; + } + + if ((err = rt_ufs_dme_enable(ufs))) + { + return err; + } + + return rk3576_phy_init(rkufs); +} + +static const struct rt_ufs_ops rk3576_ufs_ops = +{ + .init = rk3576_ufs_init, + .exit = rk3576_ufs_exit, + .reset = rk3576_ufs_reset, + .hce_enable_notify = rk3576_hce_enable_notify, +}; + +static rt_err_t rockchip_ufs_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + struct rt_ufs_host *ufs; + struct rt_device *dev = &pdev->parent; + struct rockchip_ufs_host *rkufs = rt_calloc(1, sizeof(*rkufs)); + + if (!rkufs) + { + return -RT_ENOMEM; + } + + ufs = &rkufs->parent; + ufs->parent.dev = dev; + ufs->ops = pdev->id->data; + + ufs->regs = rt_dm_dev_iomap_by_name(dev, "hci"); + if (!ufs->regs) + { + err = -RT_EIO; + goto _fail; + } + + rkufs->mphy_base = rt_dm_dev_iomap_by_name(dev, "mphy"); + if (!rkufs->mphy_base) + { + err = -RT_EIO; + goto _fail; + } + + ufs->irq = rt_dm_dev_get_irq(dev, 0); + if (ufs->irq < 0) + { + err = (rt_err_t)ufs->irq; + goto _fail; + } + + if ((err = rt_ufs_host_register(ufs))) + { + goto _fail; + } + + dev->user_data = rkufs; + pdev->parent.user_data = rkufs; + + return RT_EOK; + +_fail: + if (ufs->regs) + { + rt_iounmap(ufs->regs); + } + if (rkufs->mphy_base) + { + rt_iounmap(rkufs->mphy_base); + } + + rt_free(rkufs); + + return err; +} + +static rt_err_t rockchip_ufs_remove(struct rt_platform_device *pdev) +{ + struct rockchip_ufs_host *rkufs = pdev->parent.user_data; + struct rt_ufs_host *ufs = &rkufs->parent; + + rt_ufs_host_unregister(ufs); + + if (ufs->regs) + { + rt_iounmap(ufs->regs); + } + if (rkufs->mphy_base) + { + rt_iounmap(rkufs->mphy_base); + } + + rt_free(rkufs); + + return RT_EOK; +} + +static const struct rt_ofw_node_id rockchip_ufs_ofw_ids[] = +{ + { .compatible = "rockchip,rk3576-ufshc", .data = &rk3576_ufs_ops }, + { /* sentinel */ } +}; + +static struct rt_platform_driver rockchip_ufs_driver = +{ + .name = "rockchip-ufs", + .ids = rockchip_ufs_ofw_ids, + + .probe = rockchip_ufs_probe, + .remove = rockchip_ufs_remove, +}; +RT_PLATFORM_DRIVER_EXPORT(rockchip_ufs_driver); diff --git a/bsp/rockchip/rk3300/.config b/bsp/rockchip/rk3300/.config index 4c63a5d386eb..e656eef68da2 100644 --- a/bsp/rockchip/rk3300/.config +++ b/bsp/rockchip/rk3300/.config @@ -203,6 +203,7 @@ CONFIG_ARCH_HAVE_EFFICIENT_UNALIGNED_ACCESS=y CONFIG_ARCH_USING_GENERIC_CPUID=y CONFIG_ARCH_HEAP_SIZE=0x4000000 CONFIG_ARCH_INIT_PAGE_SIZE=0x200000 +# CONFIG_ARCH_USING_CPUIDLE is not set # end of AArch64 Architecture Configuration CONFIG_ARCH_CPU_64BIT=y @@ -322,9 +323,18 @@ CONFIG_RT_USING_SERIAL_BYPASS=y CONFIG_RT_SERIAL_8250=y CONFIG_RT_SERIAL_8250_DW=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_ROCKCHIP_SARADC=y CONFIG_RT_USING_CLOCK_TIME=y -# CONFIG_RT_CLOCK_TIME_ARM_ARCH is not set -# CONFIG_RT_CLOCK_TIMER_ROCKCHIP is not set +# CONFIG_RT_USING_CLOCK_TIMER_TRIGGER is not set +CONFIG_RT_CLOCK_TIME_ARM_ARCH=y +CONFIG_RT_CLOCK_TIMER_ROCKCHIP=y +CONFIG_RT_USING_ETHERNET=y +# CONFIG_RT_ETHERNET_CADENCE is not set +CONFIG_RT_ETHERNET_DWMAC=y +CONFIG_RT_ETHERNET_DWMAC_ROCKCHIP=y CONFIG_RT_USING_I2C=y # CONFIG_RT_I2C_DEBUG is not set CONFIG_RT_USING_I2C_BITOPS=y @@ -332,9 +342,8 @@ CONFIG_RT_USING_I2C_BITOPS=y # CONFIG_RT_USING_SOFT_I2C is not set CONFIG_RT_I2C_RK3X=y # CONFIG_RT_USING_PHY is not set -# CONFIG_RT_USING_PHY_V2 is not set -CONFIG_RT_USING_ADC=y -CONFIG_RT_ADC_ROCKCHIP_SARADC=y +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 @@ -361,6 +370,7 @@ CONFIG_RT_ALARM_PRIORITY=10 # CONFIG_RT_RTC_PCF8563 is not set # CONFIG_RT_RTC_PL031 is not set # CONFIG_RT_RTC_RX8010 is not set +# CONFIG_RT_RTC_RK8XX is not set CONFIG_RT_RTC_RK_TIMER=y CONFIG_RT_USING_SDIO=y CONFIG_RT_SDIO_STACK_SIZE=8192 @@ -371,6 +381,7 @@ CONFIG_RT_MMCSD_MAX_PARTITION=16 # CONFIG_RT_SDIO_DEBUG is not set # CONFIG_RT_USING_SDHCI is not set CONFIG_RT_SDIO_DW_MMC=y +# CONFIG_RT_SDIO_SDHCI_DWCMSHC is not set CONFIG_RT_SDIO_DW_MMC_ROCKCHIP=y CONFIG_RT_USING_SPI=y CONFIG_RT_USING_SPI_ISR=y @@ -385,17 +396,53 @@ CONFIG_RT_SPI_ROCKCHIP_SFC=y CONFIG_RT_SPI_ROCKCHIP=y CONFIG_RT_USING_WDT=y CONFIG_RT_WDT_DW=y -# CONFIG_RT_USING_AUDIO is not set +# CONFIG_RT_WDT_RK8XX is not set +CONFIG_RT_USING_AUDIO=y +CONFIG_RT_AUDIO_REPLAY_MP_BLOCK_SIZE=4096 +CONFIG_RT_AUDIO_REPLAY_MP_BLOCK_COUNT=2 +CONFIG_RT_AUDIO_RECORD_PIPE_SIZE=2048 +CONFIG_RT_AUDIO_ROCKCHIP=y +CONFIG_RT_AUDIO_ROCKCHIP_I2S_TDM=y +CONFIG_RT_AUDIO_ROCKCHIP_CODEC=y +CONFIG_RT_AUDIO_ROCKCHIP_CODEC_RK817=y +CONFIG_RT_AUDIO_ROCKCHIP_CARD=y # CONFIG_RT_USING_SENSOR is not set # CONFIG_RT_USING_TOUCH is not set -# CONFIG_RT_USING_GRAPHIC is not set +CONFIG_RT_USING_LCD=y +CONFIG_RT_USING_GRAPHIC=y +# CONFIG_RT_GRAPHIC_BACKLIGHT is not set +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_VOP2 is not set +# CONFIG_RT_GRAPHIC_FB_VOPL is not set +CONFIG_RT_GRAPHIC_FB_VOP1=y +CONFIG_RT_GRAPHIC_DISPLAY_ROCKCHIP=y +CONFIG_RT_GRAPHIC_CONNECTOR_DSI=y +CONFIG_RT_GRAPHIC_CONNECTOR_HDMI=y +CONFIG_RT_GRAPHIC_BACKLIGHT_HINT=y +CONFIG_RT_GRAPHIC_PANEL_SIMPLE=y +CONFIG_RT_GRAPHIC_INPUT_TOUCH_HINT=y +CONFIG_RT_GRAPHIC_LOGO=y +# CONFIG_RT_GRAPHIC_LOGO_NONE is not set +CONFIG_RT_GRAPHIC_LOGO_RT_THREAD_CLUT224=y +# CONFIG_RT_GRAPHIC_LOGO_RT_THREAD_WHITE_CLUT224 is not set +# CONFIG_RT_GRAPHIC_LOGO_RADXA_CLUT224 is not set +# CONFIG_RT_GRAPHIC_LOGO_ROCKCHIP_CLUT224 is not set 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 is not set -# CONFIG_RT_HWCRYPTO_USING_DES 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=y +CONFIG_RT_HWCRYPTO_USING_AES_CTR=y +CONFIG_RT_HWCRYPTO_USING_AES_OFB=y +CONFIG_RT_HWCRYPTO_USING_DES=y +CONFIG_RT_HWCRYPTO_USING_DES_ECB=y +CONFIG_RT_HWCRYPTO_USING_DES_CBC=y # CONFIG_RT_HWCRYPTO_USING_3DES is not set # CONFIG_RT_HWCRYPTO_USING_RC4 is not set # CONFIG_RT_HWCRYPTO_USING_MD5 is not set @@ -405,7 +452,9 @@ 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_RNG_ROCKCHIP=y +CONFIG_RT_HWCRYPTO_CRYPTO_ROCKCHIP_V2=y # CONFIG_RT_USING_WIFI is not set +# CONFIG_RT_USING_PTP is not set CONFIG_RT_USING_LED=y CONFIG_RT_LED_GPIO=y # CONFIG_RT_LED_PWM is not set @@ -413,6 +462,7 @@ CONFIG_RT_LED_GPIO=y # CONFIG_RT_USING_INPUT is not set # CONFIG_RT_USING_MBOX is not set # CONFIG_RT_USING_HWSPINLOCK is not set +# CONFIG_RT_USING_RPMSG is not set # CONFIG_RT_USING_PHYE is not set # CONFIG_RT_USING_ATA is not set # CONFIG_RT_USING_NVME is not set @@ -427,11 +477,33 @@ CONFIG_RT_BLK_PARTITION_EFI=y # CONFIG_RT_USING_SCSI is not set CONFIG_RT_USING_FIRMWARE=y +# CONFIG_RT_FIRMWARE_QEMU_FW_CFG is not set # CONFIG_RT_FIRMWARE_ARM_SCMI 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 +# +CONFIG_RT_DVFS_EVENT_ROCKCHIP_DFI=y + +# +# DVFS CPUfreq Drivers +# +CONFIG_RT_DVFS_ROCKCHIP_CPUFREQ=y + +# +# DVFS Devfreq Drivers +# +CONFIG_RT_DVFS_ROCKCHIP_DMC=y 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=y +CONFIG_RT_REGULATOR_RK8XX=y CONFIG_RT_USING_RESET=y # CONFIG_RT_RESET_SIMPLE is not set @@ -458,14 +530,19 @@ CONFIG_RT_THERMAL_ROCKCHIP_TSADC=y # # Thermal Cool Drivers # +# CONFIG_RT_THERMAL_COOL_DVFS is not set +# CONFIG_RT_THERMAL_COOL_GPIO_FAN is not set CONFIG_RT_THERMAL_COOL_PWM_FAN=y # CONFIG_RT_USING_VIRTIO is not set -# CONFIG_RT_USING_NVMEM is not set +CONFIG_RT_USING_NVMEM=y +CONFIG_RT_NVMEM_ROCKCHIP_OTP=y CONFIG_RT_USING_DMA=y CONFIG_RT_DMA_PL330=y +# CONFIG_RT_DMA_DW_AXI_DMAC is not set CONFIG_RT_USING_MFD=y CONFIG_RT_MFD_SYSCON=y -# CONFIG_RT_MFD_RK8XX_I2C is not set +CONFIG_RT_MFD_RK8XX=y +CONFIG_RT_MFD_RK8XX_I2C=y # CONFIG_RT_MFD_RK8XX_SPI is not set CONFIG_RT_USING_OFW=y # CONFIG_RT_USING_BUILTIN_FDT is not set @@ -483,8 +560,10 @@ CONFIG_RT_USING_PIN=y CONFIG_RT_PIN_ROCKCHIP=y CONFIG_RT_USING_PINCTRL=y # CONFIG_RT_PINCTRL_SINGLE is not set +# CONFIG_RT_PINCTRL_ROCKCHIP_RK8XX is not set CONFIG_RT_PINCTRL_ROCKCHIP=y CONFIG_RT_USING_CLK=y +# CONFIG_RT_CLK_ROCKCHIP_RK8XX_CLKOUT is not set # CONFIG_RT_CLK_ROCKCHIP_LINK is not set CONFIG_RT_CLK_ROCKCHIP=y CONFIG_RT_CLK_ROCKCHIP_RK3308=y @@ -500,6 +579,8 @@ CONFIG_RT_CLK_ROCKCHIP_RK3308=y CONFIG_RT_SOC_ROCKCHIP_FIQ_DEBUGGER=y CONFIG_RT_SOC_ROCKCHIP_GRF=y # CONFIG_RT_SOC_ROCKCHIP_HW_DECOMPRESS is not set +# CONFIG_RT_ROCKCHIP_JPEG_DEC is not set +# CONFIG_RT_ROCKCHIP_RGA2 is not set CONFIG_RT_SOC_ROCKCHIP_IODOMAIN=y # end of SoC (System on Chip) Drivers # end of Device Drivers @@ -565,9 +646,90 @@ CONFIG_RT_USING_POSIX_TIMER=y # # Network # -# CONFIG_RT_USING_SAL is not set -# CONFIG_RT_USING_NETDEV is not set -# CONFIG_RT_USING_LWIP is not set +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_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=8 +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 @@ -635,6 +797,7 @@ CONFIG_RT_USING_VDSO=y # 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 @@ -837,7 +1000,6 @@ CONFIG_RT_USING_VDSO=y # 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 @@ -862,9 +1024,6 @@ CONFIG_RT_USING_VDSO=y # # 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 @@ -913,9 +1072,6 @@ CONFIG_RT_USING_VDSO=y # 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 # end of tools packages # @@ -1010,9 +1166,6 @@ CONFIG_RT_USING_VDSO=y # 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 # @@ -1158,7 +1311,9 @@ CONFIG_RT_USING_VDSO=y # # NUVOTON Drivers # +# CONFIG_PKG_USING_NUVOTON_CMSIS_DRIVER is not set # CONFIG_PKG_USING_NUVOTON_SERIES_DRIVER is not set +# CONFIG_PKG_USING_NUVOTON_ARM926_LIB is not set # end of NUVOTON Drivers # @@ -1166,24 +1321,7 @@ CONFIG_RT_USING_VDSO=y # # 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 # end of HAL & SDK Drivers # @@ -1229,11 +1367,9 @@ CONFIG_RT_USING_VDSO=y # 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 @@ -1262,7 +1398,6 @@ CONFIG_RT_USING_VDSO=y # 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 # @@ -1280,7 +1415,6 @@ CONFIG_RT_USING_VDSO=y # 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 @@ -1360,13 +1494,6 @@ CONFIG_RT_USING_VDSO=y # 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_SPI_TOOLS is not set # end of peripheral libraries and drivers diff --git a/bsp/rockchip/rk3300/rtconfig.h b/bsp/rockchip/rk3300/rtconfig.h index c1173d0d1d6c..caddee92a482 100755 --- a/bsp/rockchip/rk3300/rtconfig.h +++ b/bsp/rockchip/rk3300/rtconfig.h @@ -222,12 +222,20 @@ #define RT_USING_SERIAL_BYPASS #define RT_SERIAL_8250 #define RT_SERIAL_8250_DW +#define RT_USING_ADC +#define RT_USING_ADC_V1 +#define RT_ADC_ROCKCHIP_SARADC #define RT_USING_CLOCK_TIME +#define RT_CLOCK_TIME_ARM_ARCH +#define RT_CLOCK_TIMER_ROCKCHIP +#define RT_USING_ETHERNET +#define RT_ETHERNET_DWMAC +#define RT_ETHERNET_DWMAC_ROCKCHIP #define RT_USING_I2C #define RT_USING_I2C_BITOPS #define RT_I2C_RK3X -#define RT_USING_ADC -#define RT_ADC_ROCKCHIP_SARADC +#define RT_USING_PHY_V2 +#define RT_PHY_V2_REALTEK #define RT_USING_NULL #define RT_USING_ZERO #define RT_USING_RANDOM @@ -254,12 +262,43 @@ #define RT_SPI_ROCKCHIP #define RT_USING_WDT #define RT_WDT_DW +#define RT_USING_AUDIO +#define RT_AUDIO_REPLAY_MP_BLOCK_SIZE 4096 +#define RT_AUDIO_REPLAY_MP_BLOCK_COUNT 2 +#define RT_AUDIO_RECORD_PIPE_SIZE 2048 +#define RT_AUDIO_ROCKCHIP +#define RT_AUDIO_ROCKCHIP_I2S_TDM +#define RT_AUDIO_ROCKCHIP_CODEC +#define RT_AUDIO_ROCKCHIP_CODEC_RK817 +#define RT_AUDIO_ROCKCHIP_CARD +#define RT_USING_LCD +#define RT_USING_GRAPHIC +#define RT_GRAPHIC_FB +#define RT_GRAPHIC_FB_VOP1 +#define RT_GRAPHIC_DISPLAY_ROCKCHIP +#define RT_GRAPHIC_CONNECTOR_DSI +#define RT_GRAPHIC_CONNECTOR_HDMI +#define RT_GRAPHIC_BACKLIGHT_HINT +#define RT_GRAPHIC_PANEL_SIMPLE +#define RT_GRAPHIC_INPUT_TOUCH_HINT +#define RT_GRAPHIC_LOGO +#define RT_GRAPHIC_LOGO_RT_THREAD_CLUT224 #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_AES_CFB +#define RT_HWCRYPTO_USING_AES_CTR +#define RT_HWCRYPTO_USING_AES_OFB +#define RT_HWCRYPTO_USING_DES +#define RT_HWCRYPTO_USING_DES_ECB +#define RT_HWCRYPTO_USING_DES_CBC #define RT_HWCRYPTO_USING_RNG #define RT_HWCRYPTO_RNG_ROCKCHIP +#define RT_HWCRYPTO_CRYPTO_ROCKCHIP_V2 #define RT_USING_LED #define RT_LED_GPIO #define RT_USING_BLK @@ -270,9 +309,26 @@ #define RT_BLK_PARTITION_EFI /* end of Partition Types */ #define RT_USING_FIRMWARE +#define RT_USING_DVFS +#define RT_USING_DVFS_EVENT +#define RT_USING_DVFS_OPP_RETRY_MAX 10 + +/* DVFS Event Drivers */ + +#define RT_DVFS_EVENT_ROCKCHIP_DFI + +/* DVFS CPUfreq Drivers */ + +#define RT_DVFS_ROCKCHIP_CPUFREQ + +/* DVFS Devfreq Drivers */ + +#define RT_DVFS_ROCKCHIP_DMC #define RT_USING_REGULATOR #define RT_REGULATOR_FIXED #define RT_REGULATOR_GPIO +#define RT_REGULATOR_PWM +#define RT_REGULATOR_RK8XX #define RT_USING_RESET /* Power Management (PM) Domains device drivers */ @@ -288,10 +344,14 @@ /* Thermal Cool Drivers */ #define RT_THERMAL_COOL_PWM_FAN +#define RT_USING_NVMEM +#define RT_NVMEM_ROCKCHIP_OTP #define RT_USING_DMA #define RT_DMA_PL330 #define RT_USING_MFD #define RT_MFD_SYSCON +#define RT_MFD_RK8XX +#define RT_MFD_RK8XX_I2C #define RT_USING_OFW #define RT_FDT_EARLYCON_MSG_SIZE 128 #define RT_USING_OFW_BUS_RANGES_NUMBER 8 @@ -355,6 +415,66 @@ /* 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 8 +#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 */ @@ -524,14 +644,6 @@ /* GD32 Drivers */ /* end of GD32 Drivers */ - -/* HPMicro SDK */ - -/* end of HPMicro SDK */ - -/* FT32 HAL & SDK Drivers */ - -/* end of FT32 HAL & SDK Drivers */ /* end of HAL & SDK Drivers */ /* sensors drivers */ diff --git a/bsp/rockchip/rk3500/.ci/attachconfig/ci.attachconfig.yml b/bsp/rockchip/rk3500/.ci/attachconfig/ci.attachconfig.yml index 527ba38637ed..faea951a9977 100644 --- a/bsp/rockchip/rk3500/.ci/attachconfig/ci.attachconfig.yml +++ b/bsp/rockchip/rk3500/.ci/attachconfig/ci.attachconfig.yml @@ -38,11 +38,30 @@ devices.dm.all: - CONFIG_RT_USING_DMA=y - CONFIG_RT_SPI_ROCKCHIP=y - CONFIG_RT_SPI_ROCKCHIP_SFC=y + - CONFIG_RT_USING_AUDIO=y + - CONFIG_RT_AUDIO_ROCKCHIP=y + - CONFIG_RT_AUDIO_ROCKCHIP_I2S_TDM=y + - CONFIG_RT_AUDIO_ROCKCHIP_CODEC=y + - CONFIG_RT_AUDIO_ROCKCHIP_CODEC_RK817=y + - CONFIG_RT_AUDIO_ROCKCHIP_CARD=y + - CONFIG_RT_USING_GRAPHIC=y + - CONFIG_RT_GRAPHIC_FB_VOP1=y + - CONFIG_RT_GRAPHIC_FB_VOP2=y + - CONFIG_RT_GRAPHIC_FB_VOPL=y + - CONFIG_RT_GRAPHIC_DISPLAY_ROCKCHIP=y + - CONFIG_RT_GRAPHIC_CONNECTOR_DSI=y + - CONFIG_RT_GRAPHIC_CONNECTOR_DSI2=y + - CONFIG_RT_GRAPHIC_CONNECTOR_HDMI=y + - CONFIG_RT_GRAPHIC_PANEL_SIMPLE=y + - CONFIG_RT_GRAPHIC_LOGO_RADXA_CLUT224=y + - CONFIG_RT_GRAPHIC_LOGO_ROCKCHIP_CLUT224=y - CONFIG_RT_USING_WDT=y - CONFIG_RT_WDT_RK8XX=y - CONFIG_RT_USING_HWCRYPTO=y - CONFIG_RT_HWCRYPTO_USING_RNG=y - CONFIG_RT_HWCRYPTO_RNG_ROCKCHIP=y + - CONFIG_RT_HWCRYPTO_USING_MD5=y + - CONFIG_RT_HWCRYPTO_CRYPTO_ROCKCHIP_V2=y - CONFIG_RT_USING_INPUT=y - CONFIG_RT_INPUT_MISC=y - CONFIG_RT_INPUT_MISC_PWRKEY_RK8XX=y @@ -53,6 +72,9 @@ devices.dm.all: - CONFIG_RT_USING_PHYE=y - CONFIG_RT_PHYE_ROCKCHIP_NANENG_COMBO=y - CONFIG_RT_PHYE_ROCKCHIP_SNPS_PCIE3=y + - CONFIG_RT_PHYE_ROCKCHIP_INNO_USB2=y + - CONFIG_RT_PHYE_ROCKCHIP_MIPI_DCPHY=y + - CONFIG_RT_PHYE_ROCKCHIP_INNO_DSIDPHY=y - CONFIG_RT_MFD_RK8XX_I2C=y - CONFIG_RT_MFD_RK8XX_SPI=y - CONFIG_RT_REGULATOR_RK8XX=y @@ -62,8 +84,21 @@ devices.dm.all: - CONFIG_RT_USING_NVMEM=y - CONFIG_RT_NVMEM_ROCKCHIP_OTP=y - CONFIG_RT_USING_PCI=y + - CONFIG_RT_PCI_ENDPOINT=y + - CONFIG_RT_PCIE_ROCKCHIP=y + - CONFIG_RT_PCIE_ROCKCHIP_EP=y - CONFIG_RT_PCI_DW=y - CONFIG_RT_PCI_DW_ROCKCHIP=y + - CONFIG_RT_USING_PHY_V2=y + - CONFIG_RT_ETHERNET_DWMAC=y + - CONFIG_RT_ETHERNET_DWMAC_ROCKCHIP=y + - CONFIG_RT_SDIO_SDHCI_DWCMSHC=y + - CONFIG_RT_SDIO_SDHCI_DWCMSHC_ROCKCHIP=y + - CONFIG_RT_USING_BLK=y + - CONFIG_RT_USING_SCSI=y + - CONFIG_RT_SCSI_SD=y + - CONFIG_RT_USING_UFS=y + - CONFIG_RT_UFS_ROCKCHIP=y - CONFIG_RT_PIN_ROCKCHIP=y - CONFIG_RT_PINCTRL_ROCKCHIP_RK8XX=y - CONFIG_RT_PINCTRL_ROCKCHIP=y @@ -78,4 +113,6 @@ devices.dm.all: - CONFIG_RT_SOC_ROCKCHIP_FIQ_DEBUGGER=y - CONFIG_RT_SOC_ROCKCHIP_GRF=y - CONFIG_RT_SOC_ROCKCHIP_HW_DECOMPRESS=y + - CONFIG_RT_ROCKCHIP_JPEG_DEC=y + - CONFIG_RT_ROCKCHIP_RGA2=y - CONFIG_RT_SOC_ROCKCHIP_IODOMAIN=y diff --git a/bsp/rockchip/rk3500/.config b/bsp/rockchip/rk3500/.config index cff7bafda2bf..5d772ca7ebbb 100644 --- a/bsp/rockchip/rk3500/.config +++ b/bsp/rockchip/rk3500/.config @@ -141,7 +141,7 @@ CONFIG_RT_CPU_USAGE_CALC_INTERVAL_MS=200 # end of kservice options CONFIG_RT_USING_DEBUG=y -# CONFIG_RT_DEBUGING_ASSERT is not set +CONFIG_RT_DEBUGING_ASSERT=y CONFIG_RT_DEBUGING_COLOR=y # CONFIG_RT_DEBUGING_CONTEXT is not set # CONFIG_RT_DEBUGING_AUTO_INIT is not set @@ -164,7 +164,7 @@ CONFIG_RT_USING_MESSAGEQUEUE_PRIORITY=y # # Memory Management # -# CONFIG_RT_USING_MEMPOOL is not set +CONFIG_RT_USING_MEMPOOL=y # CONFIG_RT_USING_SMALL_MEM is not set CONFIG_RT_USING_SLAB=y CONFIG_RT_USING_MEMHEAP=y @@ -204,6 +204,7 @@ CONFIG_ARCH_HAVE_EFFICIENT_UNALIGNED_ACCESS=y CONFIG_ARCH_USING_GENERIC_CPUID=y CONFIG_ARCH_HEAP_SIZE=0x4000000 CONFIG_ARCH_INIT_PAGE_SIZE=0x200000 +# CONFIG_ARCH_USING_CPUIDLE is not set # end of AArch64 Architecture Configuration CONFIG_ARCH_CPU_64BIT=y @@ -331,9 +332,19 @@ CONFIG_RT_CANSND_MSG_TIMEOUT=100 CONFIG_RT_CAN_NB_TX_FIFO_SIZE=256 # CONFIG_RT_CAN_MALLOC_NB_TX_BUFFER is not set CONFIG_RT_CAN_CANFD_ROCKCHIP=y +CONFIG_RT_USING_ADC=y +# CONFIG_RT_USING_ADC_V2 is not set +CONFIG_RT_USING_ADC_V1=y +CONFIG_RT_ADC_ROCKCHIP_SARADC=y CONFIG_RT_USING_CLOCK_TIME=y +# CONFIG_RT_USING_CLOCK_TIMER_TRIGGER is not set CONFIG_RT_CLOCK_TIME_ARM_ARCH=y CONFIG_RT_CLOCK_TIMER_ROCKCHIP=y +CONFIG_RT_USING_ETHERNET=y +# CONFIG_RT_ETHERNET_CADENCE is not set +CONFIG_RT_ETHERNET_DWMAC=y +CONFIG_RT_ETHERNET_DWMAC_PTP=y +CONFIG_RT_ETHERNET_DWMAC_ROCKCHIP=y CONFIG_RT_USING_I2C=y # CONFIG_RT_I2C_DEBUG is not set CONFIG_RT_USING_I2C_BITOPS=y @@ -341,9 +352,8 @@ CONFIG_RT_USING_I2C_BITOPS=y # CONFIG_RT_USING_SOFT_I2C is not set CONFIG_RT_I2C_RK3X=y # CONFIG_RT_USING_PHY is not set -# CONFIG_RT_USING_PHY_V2 is not set -CONFIG_RT_USING_ADC=y -CONFIG_RT_ADC_ROCKCHIP_SARADC=y +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 @@ -363,7 +373,7 @@ 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=y +# 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 @@ -376,16 +386,18 @@ CONFIG_RT_RTC_RK8XX=y # CONFIG_RT_RTC_RK_TIMER is not set CONFIG_RT_USING_SDIO=y CONFIG_RT_SDIO_STACK_SIZE=16384 -CONFIG_RT_SDIO_THREAD_PRIORITY=15 +CONFIG_RT_SDIO_THREAD_PRIORITY=10 CONFIG_RT_MMCSD_STACK_SIZE=16384 -CONFIG_RT_MMCSD_THREAD_PRIORITY=22 +CONFIG_RT_MMCSD_THREAD_PRIORITY=10 CONFIG_RT_MMCSD_MAX_PARTITION=16 # CONFIG_RT_SDIO_DEBUG is not set -# CONFIG_RT_USING_SDHCI is not set +CONFIG_RT_USING_SDHCI=y # CONFIG_RT_SDIO_SDHCI_PCI is not set CONFIG_RT_SDIO_DW_MMC=y # CONFIG_RT_SDIO_DW_MMC_PCI is not set +CONFIG_RT_SDIO_SDHCI_DWCMSHC=y CONFIG_RT_SDIO_DW_MMC_ROCKCHIP=y +CONFIG_RT_SDIO_SDHCI_DWCMSHC_ROCKCHIP=y CONFIG_RT_USING_SPI=y CONFIG_RT_USING_SPI_ISR=y # CONFIG_RT_USING_SPI_BITOPS is not set @@ -406,27 +418,80 @@ CONFIG_RT_USING_WDT=y CONFIG_RT_WDT_DW=y # CONFIG_RT_WDT_I6300ESB is not set CONFIG_RT_WDT_RK8XX=y -# CONFIG_RT_USING_AUDIO is not set +CONFIG_RT_USING_AUDIO=y +CONFIG_RT_AUDIO_REPLAY_MP_BLOCK_SIZE=4096 +CONFIG_RT_AUDIO_REPLAY_MP_BLOCK_COUNT=2 +CONFIG_RT_AUDIO_RECORD_PIPE_SIZE=2048 +# CONFIG_RT_AUDIO_INTEL_HDA is not set +CONFIG_RT_AUDIO_ROCKCHIP=y +CONFIG_RT_AUDIO_ROCKCHIP_I2S_TDM=y +CONFIG_RT_AUDIO_ROCKCHIP_CODEC=y +CONFIG_RT_AUDIO_ROCKCHIP_CODEC_RK817=y +CONFIG_RT_AUDIO_ROCKCHIP_CARD=y # CONFIG_RT_USING_SENSOR is not set -# CONFIG_RT_USING_TOUCH is not set -# CONFIG_RT_USING_GRAPHIC is not set +CONFIG_RT_USING_TOUCH=y +# CONFIG_RT_TOUCH_PIN_IRQ 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_VOP2=y +CONFIG_RT_GRAPHIC_FB_VOPL=y +CONFIG_RT_GRAPHIC_FB_VOP1=y +CONFIG_RT_GRAPHIC_DISPLAY_ROCKCHIP=y +CONFIG_RT_GRAPHIC_CONNECTOR_DSI=y +CONFIG_RT_GRAPHIC_CONNECTOR_HDMI=y +CONFIG_RT_GRAPHIC_BACKLIGHT_HINT=y +CONFIG_RT_GRAPHIC_PANEL_SIMPLE=y +CONFIG_RT_GRAPHIC_INPUT_TOUCH_HINT=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_RADXA_CLUT224=y +# CONFIG_RT_GRAPHIC_LOGO_ROCKCHIP_CLUT224 is not set +CONFIG_RT_GRAPHIC_LOGO_RADXA_CLUT224_PATH="../dm/graphic/logo/logo-radxa-clut224.ppm" CONFIG_RT_USING_HWCRYPTO=y -CONFIG_RT_HWCRYPTO_DEFAULT_NAME="hwcryto" +CONFIG_RT_HWCRYPTO_DEFAULT_NAME="hwcrypto" 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 is not set -# CONFIG_RT_HWCRYPTO_USING_DES is not set -# CONFIG_RT_HWCRYPTO_USING_3DES is not set +CONFIG_RT_HWCRYPTO_USING_GCM=y +CONFIG_RT_HWCRYPTO_USING_AES=y +CONFIG_RT_HWCRYPTO_USING_AES_ECB=y +# CONFIG_RT_HWCRYPTO_USING_AES_CBC is not set +# 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=y +CONFIG_RT_HWCRYPTO_USING_DES_ECB=y +# CONFIG_RT_HWCRYPTO_USING_DES_CBC is not set +CONFIG_RT_HWCRYPTO_USING_3DES=y +CONFIG_RT_HWCRYPTO_USING_3DES_ECB=y +# CONFIG_RT_HWCRYPTO_USING_3DES_CBC 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_MD5=y +CONFIG_RT_HWCRYPTO_USING_SHA1=y +CONFIG_RT_HWCRYPTO_USING_SHA2=y +# CONFIG_RT_HWCRYPTO_USING_SHA2_224 is not set +CONFIG_RT_HWCRYPTO_USING_SHA2_256=y +# CONFIG_RT_HWCRYPTO_USING_SHA2_384 is not set +# CONFIG_RT_HWCRYPTO_USING_SHA2_512 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_USING_BIGNUM=y +CONFIG_RT_HWCRYPTO_USING_BIGNUM_EXPTMOD=y +# CONFIG_RT_HWCRYPTO_USING_BIGNUM_MULMOD is not set +# CONFIG_RT_HWCRYPTO_USING_BIGNUM_MUL is not set +# CONFIG_RT_HWCRYPTO_USING_BIGNUM_ADD is not set +# CONFIG_RT_HWCRYPTO_USING_BIGNUM_SUB is not set CONFIG_RT_HWCRYPTO_RNG_ROCKCHIP=y +CONFIG_RT_HWCRYPTO_CRYPTO_ROCKCHIP_V2=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 @@ -439,7 +504,9 @@ CONFIG_RT_INPUT_POWER=y CONFIG_RT_INPUT_MISC=y # CONFIG_RT_INPUT_MISC_BUTTON_E3X0 is not set CONFIG_RT_INPUT_MISC_PWRKEY_RK8XX=y -# CONFIG_RT_INPUT_TOUCHSCREEN is not set +CONFIG_RT_INPUT_TOUCHSCREEN=y +# CONFIG_RT_INPUT_TOUCHSCREEN_ADS7846 is not set +CONFIG_RT_INPUT_TOUCHSCREEN_GOODIX=y CONFIG_RT_USING_MBOX=y CONFIG_RT_MBOX_PIC=y CONFIG_RT_MBOX_ROCKCHIP=y @@ -450,7 +517,13 @@ CONFIG_RT_USING_PHYE=y # CONFIG_RT_PHYE_GENERIC_USB is not set CONFIG_RT_PHYE_ROCKCHIP_NANENG_COMBO=y CONFIG_RT_PHYE_ROCKCHIP_SNPS_PCIE3=y -# CONFIG_RT_USING_ATA is not set +# CONFIG_RT_PHYE_ROCKCHIP_INNO_USB2 is not set +# CONFIG_RT_PHYE_ROCKCHIP_MIPI_DCPHY is not set +CONFIG_RT_PHYE_ROCKCHIP_INNO_DSIDPHY=y +CONFIG_RT_USING_ATA=y +CONFIG_RT_ATA_AHCI=y +CONFIG_RT_ATA_AHCI_DW=y +# CONFIG_RT_ATA_AHCI_PCI is not set CONFIG_RT_USING_NVME=y CONFIG_RT_USING_NVME_IO_QUEUE=4 CONFIG_RT_NVME_PCI=y @@ -463,12 +536,18 @@ CONFIG_RT_BLK_PARTITION_DFS=y CONFIG_RT_BLK_PARTITION_EFI=y # end of Partition Types -# CONFIG_RT_USING_SCSI is not set +CONFIG_RT_USING_SCSI=y +CONFIG_RT_SCSI_SD=y +CONFIG_RT_SCSI_CDROM=y +CONFIG_RT_USING_UFS=y +# CONFIG_RT_UFS_PCI is not set +CONFIG_RT_UFS_ROCKCHIP=y CONFIG_RT_USING_FIRMWARE=y # CONFIG_RT_FIRMWARE_QEMU_FW_CFG is not set CONFIG_RT_FIRMWARE_ARM_SCMI=y CONFIG_RT_FIRMWARE_ARM_SCMI_TRANSPORT_MAILBOX=y CONFIG_RT_FIRMWARE_ARM_SCMI_TRANSPORT_SMC=y +# 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 @@ -493,6 +572,7 @@ CONFIG_RT_USING_REGULATOR=y CONFIG_RT_REGULATOR_FAN53555=y CONFIG_RT_REGULATOR_FIXED=y CONFIG_RT_REGULATOR_GPIO=y +# CONFIG_RT_REGULATOR_PWM is not set CONFIG_RT_REGULATOR_SCMI=y CONFIG_RT_REGULATOR_RK8XX=y CONFIG_RT_USING_RESET=y @@ -520,6 +600,7 @@ CONFIG_RT_THERMAL_ROCKCHIP_TSADC=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 is not set CONFIG_RT_USING_NVMEM=y @@ -532,6 +613,7 @@ CONFIG_RT_MFD_SYSCON=y CONFIG_RT_MFD_RK8XX=y CONFIG_RT_MFD_RK8XX_I2C=y CONFIG_RT_MFD_RK8XX_SPI=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 @@ -550,6 +632,8 @@ CONFIG_RT_PCI_CACHE_LINE_SIZE=8 CONFIG_RT_PCI_DW=y CONFIG_RT_PCI_DW_HOST=y CONFIG_RT_PCI_DW_EP=y +# CONFIG_RT_PCIE_ROCKCHIP is not set +# CONFIG_RT_PCIE_ROCKCHIP_EP is not set CONFIG_RT_PCI_DW_ROCKCHIP=y CONFIG_RT_USING_PIC=y # CONFIG_RT_USING_PIC_STATISTICS is not set @@ -586,6 +670,8 @@ CONFIG_RT_CLK_ROCKCHIP_RK3588=y CONFIG_RT_SOC_ROCKCHIP_FIQ_DEBUGGER=y CONFIG_RT_SOC_ROCKCHIP_GRF=y CONFIG_RT_SOC_ROCKCHIP_HW_DECOMPRESS=y +CONFIG_RT_ROCKCHIP_JPEG_DEC=y +CONFIG_RT_ROCKCHIP_RGA2=y CONFIG_RT_SOC_ROCKCHIP_IODOMAIN=y # end of SoC (System on Chip) Drivers # end of Device Drivers @@ -836,6 +922,7 @@ CONFIG_RT_USING_UTESTCASES=y # CONFIG_RT_UTEST_HOOKLIST is not set # CONFIG_RT_UTEST_MTSAFE_KPRINT is not set # CONFIG_RT_UTEST_SCHEDULER is not set +# CONFIG_RT_UTEST_MEMPOOL is not set # CONFIG_RT_UTEST_SYS_PERF is not set # CONFIG_RT_UTEST_TC_USING_KLIBC is not set @@ -858,6 +945,7 @@ CONFIG_RT_USING_UTESTCASES=y # Drivers # # CONFIG_RT_UTEST_DRIVERS_CORE is not set +# CONFIG_RT_UTEST_USING_AUDIO_DRIVER is not set # # IPC Test @@ -866,6 +954,12 @@ CONFIG_RT_USING_UTESTCASES=y # CONFIG_RT_UTEST_WORKQUEUE is not set # end of IPC Test +# +# Pin Test +# +# CONFIG_RT_UTEST_PIN is not set +# end of Pin Test + # # Serial Test # @@ -877,6 +971,13 @@ CONFIG_RT_USING_UTESTCASES=y # CONFIG_RT_UTEST_SMP_CALL_FUNC=y # end of SMP-Call Test + +# +# SPI Test +# +# CONFIG_RT_UTEST_SPI_LOOPBACK is not set +# CONFIG_RT_UTEST_SPI_FLASH is not set +# end of SPI Test # end of Drivers # @@ -901,6 +1002,7 @@ CONFIG_RT_UTEST_SMP_CALL_FUNC=y # LWP Testcase # # CONFIG_RT_UTEST_LWP is not set +# CONFIG_RT_UTEST_LWP_TTY_PTMX is not set # end of LWP Testcase # diff --git a/bsp/rockchip/rk3500/applications/audio.c b/bsp/rockchip/rk3500/applications/audio.c new file mode 100644 index 000000000000..c7652fbdc182 --- /dev/null +++ b/bsp/rockchip/rk3500/applications/audio.c @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2006-2026, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2026-07-22 GuEe-GUI first version + */ + +#include +#include + +#if defined(RT_USING_AUDIO) && defined(RT_AUDIO_ROCKCHIP) && defined(RT_USING_FINSH) +#include +#include + +#define AUDIO_TEST_DEVICE "rockchip-hdmi0" +#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 + +/* One period at 48 kHz produces a 1 kHz sine wave. */ +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; + char *end; + unsigned long value; + 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 = AUDIO_TEST_DEVICE; + struct rt_audio_caps caps = { 0 }; + + if (argc > 3) + { + rt_kprintf("usage: audio_test [device] [seconds]\n"); + return -RT_EINVAL; + } + + if (argc > 1) + { + name = argv[1]; + } + if (argc > 2) + { + value = strtoul(argv[2], &end, 0); + if (*end || !value || value > AUDIO_TEST_MAX_SECONDS) + { + rt_kprintf("seconds must be 1..%u\n", AUDIO_TEST_MAX_SECONDS); + return -RT_EINVAL; + } + seconds = value; + } + + 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; + } + + ret = rt_device_open(device, RT_DEVICE_OFLAG_WRONLY); + if (ret) + { + 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; + + ret = rt_device_control(device, AUDIO_CTL_CONFIGURE, &caps); + if (ret) + { + rt_kprintf("configure %s failed: %s\n", name, rt_strerror(ret)); + goto _close; + } + + remaining = (rt_size_t)seconds * AUDIO_TEST_RATE * + AUDIO_TEST_CHANNELS * sizeof(*buffer); + rt_kprintf("playing 1 kHz stereo 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); + + /* Interleaved stereo: send the same sample to left and right. */ + for (rt_size_t i = 0; i < samples; i += AUDIO_TEST_CHANNELS) + { + 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; + +_close: + rt_device_close(device); +_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_ROCKCHIP && RT_USING_FINSH */ diff --git a/bsp/rockchip/rk3500/applications/jpegd.c b/bsp/rockchip/rk3500/applications/jpegd.c new file mode 100644 index 000000000000..a6dd6b895bfc --- /dev/null +++ b/bsp/rockchip/rk3500/applications/jpegd.c @@ -0,0 +1,704 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-11-21 GuEe-GUI first version + */ + +#include +#include +#include + +#include + +#if defined(RT_USING_FINSH) && defined(RT_USING_GRAPHIC) && defined(RT_ROCKCHIP_JPEG_DEC) +#include +#include +#include + +#define JPEGD_TABLE_SIZE 1280 +#define JPEGD_MINCODE_OFFSET 384 +#define JPEGD_VALUE_OFFSET 704 +#define JPEGD_ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1)) + +#define JPEGD_SCALE_HALF 1 +#define JPEGD_OUTPUT_RGB888 1 + +#define JPEGD_INT_TIMEOUT RT_BIT(2) +#define JPEGD_INT_BUF_EMPTY RT_BIT(3) +#define JPEGD_SYS_SCALE(x) ((x) << 12) +#define JPEGD_SYS_FILL_DOWN RT_BIT(24) +#define JPEGD_SYS_FILL_RIGHT RT_BIT(25) +#define JPEGD_SYS_OUTPUT(x) ((x) << 27) +#define JPEGD_SYS_FULL_RANGE RT_BIT(31) + +#define JPEGD_TABLE_QUANT 9 +#define JPEGD_TABLE_MINCODE 10 +#define JPEGD_TABLE_VALUE 11 +#define JPEGD_STREAM_BASE 12 +#define JPEGD_OUTPUT_BASE 13 + +struct jpegd_huff +{ + rt_uint8_t bits[16]; + rt_uint8_t vals[162]; + rt_uint16_t count; +}; + +struct jpegd_image +{ + rt_uint8_t *data; + rt_size_t size; + rt_uint16_t quant[4][64]; + struct jpegd_huff dc[2]; + struct jpegd_huff ac[2]; + rt_uint8_t comp_id[3]; + rt_uint8_t h[3], v[3], qsel[3], dcsel[3], acsel[3]; + rt_uint8_t components, qtables, htable_mask, mode, fill_right, fill_bottom; + rt_uint16_t width, height, restart; + rt_size_t scan_offset; +}; + +static const rt_uint8_t zigzag[64] = +{ + 0, 1, 8, 16, 9, 2, 3, 10, + 17, 24, 32, 25, 18, 11, 4, 5, + 12, 19, 26, 33, 40, 48, 41, 34, + 27, 20, 13, 6, 7, 14, 21, 28, + 35, 42, 49, 56, 57, 50, 43, 36, + 29, 22, 15, 23, 30, 37, 44, 51, + 58, 59, 52, 45, 38, 31, 39, 46, + 53, 60, 61, 54, 47, 55, 62, 63, +}; + +/* JPEG stores all multi-byte fields in big-endian order. */ + +static rt_uint16_t get_be16(const rt_uint8_t *p) +{ + return ((rt_uint16_t)p[0] << 8) | p[1]; +} + +static rt_err_t parse_dqt(struct jpegd_image *jpg, const rt_uint8_t *p, rt_size_t len) +{ + while (len) + { + rt_uint8_t precision, id; + int i; + + precision = *p >> 4; + id = *p++ & 0xf; + --len; + if (precision > 1 || id > 3 || len < (rt_size_t)(64 << precision)) + { + return -RT_EINVAL; + } + + for (i = 0; i < 64; ++i) + { + jpg->quant[id][i] = precision ? get_be16(p + i * 2) : p[i]; + } + p += 64 << precision; + len -= 64 << precision; + ++jpg->qtables; + } + return RT_EOK; +} + +/* Parse the baseline Huffman tables used later to build the hardware tables. */ + +static rt_err_t parse_dht(struct jpegd_image *jpg, const rt_uint8_t *p, rt_size_t len) +{ + while (len) + { + struct jpegd_huff *table; + rt_uint8_t type, id; + rt_uint16_t count = 0; + int i; + + if (len < 17) + { + return -RT_EINVAL; + } + + type = *p >> 4; + id = *p++ & 0xf; + --len; + if (type > 1 || id > 1) + { + return -RT_ENOSYS; + } + + table = type ? &jpg->ac[id] : &jpg->dc[id]; + for (i = 0; i < 16; ++i) + { + count += table->bits[i] = p[i]; + } + + p += 16; + len -= 16; + if (count > (type ? 162 : 12) || len < count) + { + return -RT_EINVAL; + } + + rt_memcpy(table->vals, p, count); + table->count = count; + jpg->htable_mask |= 1U << (id * 2 + type); + p += count; + len -= count; + } + return RT_EOK; +} + +static rt_err_t parse_sof(struct jpegd_image *jpg, const rt_uint8_t *p, rt_size_t len) +{ + int i; + + if (len < 6 || p[0] != 8 || (p[5] != 1 && p[5] != 3) || len != 6U + p[5] * 3U) + { + return -RT_ENOSYS; + } + + jpg->height = get_be16(p + 1); + jpg->width = get_be16(p + 3); + jpg->components = p[5]; + if (!jpg->width || !jpg->height) + { + return -RT_EINVAL; + } + + for (i = 0; i < jpg->components; ++i) + { + jpg->comp_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->mode = 0; + } + else if (jpg->h[0] == 2 && jpg->v[0] == 2) + { + jpg->mode = 2; + } + else if (jpg->h[0] == 2 && jpg->v[0] == 1) + { + jpg->mode = 3; + } + else if (jpg->h[0] == 1 && jpg->v[0] == 1) + { + jpg->mode = 5; + } + else if (jpg->h[0] == 1 && jpg->v[0] == 2) + { + jpg->mode = 4; + } + else if (jpg->h[0] == 4 && jpg->v[0] == 1) + { + jpg->mode = 1; + } + else + { + return -RT_ENOSYS; + } + + if (jpg->components == 3 && + (jpg->h[1] != 1 || jpg->v[1] != 1 || jpg->h[2] != 1 || jpg->v[2] != 1)) + { + return -RT_ENOSYS; + } + + if ((jpg->mode == 3 || jpg->mode == 1 || jpg->mode == 5) && + (jpg->height & 15) && (jpg->height & 15) <= 8) + { + jpg->fill_bottom = 1; + } + + if ((jpg->mode == 4 || jpg->mode == 5 || jpg->mode == 0) && + (jpg->width & 15) && (jpg->width & 15) <= 8) + { + jpg->fill_right = 1; + } + + return RT_EOK; +} + +/* The RKV JPEG decoder accepts a single baseline sequential scan. */ + +static rt_err_t parse_sos(struct jpegd_image *jpg, const rt_uint8_t *p, rt_size_t len) +{ + int i, j; + + if (len < 4 || p[0] != jpg->components || len != 4U + p[0] * 2U) + { + return -RT_ENOSYS; + } + + for (i = 0; i < p[0]; ++i) + { + for (j = 0; j < jpg->components && jpg->comp_id[j] != p[1 + i * 2]; ++j) + { + } + + if (j == jpg->components || (p[2 + i * 2] >> 4) > 1 || (p[2 + i * 2] & 0xf) > 1) + { + return -RT_ENOSYS; + } + + jpg->dcsel[i] = p[2 + i * 2] >> 4; + jpg->acsel[i] = p[2 + i * 2] & 0xf; + } + if (p[len - 3] != 0 || p[len - 2] != 63 || p[len - 1] != 0) + { + return -RT_ENOSYS; + } + + return RT_EOK; +} + +static rt_err_t jpegd_parse(struct jpegd_image *jpg) +{ + rt_size_t pos = 2; + rt_bool_t sof = RT_FALSE; + + if (jpg->size < 4 || get_be16(jpg->data) != 0xffd8) + { + return -RT_EINVAL; + } + + while (pos + 1 < jpg->size) + { + rt_uint8_t marker; + rt_uint16_t section_len; + 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_len = get_be16(jpg->data + pos); + if (section_len < 2 || pos + section_len > jpg->size) + { + return -RT_EINVAL; + } + + section = jpg->data + pos + 2; + switch (marker) + { + case 0xc0: + err = parse_sof(jpg, section, section_len - 2); + sof = err == RT_EOK; + break; + case 0xc4: + err = parse_dht(jpg, section, section_len - 2); + break; + case 0xdb: + err = parse_dqt(jpg, section, section_len - 2); + break; + case 0xdd: + if (section_len != 4) + { + err = -RT_EINVAL; + } + else + { + jpg->restart = get_be16(section); + } + break; + case 0xda: + if (!sof) + { + return -RT_EINVAL; + } + err = parse_sos(jpg, section, section_len - 2); + jpg->scan_offset = pos + section_len; + return err; + default: + if (marker >= 0xc1 && marker <= 0xcf && marker != 0xc4 && marker != 0xc8 && marker != 0xcc) + { + return -RT_ENOSYS; + } + break; + } + if (err) + { + return err; + } + + pos += section_len; + } + return -RT_EINVAL; +} + +/* Convert JPEG canonical Huffman tables into the RKV decoder table layout. */ + +static void make_huffman_table(rt_uint8_t *table_mem, struct jpegd_image *jpg) +{ + rt_uint16_t *minp = (rt_uint16_t *)(table_mem + JPEGD_MINCODE_OFFSET); + rt_uint8_t *valp = table_mem + JPEGD_VALUE_OFFSET; + int component, type, i; + + for (component = 0; component < jpg->components; ++component) + { + for (type = 0; type < 2; ++type) + { + struct jpegd_huff *h = type ? &jpg->ac[jpg->acsel[component]] : + &jpg->dc[jpg->dcsel[component]]; + rt_uint16_t mincode[16], addr[16]; + rt_uint16_t code = 0, acc = 0; + + for (i = 0; i < 16; ++i) + { + mincode[i] = code; + code += h->bits[i]; + acc += h->bits[i]; + addr[i] = acc; + code <<= 1; + } + mincode[0] = mincode[15] + (h->bits[15] ? h->bits[15] - 1 : 0); + for (i = 0; i < 16; ++i) + { + *minp++ = mincode[i]; + } + for (i = 0; i < 8; ++i) + { + *minp++ = addr[i * 2] | (addr[i * 2 + 1] << 8); + } + } + rt_memcpy(valp, jpg->dc[jpg->dcsel[component]].vals, 12); + rt_memcpy(valp + 16, jpg->ac[jpg->acsel[component]].vals, 162); + valp += 192; + } +} + +static void make_quant_table(rt_uint8_t *table_mem, struct jpegd_image *jpg) +{ + rt_uint16_t *q = (rt_uint16_t *)table_mem; + int c, i; + + for (c = 0; c < jpg->components; ++c) + { + for (i = 0; i < 64; ++i) + { + q[c * 64 + zigzag[i]] = jpg->quant[jpg->qsel[c]][i]; + } + } +} + +/* Convert the decoder's RGB888 output to the active framebuffer format. */ + +static rt_err_t pixel_convert(rt_uint8_t fmt, const rt_uint8_t *rgb, void *dst) +{ + rt_uint8_t r = rgb[0], g = rgb[1], b = rgb[2]; + + switch (fmt) + { + 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: + ((rt_uint8_t *)dst)[0] = r; + ((rt_uint8_t *)dst)[1] = g; + ((rt_uint8_t *)dst)[2] = b; + break; + case RTGRAPHIC_PIXEL_FORMAT_BGR888: + ((rt_uint8_t *)dst)[0] = b; + ((rt_uint8_t *)dst)[1] = g; + ((rt_uint8_t *)dst)[2] = r; + break; + case RTGRAPHIC_PIXEL_FORMAT_ARGB888: + *(rt_uint32_t *)dst = 0xff000000U | r << 16 | g << 8 | b; + break; + case RTGRAPHIC_PIXEL_FORMAT_ABGR888: + *(rt_uint32_t *)dst = 0xff000000U | b << 16 | g << 8 | r; + break; + default: + return -RT_ENOSYS; + } + return RT_EOK; +} + +static rt_err_t show_rgb(rt_uint8_t *rgb, int width, int height, int rgb_stride, + const char *fb_name) +{ + struct rt_device_graphic_info info; + struct rt_device_rect_info rect; + rt_device_t fb = rt_device_find(fb_name); + struct rt_graphic_device *graphic; + rt_bool_t restore_auto_update; + rt_uint8_t *screen, *dst, *src; + int x0, y0, copy_w, copy_h, x, y, bpp; + rt_err_t err; + + if (!fb) + { + return -RT_EINVAL; + } + + graphic = rt_container_of(fb, struct rt_graphic_device, parent); + restore_auto_update = graphic->update_timer != RT_NULL; + if ((err = rt_device_open(fb, 0))) + { + return err; + } + if ((err = rt_device_control(fb, RTGRAPHIC_CTRL_GET_INFO, &info))) + { + goto _out; + } + if (!info.framebuffer || !(bpp = info.bits_per_pixel / 8)) + { + err = -RT_EINVAL; + goto _out; + } + if ((err = rt_device_control(fb, RTGRAPHIC_CTRL_POWERON, RT_NULL))) + { + goto _out; + } + + screen = rt_malloc((rt_size_t)info.pitch * info.height); + if (!screen) + { + err = -RT_ENOMEM; + goto _out; + } + if (restore_auto_update) + { + rt_graphic_device_update_auto(graphic, 0); + } + + rt_memset(screen, 0, (rt_size_t)info.pitch * info.height); + copy_w = rt_min_t(int, width, info.width); + copy_h = rt_min_t(int, height, info.height); + x0 = (info.width - copy_w) / 2; + y0 = (info.height - copy_h) / 2; + src = rgb + (height - copy_h) / 2 * rgb_stride + + (width - copy_w) / 2 * 3; + for (y = 0; y < copy_h; ++y) + { + dst = screen + (y0 + y) * info.pitch + x0 * bpp; + for (x = 0; x < copy_w; ++x) + { + if ((err = pixel_convert(info.pixel_format, src + x * 3, dst + x * bpp))) + { + break; + } + } + if (err) + { + break; + } + src += rgb_stride; + } + if (!err) + { + rt_memcpy(info.framebuffer, screen, (rt_size_t)info.pitch * info.height); + rect.x = 0; + rect.y = 0; + rect.width = info.width; + rect.height = info.height; + rt_device_control(fb, RTGRAPHIC_CTRL_RECT_UPDATE, &rect); + rt_device_control(fb, RTGRAPHIC_CTRL_WAIT_VSYNC, RT_NULL); + } + rt_free(screen); + if (restore_auto_update) + { + rt_graphic_device_update_auto(graphic, RT_GRAPHIC_UPDATE_MS); + } + +_out: + rt_device_close(fb); + return err; +} + +/* Decode one baseline JPEG with jpegd0 and display the half-sized result. */ + +static int jpegd_show(int argc, char **argv) +{ + const char *path = argc > 1 ? argv[1] : "/arm-boot.jpg"; + const char *fb_name = argc > 2 ? argv[2] : "fb0"; + struct jpegd_image jpg = { 0 }; + struct jpegd_req req = { 0 }; + rt_device_t jpegd = rt_device_find("jpegd0"); + rt_uint8_t *stream = RT_NULL, *tables = RT_NULL, *output = RT_NULL; + rt_ubase_t stream_dma = 0, tables_dma = 0, output_dma = 0; + rt_size_t stream_size = 0, output_size = 0; + rt_uint32_t stride, out_height, display_width, display_height; + rt_uint32_t table_sel, htable_sel, htable_mincode_len; + rt_size_t hw_scan_offset, hw_stream_size; + off_t file_size; + int fd = -1; + rt_err_t err = -RT_ERROR; + + if (!jpegd) + { + rt_kprintf("jpegd0 not found\n"); + return -RT_EINVAL; + } + + fd = open(path, O_RDONLY, 0); + if (fd < 0) + { + rt_kprintf("open %s failed\n", path); + return -RT_EIO; + } + + file_size = lseek(fd, 0, SEEK_END); + if (file_size <= 0 || lseek(fd, 0, SEEK_SET) < 0) + { + err = -RT_EIO; + goto _out; + } + + jpg.size = file_size; + stream_size = JPEGD_ALIGN(jpg.size, 16); + stream = rt_dma_alloc_coherent(jpegd, stream_size, &stream_dma); + if (!stream) + { + err = -RT_ENOMEM; + goto _out; + } + if (read(fd, stream, jpg.size) != (int)jpg.size) + { + err = -RT_EIO; + goto _out; + } + + rt_memset(stream + jpg.size, 0xff, stream_size - jpg.size); + jpg.data = stream; + if ((err = jpegd_parse(&jpg))) + { + rt_kprintf("unsupported/invalid baseline JPEG: %d\n", err); + goto _out; + } + if (!jpg.htable_mask) + { + rt_kprintf("JPEG without DHT is not supported by this example\n"); + err = -RT_ENOSYS; + goto _out; + } + + /* The output is RGB888 with the JPEGD half-scale mode enabled. */ + tables = rt_dma_alloc_coherent(jpegd, JPEGD_TABLE_SIZE, &tables_dma); + display_width = (jpg.width + 1) / 2; + display_height = (jpg.height + 1) / 2; + stride = JPEGD_ALIGN(JPEGD_ALIGN(jpg.width, 16) / 2, 16); + out_height = JPEGD_ALIGN(jpg.height, jpg.fill_bottom ? 16 : 8) / 2; + output_size = (rt_size_t)stride * out_height * 3; + output = rt_dma_alloc_coherent(jpegd, output_size, &output_dma); + if (!tables || !output) + { + err = -RT_ENOMEM; + goto _out; + } + + rt_memset(tables, 0, JPEGD_TABLE_SIZE); + rt_memset(output, 0, output_size); + make_quant_table(tables, &jpg); + make_huffman_table(tables, &jpg); + table_sel = jpg.components == 1 ? 1 : (jpg.qtables > 1 ? 3 : 2); + htable_sel = jpg.components == 1 ? 1 : (jpg.htable_mask > 0x0f ? 3 : 2); + htable_mincode_len = htable_sel == 2 ? (jpg.components - 1) * 6 - 1 : + jpg.components * 6 - 1; + hw_scan_offset = jpg.scan_offset & ~(rt_size_t)15; + hw_stream_size = JPEGD_ALIGN(jpg.size - hw_scan_offset, 16); + req.reg[1] = JPEGD_INT_TIMEOUT | JPEGD_INT_BUF_EMPTY; + req.reg[2] = JPEGD_SYS_SCALE(JPEGD_SCALE_HALF) | + JPEGD_SYS_OUTPUT(JPEGD_OUTPUT_RGB888) | + (jpg.fill_right ? JPEGD_SYS_FILL_RIGHT : 0) | + (jpg.fill_bottom ? JPEGD_SYS_FILL_DOWN : 0) | + JPEGD_SYS_FULL_RANGE; + req.reg[3] = (jpg.width - 1) | ((rt_uint32_t)(jpg.height - 1) << 16); + req.reg[4] = jpg.mode | (table_sel << 8) | (htable_sel << 12); + if (jpg.restart) + { + req.reg[4] |= RT_BIT(15) | ((rt_uint32_t)(jpg.restart - 1) << 16); + } + req.reg[5] = (stride * 3 / 16); + req.reg[6] = (stride * 3 / 16 * out_height) << 4; + req.reg[7] = (table_sel * 8 - 1) | (htable_mincode_len << 8) | + ((htable_sel * 12 - 1) << 16); + req.reg[8] = (jpg.scan_offset & 15) | + ((rt_uint32_t)((hw_stream_size - 1) / 16) << 4); + req.reg[JPEGD_TABLE_QUANT] = (rt_uint32_t)tables_dma; + req.reg[JPEGD_TABLE_MINCODE] = (rt_uint32_t)(tables_dma + JPEGD_MINCODE_OFFSET); + req.reg[JPEGD_TABLE_VALUE] = (rt_uint32_t)(tables_dma + JPEGD_VALUE_OFFSET); + req.reg[JPEGD_STREAM_BASE] = (rt_uint32_t)(stream_dma + hw_scan_offset); + req.reg[JPEGD_OUTPUT_BASE] = (rt_uint32_t)output_dma; + req.reg[14] = 1 | (2 << 5) | (2 << 7); + req.reg[16] = 0xff; + req.reg[30] = 3 | (1 << 3) | (0xa << 4); + if ((rt_ubase_t)(rt_uint32_t)stream_dma != stream_dma || + (rt_ubase_t)(rt_uint32_t)tables_dma != tables_dma || + (rt_ubase_t)(rt_uint32_t)output_dma != output_dma) + { + rt_kprintf("jpegd DMA address exceeds 32 bits\n"); + err = -RT_EINVAL; + goto _out; + } + if ((err = rt_device_control(jpegd, JPEGD_RUN, &req))) + { + rt_kprintf("decode failed: %d, irq=0x%08x\n", err, req.irq_status); + goto _out; + } + + err = show_rgb(output, display_width, display_height, stride * 3, fb_name); + if (!err) + { + rt_kprintf("displayed %s (%ux%u -> %ux%u) on %s\n", path, + jpg.width, jpg.height, display_width, display_height, fb_name); + } + +_out: + if (output) + { + rt_dma_free_coherent(jpegd, output_size, output, output_dma); + } + if (tables) + { + rt_dma_free_coherent(jpegd, JPEGD_TABLE_SIZE, tables, tables_dma); + } + if (stream) + { + rt_dma_free_coherent(jpegd, stream_size, stream, stream_dma); + } + if (fd >= 0) + { + close(fd); + } + + return err; +} +MSH_CMD_EXPORT(jpegd_show, decode and display once: jpegd_show [/arm-boot.jpg] [fb0]); +#endif /* RT_USING_FINSH && RT_USING_GRAPHIC && RT_ROCKCHIP_JPEG_DEC */ diff --git a/bsp/rockchip/rk3500/applications/main.c b/bsp/rockchip/rk3500/applications/main.c index 02155bf206a3..220cb8076cb2 100644 --- a/bsp/rockchip/rk3500/applications/main.c +++ b/bsp/rockchip/rk3500/applications/main.c @@ -5,12 +5,12 @@ * * Change Logs: * Date Author Notes - * 2017-5-30 Bernard the first version + * 2017-05-30 Bernard the first version */ #include -int main(int argc, char** argv) +int main(int argc, char **argv) { rt_kprintf("Hi, this is RT-Thread!!\n"); diff --git a/bsp/rockchip/rk3500/applications/rga2.c b/bsp/rockchip/rk3500/applications/rga2.c new file mode 100644 index 000000000000..4394b7a647a0 --- /dev/null +++ b/bsp/rockchip/rk3500/applications/rga2.c @@ -0,0 +1,502 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-11-21 GuEe-GUI first version + */ + +#include +#include + +#if defined(RT_USING_FINSH) && defined(RT_USING_GRAPHIC) && defined(RT_ROCKCHIP_RGA2) +#include +#include +#include + +#define RGA2_TEST_WIDTH 320 +#define RGA2_TEST_HEIGHT 180 +#define RGA2_TEST_MARGIN 12 +#define RGA2_ANIM_DEFAULT_FRAMES 600U +#define RGA2_ANIM_MAX_FRAMES 3600U + +static void rga2_make_pattern(rt_uint32_t *pixels, int width, int height) +{ + int x, y; + + for (y = 0; y < height; ++y) + { + for (x = 0; x < width; ++x) + { + rt_uint32_t color; + + if (x < width / 4 && y < height / 4) + { + color = 0xffff0000; + } + else if (x >= width * 3 / 4 && y < height / 4) + { + color = 0xff00ff00; + } + else if (x < width / 4 && y >= height * 3 / 4) + { + color = 0xff0000ff; + } + else if (x >= width * 3 / 4 && y >= height * 3 / 4) + { + color = 0xffffffff; + } + else + { + rt_uint32_t red = x * 255 / width; + rt_uint32_t green = y * 255 / height; + rt_uint32_t blue = (x + y) * 127 / (width + height); + + color = 0xff000000 | (red << 16) | (green << 8) | blue; + } + + /* An off-centre cross makes every rotation and mirror obvious. */ + if ((x >= width / 3 && x < width / 3 + 5) || + (y >= height / 3 && y < height / 3 + 5)) + { + color = 0xffffff00; + } + pixels[y * width + x] = color; + } + } +} + +static void rga2_set_image(struct rga2_image *image, + const struct rga2_buffer *buffer, rt_uint16_t width, + rt_uint16_t height, rt_uint16_t stride) +{ + image->address = buffer->phys_addr; + image->width = width; + image->height = height; + image->stride = stride; + image->format = RGA2_FORMAT_BGRA8888; +} + +static rt_err_t rga2_fill(rt_device_t rga, struct rga2_req *req, + rt_uint16_t x, rt_uint16_t y, rt_uint16_t width, + rt_uint16_t height, rt_uint32_t color) +{ + req->render_mode = RGA2_MODE_COLOR_FILL; + req->rotate = RGA2_ROTATE_0; + req->mirror = 0; + req->color = color; + req->dst.rect.x = x; + req->dst.rect.y = y; + req->dst.rect.width = width; + req->dst.rect.height = height; + + return rt_device_control(rga, RGA2_SUBMIT, req); +} + +static rt_err_t rga2_blit(rt_device_t rga, struct rga2_req *req, + rt_uint16_t x, rt_uint16_t y, rt_uint16_t width, + rt_uint16_t height, rt_uint8_t rotate, rt_uint8_t mirror) +{ + req->render_mode = RGA2_MODE_BITBLT; + req->rotate = rotate; + req->mirror = mirror; + req->src.rect.x = 0; + req->src.rect.y = 0; + req->src.rect.width = RGA2_TEST_WIDTH; + req->src.rect.height = RGA2_TEST_HEIGHT; + req->dst.rect.x = x; + req->dst.rect.y = y; + req->dst.rect.width = width; + req->dst.rect.height = height; + + return rt_device_control(rga, RGA2_SUBMIT, req); +} + +static rt_uint32_t rga2_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 rga2_color(rt_uint8_t red, rt_uint8_t green, + rt_uint8_t blue) +{ + return 0xff000000U | (rt_uint32_t)red << 16 | + (rt_uint32_t)green << 8 | blue; +} + +static rt_err_t rga2_parse_frames(const char *text, rt_uint32_t *frames) +{ + char *end; + unsigned long value = strtoul(text, &end, 0); + + if (!text[0] || *end || !value || value > RGA2_ANIM_MAX_FRAMES) + { + return -RT_EINVAL; + } + + *frames = value; + return RT_EOK; +} + +static int rga2_test(int argc, char **argv) +{ + const char *rga_name = argc > 1 ? argv[1] : "rga0"; + const char *fb_name = argc > 2 ? argv[2] : "fb0"; + rt_device_t rga = rt_device_find(rga_name); + rt_device_t fb = rt_device_find(fb_name); + struct rt_device_graphic_info info; + struct rt_device_rect_info rect; + struct rga2_buffer source = { 0 }; + struct rga2_buffer destination = { 0 }; + struct rga2_req req = { 0 }; + static const rt_uint8_t rotations[] = + { + RGA2_ROTATE_0, RGA2_ROTATE_90, RGA2_ROTATE_180, + RGA2_ROTATE_270, RGA2_ROTATE_0, RGA2_ROTATE_0, + }; + static const rt_uint8_t mirrors[] = + { + 0, 0, 0, 0, RGA2_MIRROR_X, RGA2_MIRROR_Y, + }; + static const char *names[] = + { + "scale", "rotate 90", "rotate 180", "rotate 270", + "mirror X", "mirror Y", + }; + rt_uint32_t version; + rt_uint16_t panel_width, panel_height; + int i; + rt_err_t err = -RT_ERROR; + + if (!rga || !fb) + { + rt_kprintf("device not found: %s or %s\n", rga_name, fb_name); + return -RT_EINVAL; + } + 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.bits_per_pixel != 32 || !info.framebuffer) + { + rt_kprintf("rga2_test requires a 32-bit framebuffer\n"); + err = -RT_ENOSYS; + goto _out; + } + if (info.width <= RGA2_TEST_MARGIN * 4 || + info.height <= RGA2_TEST_MARGIN * 3 || info.pitch > UINT16_MAX) + { + rt_kprintf("framebuffer geometry is not supported\n"); + err = -RT_EINVAL; + goto _out; + } + + source.size = RGA2_TEST_WIDTH * RGA2_TEST_HEIGHT * 4; + destination.size = info.pitch * info.height; + if ((err = rt_device_control(rga, RGA2_ALLOC_BUFFER, &source)) != RT_EOK || + (err = rt_device_control(rga, RGA2_ALLOC_BUFFER, &destination)) != RT_EOK) + { + rt_kprintf("RGA2 buffer allocation failed: %d\n", err); + goto _out; + } + rga2_make_pattern(source.virt_addr, RGA2_TEST_WIDTH, RGA2_TEST_HEIGHT); + + rga2_set_image(&req.src, &source, RGA2_TEST_WIDTH, + RGA2_TEST_HEIGHT, RGA2_TEST_WIDTH * 4); + rga2_set_image(&req.dst, &destination, info.width, + info.height, info.pitch); + + /* Clear the complete output through the color-fill render mode. */ + if ((err = rga2_fill(rga, &req, 0, 0, info.width, info.height, + 0xff202020)) != RT_EOK) + { + rt_kprintf("RGA2 color fill failed: %d, irq=0x%08x\n", + err, req.irq_status); + goto _out; + } + + panel_width = (info.width - RGA2_TEST_MARGIN * 4) / 3; + panel_height = (info.height - RGA2_TEST_MARGIN * 3) / 2; + if (!panel_width || !panel_height) + { + err = -RT_EINVAL; + goto _out; + } + + for (i = 0; i < 6; ++i) + { + rt_uint16_t x = RGA2_TEST_MARGIN + + (i % 3) * (panel_width + RGA2_TEST_MARGIN); + rt_uint16_t y = RGA2_TEST_MARGIN + + (i / 3) * (panel_height + RGA2_TEST_MARGIN); + + err = rga2_blit(rga, &req, x, y, panel_width, panel_height, + rotations[i], mirrors[i]); + if (err != RT_EOK) + { + rt_kprintf("RGA2 %s failed: %d, irq=0x%08x\n", + names[i], err, req.irq_status); + goto _out; + } + rt_kprintf("RGA2 %-10s: (%u,%u) %ux%u\n", + names[i], x, y, panel_width, panel_height); + } + + rt_memcpy(info.framebuffer, destination.virt_addr, destination.size); + rect.x = 0; + rect.y = 0; + rect.width = info.width; + rect.height = info.height; + rt_device_control(fb, RTGRAPHIC_CTRL_RECT_UPDATE, &rect); + rt_device_control(fb, RTGRAPHIC_CTRL_WAIT_VSYNC, RT_NULL); + rt_device_control(rga, RGA2_GET_VERSION, &version); + rt_kprintf("RGA2 %08x completed fill/scale/rotate/mirror tests on %s\n", + version, fb_name); + err = RT_EOK; + +_out: + if (destination.virt_addr) + { + rt_device_control(rga, RGA2_FREE_BUFFER, &destination); + } + if (source.virt_addr) + { + rt_device_control(rga, RGA2_FREE_BUFFER, &source); + } + rt_device_close(fb); + return err; +} +MSH_CMD_EXPORT(rga2_test, run RGA2 fill scale rotate and mirror tests); + +static int rga2_anim(int argc, char **argv) +{ + const char *rga_name = argc > 1 ? argv[1] : "rga0"; + const char *fb_name = argc > 2 ? argv[2] : "fb0"; + rt_uint32_t frames = RGA2_ANIM_DEFAULT_FRAMES; + rt_device_t rga = rt_device_find(rga_name); + rt_device_t fb = rt_device_find(fb_name); + struct rt_graphic_device *graphic; + struct rt_device_graphic_info info; + struct rga2_buffer source = { 0 }; + struct rga2_buffer destination = { 0 }; + struct rga2_req req = { 0 }; + static const rt_uint8_t rotations[] = + { + RGA2_ROTATE_0, RGA2_ROTATE_90, RGA2_ROTATE_180, + RGA2_ROTATE_270, RGA2_ROTATE_0, RGA2_ROTATE_0, + }; + static const rt_uint8_t mirrors[] = + { + 0, 0, 0, 0, RGA2_MIRROR_X, RGA2_MIRROR_Y, + }; + rt_uint8_t *front_buffer, *back_buffer, *swap_buffer; + rt_size_t screen_size; + unsigned long frame = 0; + rt_tick_t start_ms, elapsed_ms; + rt_bool_t restore_auto_update = RT_FALSE; + rt_err_t err = -RT_ERROR; + + if (argc > 4 || (argc > 3 && + rga2_parse_frames(argv[3], &frames) != RT_EOK)) + { + rt_kprintf("usage: rga2_anim [rga] [fb] [frames: 1-%u]\n", + RGA2_ANIM_MAX_FRAMES); + return -RT_EINVAL; + } + if (!rga || !fb) + { + rt_kprintf("device not found: %s or %s\n", rga_name, fb_name); + return -RT_ENOSYS; + } + 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.bits_per_pixel != 32 || !info.framebuffer || + info.width < 400 || info.height < 240 || info.pitch > UINT16_MAX) + { + rt_kprintf("rga2_anim requires a 32-bit framebuffer of at least 400x240\n"); + err = -RT_ENOSYS; + goto _out; + } + + screen_size = (rt_size_t)info.pitch * info.height; + if (screen_size > info.smem_len / 2U) + { + rt_kprintf("%s needs a double framebuffer for tear-free animation\n", + fb_name); + err = -RT_ENOMEM; + goto _out; + } + front_buffer = info.framebuffer; + back_buffer = front_buffer + screen_size; + 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); + } + + source.size = RGA2_TEST_WIDTH * RGA2_TEST_HEIGHT * 4; + destination.size = screen_size; + if ((err = rt_device_control(rga, RGA2_ALLOC_BUFFER, &source)) != RT_EOK || + (err = rt_device_control(rga, RGA2_ALLOC_BUFFER, &destination)) != RT_EOK) + { + rt_kprintf("RGA2 buffer allocation failed: %d\n", err); + goto _out; + } + + rga2_make_pattern(source.virt_addr, RGA2_TEST_WIDTH, RGA2_TEST_HEIGHT); + rga2_set_image(&req.src, &source, RGA2_TEST_WIDTH, + RGA2_TEST_HEIGHT, RGA2_TEST_WIDTH * 4); + rga2_set_image(&req.dst, &destination, info.width, + info.height, info.pitch); + + if ((err = rga2_fill(rga, &req, 0, 0, info.width, info.height, + 0xff182028)) != RT_EOK) + { + goto _failed; + } + rt_memcpy(front_buffer, destination.virt_addr, screen_size); + rt_memcpy(back_buffer, destination.virt_addr, screen_size); + 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("RGA2 animation: fill, scale, rotate, mirror, %u frames\n", + frames); + start_ms = rt_tick_get_millisecond(); + + for (frame = 0; frame < frames; ++frame) + { + rt_uint32_t min_width = rt_max(96U, info.width / 8U); + rt_uint32_t min_height = rt_max(72U, info.height / 8U); + rt_uint32_t max_width = info.width * 3U / 4U; + rt_uint32_t max_height = info.height * 3U / 4U; + rt_uint32_t width = min_width + rga2_triangle(frame, 151, + max_width - min_width); + rt_uint32_t height = min_height + rga2_triangle(frame + 37, 127, + max_height - min_height); + rt_uint32_t x = rga2_triangle(frame, 137, info.width - width); + rt_uint32_t y = rga2_triangle(frame + 29, 103, info.height - height); + rt_uint32_t transform = (frame / 40) % 6; + rt_uint32_t small_width = rt_max(64U, info.width / 5U); + rt_uint32_t small_height = rt_max(48U, info.height / 5U); + rt_uint32_t small_x = rga2_triangle(frame + 61, 113, + info.width - small_width); + rt_uint32_t small_y = rga2_triangle(frame + 17, 89, + info.height - small_height); + rt_uint32_t box_width = rt_max(40U, info.width / 10U); + rt_uint32_t box_height = rt_max(32U, info.height / 10U); + rt_uint32_t box_x = rga2_triangle(frame + 83, 97, + info.width - box_width); + rt_uint32_t box_y = rga2_triangle(frame + 43, 79, + info.height - box_height); + rt_uint32_t background = rga2_color( + 20 + rga2_triangle(frame, 181, 52), + 24 + rga2_triangle(frame + 53, 157, 48), + 32 + rga2_triangle(frame + 101, 193, 64)); + rt_uint32_t box_color = rga2_color( + 96 + rga2_triangle(frame + 73, 109, 159), + 64 + rga2_triangle(frame + 7, 131, 191), + 80 + rga2_triangle(frame + 41, 149, 175)); + + /* Each operation below is a separate RGA2 hardware job. */ + err = rga2_fill(rga, &req, 0, 0, info.width, info.height, + background); + if (err != RT_EOK) + { + goto _failed; + } + err = rga2_blit(rga, &req, x, y, width, height, + rotations[transform], mirrors[transform]); + if (err != RT_EOK) + { + goto _failed; + } + err = rga2_blit(rga, &req, small_x, small_y, + small_width, small_height, + rotations[(transform + 3) % 6], + mirrors[(transform + 3) % 6]); + if (err != RT_EOK) + { + goto _failed; + } + err = rga2_fill(rga, &req, box_x, box_y, box_width, box_height, + box_color); + if (err != RT_EOK) + { + goto _failed; + } + + 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) + { + goto _failed; + } + 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("RGA2 animation done on %s: %u frames in %u ms, %u.%u fps\n", + fb_name, frames, (unsigned int)elapsed_ms, + (unsigned int)((rt_uint64_t)frames * 1000 / elapsed_ms), + (unsigned int)(((rt_uint64_t)frames * 10000 / elapsed_ms) % 10)); + err = RT_EOK; + goto _out; + +_failed: + rt_kprintf("RGA2 animation failed at frame %lu: %d, irq=0x%08x\n", + frame, err, req.irq_status); + +_out: + if (restore_auto_update) + { + rt_graphic_device_update_auto(graphic, RT_GRAPHIC_UPDATE_MS); + } + if (destination.virt_addr) + { + rt_device_control(rga, RGA2_FREE_BUFFER, &destination); + } + if (source.virt_addr) + { + rt_device_control(rga, RGA2_FREE_BUFFER, &source); + } + rt_device_close(fb); + return err; +} +MSH_CMD_EXPORT(rga2_anim, animate an RGA2 scaled and rotating image); +#endif /* RT_USING_FINSH && RT_USING_GRAPHIC && RT_ROCKCHIP_RGA2 */ diff --git a/bsp/rockchip/rk3500/driver/board.c b/bsp/rockchip/rk3500/driver/board.c index e2e14a6994ba..96c85924cecb 100644 --- a/bsp/rockchip/rk3500/driver/board.c +++ b/bsp/rockchip/rk3500/driver/board.c @@ -10,23 +10,8 @@ #include #include -#include -#include - -static void rk3568_machine_shutdown(void) -{ - psci_system_off(); -} void rt_hw_board_init(void) { rt_hw_common_setup(); - rt_dm_machine_shutdown = rk3568_machine_shutdown; - rt_dm_machine_reset = psci_system_reboot; -} - -void reboot(void) -{ - psci_system_reboot(); } -MSH_CMD_EXPORT(reboot, reboot...); diff --git a/bsp/rockchip/rk3500/rtconfig.h b/bsp/rockchip/rk3500/rtconfig.h index bebf4706dff3..263205f25703 100644 --- a/bsp/rockchip/rk3500/rtconfig.h +++ b/bsp/rockchip/rk3500/rtconfig.h @@ -87,6 +87,7 @@ /* end of kservice options */ #define RT_USING_DEBUG +#define RT_DEBUGING_ASSERT #define RT_DEBUGING_COLOR /* Inter-Thread communication */ @@ -101,6 +102,7 @@ /* Memory Management */ +#define RT_USING_MEMPOOL #define RT_USING_SLAB #define RT_USING_MEMHEAP #define RT_MEMHEAP_FAST_MODE @@ -226,14 +228,21 @@ #define RT_CANSND_MSG_TIMEOUT 100 #define RT_CAN_NB_TX_FIFO_SIZE 256 #define RT_CAN_CANFD_ROCKCHIP +#define RT_USING_ADC +#define RT_USING_ADC_V1 +#define RT_ADC_ROCKCHIP_SARADC #define RT_USING_CLOCK_TIME #define RT_CLOCK_TIME_ARM_ARCH #define RT_CLOCK_TIMER_ROCKCHIP +#define RT_USING_ETHERNET +#define RT_ETHERNET_DWMAC +#define RT_ETHERNET_DWMAC_PTP +#define RT_ETHERNET_DWMAC_ROCKCHIP #define RT_USING_I2C #define RT_USING_I2C_BITOPS #define RT_I2C_RK3X -#define RT_USING_ADC -#define RT_ADC_ROCKCHIP_SARADC +#define RT_USING_PHY_V2 +#define RT_PHY_V2_REALTEK #define RT_USING_NULL #define RT_USING_ZERO #define RT_USING_RANDOM @@ -246,7 +255,6 @@ #define RT_ALARM_STACK_SIZE 16384 #define RT_ALARM_TIMESLICE 5 #define RT_ALARM_PRIORITY 10 -#define RT_USING_SOFT_RTC #define RT_RTC_HYM8563 #define RT_RTC_PCF8523 #define RT_RTC_PCF8563 @@ -254,12 +262,15 @@ #define RT_RTC_RK8XX #define RT_USING_SDIO #define RT_SDIO_STACK_SIZE 16384 -#define RT_SDIO_THREAD_PRIORITY 15 +#define RT_SDIO_THREAD_PRIORITY 10 #define RT_MMCSD_STACK_SIZE 16384 -#define RT_MMCSD_THREAD_PRIORITY 22 +#define RT_MMCSD_THREAD_PRIORITY 10 #define RT_MMCSD_MAX_PARTITION 16 +#define RT_USING_SDHCI #define RT_SDIO_DW_MMC +#define RT_SDIO_SDHCI_DWCMSHC #define RT_SDIO_DW_MMC_ROCKCHIP +#define RT_SDIO_SDHCI_DWCMSHC_ROCKCHIP #define RT_USING_SPI #define RT_USING_SPI_ISR #define RT_USING_QSPI @@ -271,18 +282,62 @@ #define RT_USING_WDT #define RT_WDT_DW #define RT_WDT_RK8XX +#define RT_USING_AUDIO +#define RT_AUDIO_REPLAY_MP_BLOCK_SIZE 4096 +#define RT_AUDIO_REPLAY_MP_BLOCK_COUNT 2 +#define RT_AUDIO_RECORD_PIPE_SIZE 2048 +#define RT_AUDIO_ROCKCHIP +#define RT_AUDIO_ROCKCHIP_I2S_TDM +#define RT_AUDIO_ROCKCHIP_CODEC +#define RT_AUDIO_ROCKCHIP_CODEC_RK817 +#define RT_AUDIO_ROCKCHIP_CARD +#define RT_USING_TOUCH +#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_VOP2 +#define RT_GRAPHIC_FB_VOPL +#define RT_GRAPHIC_FB_VOP1 +#define RT_GRAPHIC_DISPLAY_ROCKCHIP +#define RT_GRAPHIC_CONNECTOR_DSI +#define RT_GRAPHIC_CONNECTOR_HDMI +#define RT_GRAPHIC_BACKLIGHT_HINT +#define RT_GRAPHIC_PANEL_SIMPLE +#define RT_GRAPHIC_INPUT_TOUCH_HINT +#define RT_GRAPHIC_LOGO +#define RT_GRAPHIC_LOGO_RADXA_CLUT224 +#define RT_GRAPHIC_LOGO_RADXA_CLUT224_PATH "../dm/graphic/logo/logo-radxa-clut224.ppm" #define RT_USING_HWCRYPTO -#define RT_HWCRYPTO_DEFAULT_NAME "hwcryto" +#define RT_HWCRYPTO_DEFAULT_NAME "hwcrypto" #define RT_HWCRYPTO_IV_MAX_SIZE 16 #define RT_HWCRYPTO_KEYBIT_MAX_SIZE 256 +#define RT_HWCRYPTO_USING_GCM +#define RT_HWCRYPTO_USING_AES +#define RT_HWCRYPTO_USING_AES_ECB +#define RT_HWCRYPTO_USING_DES +#define RT_HWCRYPTO_USING_DES_ECB +#define RT_HWCRYPTO_USING_3DES +#define RT_HWCRYPTO_USING_3DES_ECB +#define RT_HWCRYPTO_USING_MD5 +#define RT_HWCRYPTO_USING_SHA1 +#define RT_HWCRYPTO_USING_SHA2 +#define RT_HWCRYPTO_USING_SHA2_256 #define RT_HWCRYPTO_USING_RNG +#define RT_HWCRYPTO_USING_BIGNUM +#define RT_HWCRYPTO_USING_BIGNUM_EXPTMOD #define RT_HWCRYPTO_RNG_ROCKCHIP +#define RT_HWCRYPTO_CRYPTO_ROCKCHIP_V2 +#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_RK8XX +#define RT_INPUT_TOUCHSCREEN +#define RT_INPUT_TOUCHSCREEN_GOODIX #define RT_USING_MBOX #define RT_MBOX_PIC #define RT_MBOX_ROCKCHIP @@ -291,6 +346,10 @@ #define RT_USING_PHYE #define RT_PHYE_ROCKCHIP_NANENG_COMBO #define RT_PHYE_ROCKCHIP_SNPS_PCIE3 +#define RT_PHYE_ROCKCHIP_INNO_DSIDPHY +#define RT_USING_ATA +#define RT_ATA_AHCI +#define RT_ATA_AHCI_DW #define RT_USING_NVME #define RT_USING_NVME_IO_QUEUE 4 #define RT_NVME_PCI @@ -301,6 +360,11 @@ #define RT_BLK_PARTITION_DFS #define RT_BLK_PARTITION_EFI /* end of Partition Types */ +#define RT_USING_SCSI +#define RT_SCSI_SD +#define RT_SCSI_CDROM +#define RT_USING_UFS +#define RT_UFS_ROCKCHIP #define RT_USING_FIRMWARE #define RT_FIRMWARE_ARM_SCMI #define RT_FIRMWARE_ARM_SCMI_TRANSPORT_MAILBOX @@ -395,6 +459,8 @@ #define RT_SOC_ROCKCHIP_FIQ_DEBUGGER #define RT_SOC_ROCKCHIP_GRF #define RT_SOC_ROCKCHIP_HW_DECOMPRESS +#define RT_ROCKCHIP_JPEG_DEC +#define RT_ROCKCHIP_RGA2 #define RT_SOC_ROCKCHIP_IODOMAIN /* end of SoC (System on Chip) Drivers */ /* end of Device Drivers */ @@ -579,6 +645,10 @@ /* end of IPC Test */ +/* Pin Test */ + +/* end of Pin Test */ + /* Serial Test */ /* end of Serial Test */ @@ -587,6 +657,10 @@ #define RT_UTEST_SMP_CALL_FUNC /* end of SMP-Call Test */ + +/* SPI Test */ + +/* end of SPI Test */ /* end of Drivers */ /* File System */