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 */